Skip to content
Docs
Open Promoeyes
camera-dof-bokeh2

camera-dof-bokeh2

Camera depth-of-field primitives — the whole DOF surface, one knob per scene.

Read the rig's notes
THIS IS THE ALL-BOKEH2 TWIN of camera-dof.pug: every camera in every scene
carries dof_pass="bokeh2" on a 42mm lens, so the whole reel is one lens and
the only variables left are the ones each scene names. The mixed reel next
door keeps the default camera_dof pass for scenes 1-7; read them side by
side to see what the pass itself is worth.


DOF is not a <postprocessing> step you add: writing ANY of `focus`,
`aperture` or `max_blur` on a <camera> (or on any camera <kf>) auto-injects
the pass and drives it from camera.userData.dof every frame
(engine/yaml-runtime, "Shallow DOF"). There is nothing else to turn on.

THE THREE AUTHORED VALUES — the only ones that animate
  focus       the sharp distance. Three spellings, all live:
                focus=9.3            a distance in world units
                focus="0 0 0.2"      a world POINT — whatever sits there
                focus="chaser"       a NODE id — tracks that node's position
              Point/node forms re-resolve every frame against the live
              camera pose (lib/focus-target.ts), so a moving camera or a
              moving subject needs no hand-computed distances.
  aperture    how FAST blur grows away from the focal plane. The default
              pass ramps over `range = max_blur ÷ aperture` world units and
              then flattens, so a bigger aperture = a shorter ramp.
  max_blur    the blur CEILING, as a fraction of frame width (0.03 ≈ 32px
              on a 1080p frame). It is also the numerator of `range`, so
              raising the ceiling softens the ramp unless aperture rises
              with it.
All three interpolate per <kf> on the camera's <frame> keyframes — that is
what a rack focus IS here.

TWO PASSES — dof_pass=
  (default)   camera_dof (lib/postprocessing/camera-dof-pass.ts). Smoothstep
              CoC, 80-tap Vogel disc with a per-pixel golden-angle phase,
              scatter-as-gather weighting so a sharp subject cannot smear a
              halo into the soft field around it. No highlight model: an
              out-of-focus specular just spreads and dims.
  "bokeh2"    the three.js webgl_postprocessing_dof2 port (BokehShader2).
              A real thin lens: fstop = 0.0072 ÷ aperture, focalLength in
              mm, CoC 0.03mm, plus per-channel fringe and a highlight gain
              that keeps blown-out points bright as they spread — which is
              what makes bokeh balls read as bokeh balls.

BOKEH2-ONLY KNOBS — dof_* camera attrs, read once when the pass is built
(so they are scene-level, not keyframable):
  dof_rings dof_samples             tap budget of the ring gather (3 / 4)
  dof_fstop dof_focal_length        override the thin lens directly
  dof_pentagon                      pentagon iris instead of a round one
  dof_threshold dof_gain dof_bias   the highlight model
  dof_fringe                        chromatic fringing on the gather
  dof_vignetting dof_noise dof_dithering   rim falloff + grain
  dof_showFocus                     debug tint: orange sharp, blue on ramp
  dof_exclude_sharp=false           restore stock (halo-prone) gathering
  dof_manualdof dof_depthblur dof_shaderFocus   the remaining stock flags

THE STAGE · one lens (fov 34 at 0 0.15 9.5) and one light rig in every
scene, and four depth planes that never move:

    laptop  z=-5.5  → screen at 18.0       ipad   z=-2.0  → 11.5
    panel   z= 0.2  →  9.3                 iphone z= 3.6  →  5.9

The laptop is the one to watch: the rig origin is 15.0 out, but an open lid
leans its SCREEN about three units further back, so the plane you focus on
is 18.0 — measured with dof_showFocus, not assumed. The five scattered
accents do sit on their nominal planes (15.0 / 11.5 / 9.3 / 5.9 / 4.9),
which is why the far spheres go soft while the laptop screen is sharp.

Scenes dress those planes three ways — a device desk (laptop · tablet ·
floating panel · phone), a wall of floating UI behind a browser, and the
desk again with a field of blown-out points for bokeh — plus five scattered
primitives, one per plane, so the falloff also reads on plain geometry.
Subjects, haze lobes and accents carry `match` ids the whole way, so
match-move gaps morph the set; the A/B pairs (passes, tap budgets) cut hard
on `transition=none` so nothing but the named attribute differs.

