pp-lab.next
pp-lab.next
Post-processing lab — FIRST-CLASS STEPS. pp-lab.promo's three shots, rebuilt with the engine-ordered post steps (docs/plans/postprocess.plan.md), plus a fourth shot that only the new grammar can author.
Read the rig's notes
The steps, and the order the ENGINE runs them in whatever order they are
written (packages/engine/engine/post/steps.ts):
bloom 30 strength radius threshold selective …
output 40 tone_mapping=aces|agx|neutral|reinhard|cineon|linear|none exposure
aa 50 method=ssaa samples=4 — always, written LAST in the chain
film 60 grain scanlines line_count vignette vignette_start
Every numeric param is a channel (pug short rows or properties > kf, any
easing); `enabled` is a channel too.
ANTIALIASING · `step(name=aa method=ssaa samples=4)`, the last step.
Never FXAA (`aa method=fxaa` / `step(name=fxaa)`): house rule.
samples = full scene renders per frame, a power of two (1 2 4 8 16 32).
Never 3: the engine rounds log2, so 3 silently costs 4 renders.
8 only for a shot whose thin near-diagonal lines stair-step at 4 —
say why in a comment.
DEPTH OF FIELD · on the CAMERA, never as a post step:
camera(dof_pass=three dof_range=<mm> dof_blur=<px at 1080p> [focus=…])
dof_range = mm from the focus plane to full blur; dof_blur = disc size.
focus = mm | "x y z" | node id. With a frame track and no focus on its
kfs, the lens follows the framing (look_at / node=) — shots 1 and 4.
kf(… focus= dof_range= dof_blur=) keys the lens per pose; a kf focus
is a number (mm) only — shot 3.
A static camera with no frame track needs focus=, else it sits at 10 mm.
Camera DOF runs at the end of the chain (slot 70, after film).
Keep hot emissives (the halo rings) OUTSIDE the focus band: they bloom
sharp, then the lens spreads them into soft bokeh.
dof_pass=three reads about 1.5× narrower than the default pass at the
same dof_blur on these dark sets — shots 1 and 4 are tuned by eye.
A bright UI page that goes out of focus stays on the default pass (no
dof_pass): three's max filter breaks its dark text into scribbles — shot 3.
Do not author `step(name=dof …)`: it takes over the lens (camera focus /
dof_range / dof_blur are then ignored) and it reads method=/pass=, so a
dof_pass= written on it does nothing.
Shots 1–3 translate pp-lab.promo one to one:
film_grain(output_transform=1) + fxaa → output(aces) + film + aa(ssaa)
film_grain(output_transform=2) → output(none)
camera focus/dof_range/dof_blur → the same; dof_pass=three in shot 1
4 · LIVE everything keyed: the lens opens (dof_blur 6 → 33 on the
camera kfs) as focus follows the push from phone to laptop,
bloom swells, AgX exposure lifts, and the film layer switches
off at 3.5 s.
THE SET and THE SCREENS as pp-lab.promo.
Preview: http://localhost:4444/runtime?project=promos/primitives/postprocessing/pp-lab.next.promo&renderer=webgpu- Topic
- postprocessing
- Scenes
- 4
- Kind
- reference rig
//
Post-processing lab — FIRST-CLASS STEPS. pp-lab.promo's three shots,
rebuilt with the engine-ordered post steps (docs/plans/postprocess.plan.md), plus a
fourth shot that only the new grammar can author.
The steps, and the order the ENGINE runs them in whatever order they are
written (packages/engine/engine/post/steps.ts):
bloom 30 strength radius threshold selective …
output 40 tone_mapping=aces|agx|neutral|reinhard|cineon|linear|none exposure
aa 50 method=ssaa samples=4 — always, written LAST in the chain
film 60 grain scanlines line_count vignette vignette_start
Every numeric param is a channel (pug short rows or properties > kf, any
easing); `enabled` is a channel too.
ANTIALIASING · `step(name=aa method=ssaa samples=4)`, the last step.
Never FXAA (`aa method=fxaa` / `step(name=fxaa)`): house rule.
samples = full scene renders per frame, a power of two (1 2 4 8 16 32).
Never 3: the engine rounds log2, so 3 silently costs 4 renders.
8 only for a shot whose thin near-diagonal lines stair-step at 4 —
say why in a comment.
DEPTH OF FIELD · on the CAMERA, never as a post step:
camera(dof_pass=three dof_range=<mm> dof_blur=<px at 1080p> [focus=…])
dof_range = mm from the focus plane to full blur; dof_blur = disc size.
focus = mm | "x y z" | node id. With a frame track and no focus on its
kfs, the lens follows the framing (look_at / node=) — shots 1 and 4.
kf(… focus= dof_range= dof_blur=) keys the lens per pose; a kf focus
is a number (mm) only — shot 3.
A static camera with no frame track needs focus=, else it sits at 10 mm.
Camera DOF runs at the end of the chain (slot 70, after film).
Keep hot emissives (the halo rings) OUTSIDE the focus band: they bloom
sharp, then the lens spreads them into soft bokeh.
dof_pass=three reads about 1.5× narrower than the default pass at the
same dof_blur on these dark sets — shots 1 and 4 are tuned by eye.
A bright UI page that goes out of focus stays on the default pass (no
dof_pass): three's max filter breaks its dark text into scribbles — shot 3.
Do not author `step(name=dof …)`: it takes over the lens (camera focus /
dof_range / dof_blur are then ignored) and it reads method=/pass=, so a
dof_pass= written on it does nothing.
Shots 1–3 translate pp-lab.promo one to one:
film_grain(output_transform=1) + fxaa → output(aces) + film + aa(ssaa)
film_grain(output_transform=2) → output(none)
camera focus/dof_range/dof_blur → the same; dof_pass=three in shot 1
4 · LIVE everything keyed: the lens opens (dof_blur 6 → 33 on the
camera kfs) as focus follows the push from phone to laptop,
bloom swells, AgX exposure lifts, and the film layer switches
off at 3.5 s.
THE SET and THE SCREENS as pp-lab.promo.
Preview: http://localhost:4444/runtime?project=promos/primitives/postprocessing/pp-lab.next.promo&renderer=webgpu
promo#pp-lab-next(width=1920 height=1080 fps=30)
materials
// emissive well past the 0.85 threshold: selective bloom only sees emissive light
standard#glow(color=#1a1206 emissive=#ffb347 emissive-intensity=2.2 metalness=0 roughness=1)
standard#glow-cyan(color=#06121a emissive=#7ad7ff emissive-intensity=2 metalness=0 roughness=1)
standard#shell(color=#26262b metalness=0.4 roughness=0.3 envmap-intensity=1.1)
standard#deck(color=#08090c metalness=0.1 roughness=0.8)
// ===================================================================
// SCREENS — html2ui output (pp-lab.screens.html)
// ===================================================================
template#scr-ph-cam
card#ph-cam(x=0 y=0 w=71 h=154 r=0 fill=#07080c shadow=false)
card(x=0 y=0 w=71 h=154.02 r=0 fill=#07080c clip=true)
text(x=5.1 y=4.01 size=2.91 weight=700 color=#f4