Skip to content

Production-Quality Tuning

The high-level calls (shot.camera, shot.lighting, actor.move_to, …) get you a working shot. The dialsR, theta, phi, f, key/rim power, motion_scale, gap, volume, samples — get you a look. This page is the workflow and a set of ready recipes; the exhaustive per-dial reference lives with each concern:

Area Key dials Reference
Camera subject mode R theta phi R1/R2 arc f anchor lookat Cameras → Parameter reference
Lighting key_power rim_power back_power power strength rotation Lighting → Parameter reference
Actors action to duration motion_scale dialog hold gap Actors → Parameter reference
Voice & delivery voice · instructions · default_voice · by_gender Voice Catalogue · Actors → voices
Blocking gap gap_x gap_y who_faces Blocking → Parameter reference
Editing & sound trim speed volume pan at look letterbox crossfade Editing → Parameter reference
Timeline & render clip gap · engine · cycles_samples · downsample_factor · fps/step Render Pipeline

The tuning order

Work in this order — each step assumes the previous is settled:

  1. Frame itsubject, then R (distance) and mode (aim height). Get the subject the right size, in the right part of the frame.
  2. Angle ittheta (¾ / profile / behind) and phi (low = power, high = vulnerability). This is most of the "cinematic" feeling.
  3. Stage it — for groups, the blocking gap(s) and the anchor theta; for movement, the gait and motion_scale.
  4. Light it — pick a preset and set the key : rim ratio for mood (dramatic vs soft).
  5. Expose it — scale the powers (or HDR strength) for overall brightness; rotation to place the sun.
  6. Finish it — switch to the quality engine, raise samples/resolution, then grade & score in the edit.

Recipes

Each is a starting point — then nudge per the order above.

Intimate dialogue (flattering ¾)

shot.block(face_to_face(gap=1.2), hero, other, at=A1)
shot.camera("static", mode="medium", R=1.8, theta=25, phi=-5, subject=hero)
shot.lighting("rembrandt", key_power=350, rim_power=140)   # soft-ish, modelled

Hero / power (low angle)

shot.camera("static", R=2.0, theta=12, phi=-16)
shot.lighting("rembrandt", key_power=420, rim_power=90)    # wide key:rim ratio = drama

Vulnerable / diminished (high angle)

shot.camera("static", mode="wide", R=3.0, theta=0, phi=32)
shot.lighting("three_point", key_power=380, rim_power=160, back_power=120)

Establishing exterior — golden hour

from dsl.lighting import apply_hdr_lighting
apply_hdr_lighting(hdr="golden_hour_4k", strength=1.0, rotation_z_deg=80)  # sun low & angled
shot.camera("global_static", anchor=BRIDGE.Camera_Point_1, f=28)          # wide, fixed vantage

Walk-and-talk

sam.move_to(target, action="walking", motion_scale=1.1, dialog="Keep up — we're late.")
shot.camera("tracking_moving", mode="medium", R=4.0, theta=20)
shot.clip(5.0)

Vertigo / unease

shot.camera("dolly_zoom", R1=5.0, R2=2.0, theta=0, subject=hero)   # don't set f — it's derived

Reveal head-to-toe

shot.camera("tilt", R=3.0, phi_start=-25, phi_end=12)

Soft beauty

shot.camera("static", mode="closeup", R=1.2, phi=6)
shot.lighting("butterfly", key_power=360)

Noir / chiaroscuro

shot.camera("static", mode="closeup", R=1.3, theta=30, phi=-4)
shot.lighting("split", key_power=260)         # dark surround; render eevee/cycles
# then in the edit:  c.look("noir");  edit.letterbox("2.35")

A finished cut

with edit.clip(shot.render) as c:
    c.look("cold"); c.fade_in(0.4)
edit.between("a", "b").crossfade(0.4)
edit.music("bgm/atmospheric_pad", volume=0.7)   # audible under dialogue (amix halves it)
edit.letterbox("2.35")

Cast the voice (performance)

from dsl.voices import echo, by_gender
marcus = james("Marcus", voice=echo)                                 # gender-matched, define once
brian("The Stranger", voice="onyx", instructions="Cold. Clipped.")   # inline override + delivery
Match the voice's gender to the character (or by_gender("male")); tone goes in instructions. Full list: Voice Catalogue.

Final-quality render

Leave the fast proxy and lean on Cycles for the version you ship:

use_fast_cycles(samples=48, downsample_factor=1)   # full-res, path-traced

Higher cycles_samples (≈ 24–64) cleans noise; downsample_factor=1 is full resolution; keep output_fps ≈ animation_fps / frame_step so the proxy plays at real speed. Full detail: Render Pipeline.