Every piece of type sits on the plane it is talking about, which is why a
readout goes soft the moment its beat ends.

A NOTE ON focus TARGETS · the point and node-id forms resolve per frame on
the CAMERA (scene 5 and scene 6 prove it). Written on a <kf> instead they
come back as the resolver's 0.001 floor in this build, which collapses the
thin lens (focalDepth < focalLength) and the frame goes flat — so a rack
across keyframes uses distances, as scene 14 does.

Preview: /packages/runtime/index.html?project=promos/primitives/camera-dof/camera-dof-bokeh2.promo
Topic
camera
Scenes
15
Kind
reference rig
//
    Camera depth-of-field primitives — the whole DOF surface, one knob per scene.

    THIS IS THE ALL-BOKEH2 TWIN of camera-dof.pug: every camera in every scene
    carries dof_pass="bokeh2" on a 42mm lens, so the whole reel is one lens and
    the only variables left are the ones each scene names. The mixed reel next
    door keeps the default camera_dof pass for scenes 1-7; read them side by
    side to see what the pass itself is worth.


    DOF is not a <postprocessing> step you add: writing ANY of `focus`,
    `aperture` or `max_blur` on a <camera> (or on any camera <kf>) auto-injects
    the pass and drives it from camera.userData.dof every frame
    (engine/yaml-runtime, "Shallow DOF"). There is nothing else to turn on.

    THE THREE AUTHORED VALUES — the only ones that animate
      focus       the sharp distance. Three spellings, all live:
                    focus=9.3            a distance in world units
                    focus="0 0 0.2"      a world POINT — whatever sits there
                    focus="chaser"       a NODE id — tracks that node's position
                  Point/node forms re-resolve every frame against the live
                  camera pose (lib/focus-target.ts), so a moving camera or a
                  moving subject needs no hand-computed distances.
      aperture    how FAST blur grows away from the focal plane. The default
                  pass ramps over `range = max_blur ÷ aperture` world units and
                  then flattens, so a bigger aperture = a shorter ramp.
      max_blur    the blur CEILING, as a fraction of frame width (0.03 ≈ 32px
                  on a 1080p frame). It is also the numerator of `range`, so
                  raising the ceiling softens the ramp unless aperture rises
                  with it.
    All three interpolate per <kf> on the camera's <frame> keyframes — that is
    what a rack focus IS here.

    TWO PASSES — dof_pass=
      (default)   camera_dof (lib/postprocessing/camera-dof-pass.ts). Smoothstep
                  CoC, 80-tap Vogel disc with a per-pixel golden-angle phase,
                  scatter-as-gather weighting so a sharp subject cannot smear a
                  halo into the soft field around it. No highlight model: an
                  out-of-focus specular just spreads and dims.
      "bokeh2"    the three.js webgl_postprocessing_dof2 port (BokehShader2).
                  A real thin lens: fstop = 0.0072 ÷ aperture, focalLength in
                  mm, CoC 0.03mm, plus per-channel fringe and a highlight gain
                  that keeps blown-out points bright as they spread — which is
                  what makes bokeh balls read as bokeh balls.

    BOKEH2-ONLY KNOBS — dof_* camera attrs, read once when the pass is built
    (so they are scene-level, not keyframable):
      dof_rings dof_samples             tap budget of the ring gather (3 / 4)
      dof_fstop dof_focal_length        override the thin lens directly
      dof_pentagon                      pentagon iris instead of a round one
      dof_threshold dof_gain dof_bias   the highlight model
      dof_fringe                        chromatic fringing on the gather
      dof_vignetting dof_noise dof_dithering   rim falloff + grain
      dof_showFocus                     debug tint: orange sharp, blue on ramp
      dof_exclude_sharp=false           restore stock (halo-prone) gathering
      dof_manualdof dof_depthblur dof_shaderFocus   the remaining stock flags

    THE STAGE · one lens (fov 34 at 0 0.15 9.5) and one light rig in every
    scene, and four depth planes that never move:

        laptop  z=-5.5  → screen at 18.0       ipad   z=-2.0  → 11.5
        panel   z= 0.2  →  9.3                 iphone z= 3.6  →  5.9

    The laptop is the one to watch: the rig origin is 15.0 out, but an open lid
    leans its SCREEN about three units further back, so the plane you focus on
    is 18.0 — measured with dof_showFocus, not assumed. The five scattered
    accents do sit on