camera-dof
camera-dof
Camera depth-of-field primitives — the whole DOF surface, one knob per scene.
Read the rig's notes
Every length here is a MILLIMETRE (packages/core/units.ts). That is the whole
reason the numbers look the way they do: the panel sits 791mm from the lens,
not 9.3 of anything.
DOF is not a <postprocessing> step you add: writing ANY of `focus`,
`dof_range` or `dof_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, and
this reel runs the default pass — camera_dof (gpu/post/camera-dof.ts).
THE THREE AUTHORED VALUES — the only ones that animate
focus the sharp distance, in mm. Three spellings, all live:
focus=791 a distance
focus="0 0 17" 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. A FRAMED kf
needs none of them: framing is focus, resolved per frame.
dof_range mm — how far from the focal plane blur reaches full strength,
i.e. the depth of the sharp band. Typical 25-50% of `focus`;
the runtime warns under 5%, which blurs the whole frame.
dof_blur mm ON THE FRAME — the blur ceiling, measured on the 1.92 x
1.08 m full-frame wall, so `dof_blur=28.1` is a 28mm disc on a
1080mm-tall frame at any resolution and wherever focus sits.
It is a CEILING: it must not grow when the camera racks close.
All three interpolate per <kf> on the camera's <frame> keyframes — that is
what a rack focus IS here. `aperture`/`max_blur` are the pass's raw internal
pair and are still accepted for old reels; the mm knobs win when both are
present (lib/postprocessing/dof-units.ts).
THE PASS · camera_dof. Smoothstep CoC over `dof_range`, gathered at HALF
resolution with a Vogel disc (spiral rotated per pixel) whose tap count is
sized to the disc's AREA each frame — about one tap per 4 texels, <= 128 —
then composited full-res against the sharp buffer, keyed on each pixel's own
CoC so thin in-focus text stays sharp over a soft background. Scatter-as-
gather weighting, so a sharp subject cannot smear a halo into the soft field
around it. The depth it keys on is its own pre-pass: ui3d cards write depth
where their body is, not across the padding that holds their shadow. No
highlight model: an out-of-focus specular spreads and dims rather than
staying blown. `falloff` on an explicit <step name=camera_dof> shoulders the
ramp. (dof_pass=three — three.js's DepthOfFieldNode — suits highlights on a
dark field, camera-dof-lattice; on this bright ground it blurs the
focal-plane text and erodes the devices.)
THE STAGE · one lens (fov 34 at "0 12.75 808") and one light rig in every
scene, and four depth planes that never move:
laptop z=-467 -> screen at 1530 ipad z=-170 -> 978
panel z= 17 -> 791 iphone z= 306 -> 502
The laptop is the one to watch: the rig origin is 1275mm out, but an open lid
leans its SCREEN about 255mm further back, so the plane you focus on is 1530
— measured, not assumed. The five scattered accents do sit on their nominal
planes (1275 / 978 / 791 / 502 / 417), which is why the far spheres go soft
while the laptop screen is sharp.
Scenes dress those planes two ways — a device desk (laptop · tablet ·
floating panel · phone) and a wall of floating UI behind a browser — 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.
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 (scenes 5 and 6 prove it). Written on a <kf> instead they come
back as the resolver's 0.001 floor in this build and the frame goes flat —
so a rack across keyframes uses distances, as scene 7 does.
Preview: http://localhost:4444/runtime?project=promos/primitives/camera/camera-dof/camera-dof.promo- Topic
- camera
- Scenes
- 8
- Kind
- reference rig
//
Camera depth-of-field primitives — the whole DOF surface, one knob per scene.
Every length here is a MILLIMETRE (packages/core/units.ts). That is the whole
reason the numbers look the way they do: the panel sits 791mm from the lens,
not 9.3 of anything.
DOF is not a <postprocessing> step you add: writing ANY of `focus`,
`dof_range` or `dof_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, and
this reel runs the default pass — camera_dof (gpu/post/camera-dof.ts).
THE THREE AUTHORED VALUES — the only ones that animate
focus the sharp distance, in mm. Three spellings, all live:
focus=791 a distance
focus="0 0 17" 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. A FRAMED kf
needs none of them: framing is focus, resolved per frame.
dof_range mm — how far from the focal plane blur reaches full strength,
i.e. the depth of the sharp band. Typical 25-50% of `focus`;
the runtime warns under 5%, which blurs the whole frame.
dof_blur mm ON THE FRAME — the blur ceiling, measured on the 1.92 x
1.08 m full-frame wall, so `dof_blur=28.1` is a 28mm disc on a
1080mm-tall frame at any resolution and wherever focus sits.
It is a CEILING: it must not grow when the camera racks close.
All three interpolate per <kf> on the camera's <frame> keyframes — that is
what a rack focus IS here. `aperture`/`max_blur` are the pass's raw internal
pair and are still accepted for old reels; the mm knobs win when both are
present (lib/postprocessing/dof-units.ts).
THE PASS · camera_dof. Smoothstep CoC over `dof_range`, gathered at HALF
resolution with a Vogel disc (spiral rotated per pixel) whose tap count is
sized to the disc's AREA each frame — about one tap per 4 texels, <= 128 —
then composited full-res against the sharp buffer, keyed on each pixel's own
CoC so thin in-focus text stays sharp over a soft background. Scatter-as-
gather weighting, so a sharp subject cannot smear a halo into the soft field
around it. The depth it keys on is its own pre-pass: ui3d cards write depth
where their body is, not across the padding that holds their shadow. No
highlight model: an out-of-focus specular spreads and dims rather than
staying blown. `falloff` on an explicit <step name=camera_dof> shoulders the
ramp. (dof_pass=three — three.js's DepthOfFieldNode — suits highlights on a
dark field, camera-dof-lattice; on this bright ground it blurs the
focal-plane text and erodes the devices.)
THE STAGE · one lens (fov 34 at "0 12.75 808") and one light rig in every
scene, and four depth planes that never move:
laptop z=-467 -> screen at 1530 ipad z=-170 -> 978
panel z= 17 -> 791 iphone z= 306 -> 502
The laptop is the one to watch: the rig origin is 1275mm out, but an open lid
leans its SCREEN about 255mm further back, so the plane you focus on is 1530
— measured, not assumed. The five scattered accents do sit on their nominal
planes (1275 / 978 / 791 / 502 / 417), which is why the far spheres go soft
while the laptop screen is sharp.
Scenes dress those planes two ways — a device desk (laptop · tablet ·
floating panel · phone) and a wall of floating UI behind a browser — plus
five scattered primitives, one per plane, so the falloff also reads on plain
geometry. Su