Skip to content

Visual proofs — vocabulary-entry before/after gallery

Side-by-side renders of the synthetic ColorChecker chart and the synthetic grayscale ramp, before and after each vocabulary entry. For human visual validation: does each primitive visibly do what its description claims?

Renders use an empty-history baseline + --apply-custom-presets false so the chart passes through the darktable pipeline cleanly (input profile → output profile only, no scene-referred tone mapping). Each primitive is then applied in isolation — the only difference between baseline and per-entry renders is that primitive's effect. This lets you eyeball each primitive against the reference chart and verify it does what its description claims.

Production raw renders use the full _baseline_v1.xmp with sigmoid + colorbalancergb defaults — that path is correct for raws. The empty-baseline trick is specifically for chart-input isolation testing; it would not be appropriate for editing real photographs.

Masked columns: every non-mask-bound primitive renders additionally through a centered ellipse mask (radius=0.2, border=0.05) so you can see the spatial shaping in action. The mask covers the middle 16% of the frame; anything outside it should remain at baseline. This visually demonstrates that any primitive can be applied through a mask — see mask-applicable-controls.md for the per-module compatibility matrix.

Auto-generated. Regenerate via uv run python scripts/generate-visual-proofs.py after vocabulary changes. Commit the regenerated images alongside any vocabulary commit so the gallery and the manifest stay in sync.

Render size: 400x400, JPEG quality default. Inputs: synthetic targets from tests/fixtures/reference-targets/.

🎯 Trust basis — what the chart can and can't verify. The synthetic chart is a legitimate fixture for entries whose touched darktable modules operate on already-developed sRGB / working-profile pixels (exposure, sigmoid, bilat, vignette, grain, sharpen, single-axis colorbalancergb shifts, channelmixerrgb in destination=grey mode, highlights, toneequal). For these — listed in the Chart-verifiable sections below — the after-image shows exactly what the entry does. Trust it.

Entries that touch raw-domain modules (colorequal, denoiseprofile, lens, hazeremoval, ashift, crop, retouch, filmicrgb, diffuse) can't be honestly verified against a synthetic sRGB chart — those modules need the full raw → input-profile → working-profile pipeline. Such entries render against a CC BY-SA real-raw fixture in the Real-raw entries section below.

A separate Not yet honestly verifiable section lists entries touching temperature — the chemigram apply path doesn't yet compute camera-correct WB coefficients per raw at apply time, so those entries' dtstyle blobs carry foreign-camera coefficients that produce a visible cast on any non-matching body. Tracked in #131 Step 2 / RFC-039 (raw-derived parameters in L2 composition). The module-level discriminator lives at src/chemigram/core/visual_verification.py.

📷 Real-raw fixtures (#130). Entries that touch raw-domain modules render against one of two CC BY-SA 4.0 fixtures from discuss.pixls.us: landscape.ARW (Sony DSC-RX10M4 — sky, foliage, water, horizon) or portrait.ARW (Sony ZV-E10 — indoor single subject). Routing per entry by name heuristic — skin/face/eye/portrait/subject/hair → portrait; everything else → landscape. See tests/fixtures/raws/README.md for provenance, license, and attribution.


Baseline reference

These are the reference targets rendered through the baseline XMP with no primitive applied — the before state every row below compares against.

ColorChecker Grayscale ramp
baseline ColorChecker baseline grayscale

starter pack — 3 entries (0 chart-verifiable, 3 real-raw, 0 not-yet-portable)

Real-raw entries

These entries touch raw-domain darktable modules (colorequal, denoiseprofile, lens, hazeremoval, ashift, crop, retouch, filmicrgb, diffuse) — or compose looks that include one. The synthetic chart can't represent the input these modules expect; rendering against it produces structurally-misleading output. Each entry is routed to either the landscape or portrait CC BY-SA 4.0 fixture from tests/fixtures/raws/ so the after-image is honest. Apply-path correctness is independently verified by the unit + integration + e2e test coverage.

wb_kelvin_delta 📷 landscape raw

WB Kelvin / tint UX wrapper (#102). Same temperature module as the temperature entry, but exposes photographic units instead of raw RGB coefficients. 2 axes: --param kelvin_delta=V (range [-3000, 3000]; positive = warmer) and --param tint_delta=V (range [-200, 200]; positive = magenta-shifted). Linear approximation: red_coeff = 1 + kelvin_delta * 0.0001, blue_coeff inverse, green_coeff = 1 + tint_delta * 0.0001. Daily-use accurate; not chromatic-adaptation-perfect. RFC-039 / #131 made apply path camera-aware: at non-zero delta, shifts are relative to the target raw's camera-default WB read via rawpy.

🔬 CI assertions (parametric): - warmer (kelvin_delta=2000) → render_completes() against grayscale - cooler (kelvin_delta=-1500) → render_completes() against grayscale - tint_only (tint_delta=100) → render_completes() against grayscale

📷 Real-raw rendering (fixture: landscape.ARW, CC BY-SA 4.0). This entry touches a raw-domain darktable module that needs the full input-profile chain. Rendered against the landscape fixture so the after-image is honest. Apply-path correctness is independently verified by the unit + integration + e2e test coverage. See tests/fixtures/raws/README.md for provenance and attribution.

Landscape raw
wb_kelvin_delta landscape raw

wb_warm_subtle 📷 landscape raw

Warm white balance, subtle. Reauthored RFC-039 / #137 to compose wb_kelvin_delta with a fixed +500K shift; camera-portable.

🔬 CI: skipped — Reauthored under RFC-039 / #137 to compose wb_kelvin_delta with kelvin_delta=+500. The composed primitive's apply path is camera-aware (reads raw EXIF WB at apply time); the synthetic grayscale fixture isn't a raw — no EXIF — so the parametric apply returns identity-skip and the temperature op is dropped. Direction-of-effect is asserted on real raws by tests/integration/core/test_cross_camera_wb.py (#142, across 3 camera bodies) and at the byte level by tests/unit/core/parameterize/test_temperature.py (kelvin_delta scaling).

📷 Real-raw rendering (fixture: landscape.ARW, CC BY-SA 4.0). This entry touches a raw-domain darktable module that needs the full input-profile chain. Rendered against the landscape fixture so the after-image is honest. Apply-path correctness is independently verified by the unit + integration + e2e test coverage. See tests/fixtures/raws/README.md for provenance and attribution.

Landscape raw
wb_warm_subtle landscape raw

look_neutral 📷 landscape raw

Neutral L2 look — exposure + warm-subtle WB baseline. Reauthored RFC-039 / #137 to compose wb_kelvin_delta (no shift at default); camera-portable.

🔬 CI: L2 composite — auto-skipped by structural rule in test_lab_grade_primitives.py. Direction-of-effect is verified at the L3 primitive layer; this L2 look's composition is verified by visual review.

📷 Real-raw rendering (fixture: landscape.ARW, CC BY-SA 4.0). This entry touches a raw-domain darktable module that needs the full input-profile chain. Rendered against the landscape fixture so the after-image is honest. Apply-path correctness is independently verified by the unit + integration + e2e test coverage. See tests/fixtures/raws/README.md for provenance and attribution.

Landscape raw
look_neutral landscape raw

expressive-baseline pack — 111 entries (76 chart-verifiable, 35 real-raw, 0 not-yet-portable)

Chart-verifiable entries

These entries' touched darktable modules operate on already-developed sRGB / working-profile pixels. The chart is an honest fixture; the after-image shows exactly what the entry does in that pixel domain. Trust the result.

grain_strength

Parameterized grain strength (RFC-021). Pass --value V; range [0.0, 100.0]. 8 = grain_fine-equivalent, 25 = grain_medium-equivalent, 50 = grain_heavy-equivalent. Replaces the v1.5.x discrete grain_fine / grain_medium / grain_heavy entries with a single continuous-magnitude primitive.

🔬 CI assertions (parametric): - grain_strength_50 (grain_strength=50) → pixel_std_increase(1) against grayscale - grain_strength_8 (grain_strength=8) → pixel_std_increase(0.05) against grayscale

⚙️ Main row = parametric default (identity). This entry's default parameter value is the identity (no-op); the main row below shows the unchanged input by design. See the parameter sweep lower down for what the entry does at non-default values.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
grain_strength ColorChecker global grain_strength grayscale global grain_strength ColorChecker masked grain_strength grayscale masked

On the clipped-gradient fixture (continuous tone + blown highlights — chart designed to show this module's effect; see reference-targets/README.md):

Clipped gradient (global) Clipped gradient (centered ellipse mask)
grain_strength clipped-gradient global grain_strength clipped-gradient masked

vignette

Parameterized vignette (RFC-021). Pass --value V (CLI) or value: V (MCP); range [-1.0, +1.0] (negative darkens corners; positive lifts). Replaces the v1.5.x discrete vignette_subtle / vignette_medium / vignette_heavy entries with a single continuous-magnitude primitive.

🔬 CI assertions (parametric): - brightness_-0.5 (brightness=-0.5) → bright_dampen(-0.005) against grayscale - brightness_-0.8 (brightness=-0.8) → bright_dampen(-0.01) against grayscale

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
vignette ColorChecker global vignette grayscale global (n/a) (n/a)

highlights_clip_threshold

Parameterized highlight-recovery clip threshold (RFC-021). Pass --value V; range [0.0, 2.0]: lower = more aggressive recovery (0.95 = subtle, 0.85 = strong, 0.5 = aggressive). Default 1.0 (darktable default; recovers only above 1.0). Replaces the v1.5.x discrete highlights_recovery_subtle / highlights_recovery_strong entries.

🔬 CI assertions (parametric): - clip_0.85 (clip_threshold=0.85) → render_completes() against grayscale - clip_0.95 (clip_threshold=0.95) → render_completes() against grayscale

⚙️ Main row = parametric default (identity). This entry's default parameter value is the identity (no-op); the main row below shows the unchanged input by design. See the parameter sweep lower down for what the entry does at non-default values.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
highlights_clip_threshold ColorChecker global highlights_clip_threshold grayscale global highlights_clip_threshold ColorChecker masked highlights_clip_threshold grayscale masked

On the clipped-gradient fixture (continuous tone + blown highlights — chart designed to show this module's effect; see reference-targets/README.md):

Clipped gradient (global) Clipped gradient (centered ellipse mask)
highlights_clip_threshold clipped-gradient global highlights_clip_threshold clipped-gradient masked

sigmoid_contrast

Parameterized sigmoid tone-curve contrast (RFC-021). Pass --value V (CLI) or value: V (MCP); range [0.5, 5.0] (1.0 = mild s-curve, 1.5 = darktable default / no curve change, 2.5 = aggressive s-curve). Replaces the v1.5.x discrete contrast_low / contrast_high entries with a single continuous-magnitude primitive.

🔬 CI assertions (parametric): - contrast_2.5 (contrast=2.5) → contrast_increase(0.005, -0.005) against grayscale - contrast_1.0 (contrast=1) → contrast_decrease(-0.002, 0.002) against grayscale

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
sigmoid_contrast ColorChecker global sigmoid_contrast grayscale global sigmoid_contrast ColorChecker masked sigmoid_contrast grayscale masked

blacks_lifted

Lift target black to 0.5.

🔬 CI: skipped — Sigmoid 'target_black' is scene-referred; effect is below noise on display-referred chart input. Covered by test_path_a_sigmoid.py against real raws.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
blacks_lifted ColorChecker global blacks_lifted grayscale global blacks_lifted ColorChecker masked blacks_lifted grayscale masked

On the clipped-gradient fixture (continuous tone + blown highlights — chart designed to show this module's effect; see reference-targets/README.md):

Clipped gradient (global)
blacks_lifted clipped-gradient global

blacks_crushed

Crush blacks: target 0.001 + skew -0.3.

🔬 CI: skipped — Same as blacks_lifted.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
blacks_crushed ColorChecker global blacks_crushed grayscale global blacks_crushed ColorChecker masked blacks_crushed grayscale masked

On the clipped-gradient fixture (continuous tone + blown highlights — chart designed to show this module's effect; see reference-targets/README.md):

Clipped gradient (global)
blacks_crushed clipped-gradient global

whites_open

Open whites: target 300 (3x default).

🔬 CI assertion: bright_open(0.005) against the grayscale fixture.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
whites_open ColorChecker global whites_open grayscale global whites_open ColorChecker masked whites_open grayscale masked

bw_sky_drama

B&W with sky-drama mix (red-emphasis: R 0.5 / G 0.4 / B 0.1). Lightens reds and darkens blues — classic 'red filter' landscape look that emphasizes clouds against sky. normalize_grey=true.

🔬 CI assertion: chroma_zero(8) against the colorchecker fixture.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
bw_sky_drama ColorChecker global bw_sky_drama grayscale global bw_sky_drama ColorChecker masked bw_sky_drama grayscale masked

On the landscape raw fixture (real-raw content matching this entry's requires_content tags; the chart's module-level signal is honest, but the content-level payoff shows here):

Landscape raw
bw_sky_drama content Landscape raw

bw_foliage

B&W with foliage mix (green-emphasis: R 0.1 / G 0.7 / B 0.2). Lightens greens — separates foliage from neighboring tones; useful for forest / botanical work where green is the dominant subject. normalize_grey=true.

🔬 CI assertion: chroma_zero(8) against the colorchecker fixture.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
bw_foliage ColorChecker global bw_foliage grayscale global bw_foliage ColorChecker masked bw_foliage grayscale masked

On the landscape raw fixture (real-raw content matching this entry's requires_content tags; the chart's module-level signal is honest, but the content-level payoff shows here):

Landscape raw
bw_foliage content Landscape raw

toneequalizer

Parameterized 9-band tone equalizer (RFC-022 Tier 2; most complex multi-parameter ship). Pass --param NODE=V for any of: noise, ultra_deep_blacks, deep_blacks, blacks, shadows, midtones, highlights, whites, speculars. Each in [-2.0, +2.0] EV; default 0.0. Algorithm fields preserved at darktable defaults.

🔬 CI assertions (parametric): - compress_curve (shadows=1, highlights=-1, midtones=0) → render_completes() against grayscale - midtones_lift (midtones=0.5) → render_completes() against grayscale

⚙️ Main row = parametric default (identity). This entry's default parameter value is the identity (no-op); the main row below shows the unchanged input by design. See the parameter sweep lower down for what the entry does at non-default values.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
toneequalizer ColorChecker global toneequalizer grayscale global toneequalizer ColorChecker masked toneequalizer grayscale masked

sharpen

Parameterized sharpening (RFC-022 Tier 2). Pass --value V; range [0.0, 2.0] (0.0 = no sharpen, 0.5 = subtle, 1.0 = strong, 2.0 = aggressive). Radius preserved at darktable default 2.0 px, threshold at 0.5.

🔬 CI assertions (parametric): - amount_1.0 (amount=1) → render_completes() against grayscale - amount_0.5 (amount=0.5) → render_completes() against grayscale

⚙️ Main row = parametric default (identity). This entry's default parameter value is the identity (no-op); the main row below shows the unchanged input by design. See the parameter sweep lower down for what the entry does at non-default values.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
sharpen ColorChecker global sharpen grayscale global sharpen ColorChecker masked sharpen grayscale masked

bilat_clarity_strength

Parameterized clarity strength on bilat / local laplacian (RFC-021). Pass --value V; range [-1.0, 4.0]. 1.5 = clarity_strong-equivalent. clarity_painterly stays as a separate discrete entry — different kind, not strength.

🔬 CI assertions (parametric): - clarity_strength_2.5 (clarity_strength=2.5) → render_completes() against grayscale - clarity_strength_0.5 (clarity_strength=0.5) → render_completes() against grayscale

⚙️ Main row = parametric default (identity). This entry's default parameter value is the identity (no-op); the main row below shows the unchanged input by design. See the parameter sweep lower down for what the entry does at non-default values.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
bilat_clarity_strength ColorChecker global bilat_clarity_strength grayscale global bilat_clarity_strength ColorChecker masked bilat_clarity_strength grayscale masked

clarity_painterly

Soft painterly local contrast (detail 0.4).

🔬 CI: skipped — Local-contrast on edges/details, not flat patches (covered by test_path_b_localcontrast.py). The strength axis was parameterized in v1.6.0+ (bilat_clarity_strength); clarity_painterly stays discrete because it represents a different kind of clarity (different sigma_r/s/midtone shaping), not a different strength.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
clarity_painterly ColorChecker global clarity_painterly grayscale global clarity_painterly ColorChecker masked clarity_painterly grayscale masked

clarity_etched

L3 discrete kind — etched / over-defined clarity (#110). bilat_clarity_strength=2.0 (high local-contrast bite).

🔬 CI: skipped — Strength variant of bilat_clarity_strength (parameterized covers strength); kind-specific sigma/midtone shaping not flat-patch testable.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
clarity_etched ColorChecker global clarity_etched grayscale global clarity_etched ColorChecker masked clarity_etched grayscale masked

clarity_dreamy

L3 discrete kind — soft / dreamy clarity (#110). bilat_clarity_strength=-0.5 (negative bite — softens local contrast).

🔬 CI: skipped — Negative-strength variant of bilat_clarity_strength; same coverage rationale as clarity_painterly.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
clarity_dreamy ColorChecker global clarity_dreamy grayscale global clarity_dreamy ColorChecker masked clarity_dreamy grayscale masked

sharpen_edge_only

L3 discrete kind — edge-only sharpening (#110). amount=0.6 with default radius (2.0 px) and threshold (0.5). Threshold gates sharpening to detected edges only.

🔬 CI: skipped — Edge-only sharpening; effect on flat patches is below noise. Covered by parameterized sharpen entry.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
sharpen_edge_only ColorChecker global sharpen_edge_only grayscale global sharpen_edge_only ColorChecker masked sharpen_edge_only grayscale masked

sharpen_overall

L3 discrete kind — whole-image sharpening with bite (#110). amount=1.2 (strong).

🔬 CI: skipped — Whole-image sharpen; covered by parameterized sharpen entry's high-magnitude values.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
sharpen_overall ColorChecker global sharpen_overall grayscale global sharpen_overall ColorChecker masked sharpen_overall grayscale masked

vignette_subtle

L3 discrete kind — gentle peripheral darkening (#110). brightness=-0.15.

🔬 CI: skipped — Magnitude variant of vignette; covered by parameterized vignette entry's range.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
vignette_subtle ColorChecker global vignette_subtle grayscale global (n/a) (n/a)

vignette_strong

L3 discrete kind — pronounced peripheral darkening (#110). brightness=-0.5.

🔬 CI: skipped — Magnitude variant of vignette; covered by parameterized vignette entry's range.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
vignette_strong ColorChecker global vignette_strong grayscale global (n/a) (n/a)

exposure

Parameterized exposure compensation (RFC-021). Pass --value V (CLI) or value: V (MCP) in EV stops; range [-3.0, +3.0]. Replaces the v1.5.x discrete expo+0.3 / expo_+0.5 / expo_-0.3 / expo_-0.5 / shadows_global_± entries with a single continuous-magnitude primitive._

🔬 CI assertions (parametric): - ev_+0.5 (ev=0.5) → bright_open(0.05) against grayscale - ev_-0.5 (ev=-0.5) → bright_dampen(-0.05) against grayscale - ev_+1.0 (ev=1) → bright_open(0.15) against grayscale - ev_-1.0 (ev=-1) → bright_dampen(-0.15) against grayscale

⚙️ Main row = parametric default (identity). This entry's default parameter value is the identity (no-op); the main row below shows the unchanged input by design. See the parameter sweep lower down for what the entry does at non-default values.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
exposure ColorChecker global exposure grayscale global exposure ColorChecker masked exposure grayscale masked

saturation_global

Parameterized global saturation in colorbalancergb (RFC-021). Pass --value V (CLI) or value: V (MCP); range [-1.0, +1.0] (-1.0 = fully desaturated / monochrome; +0.5 = strong boost). Replaces the v1.5.x discrete sat_kill / sat_boost_moderate / sat_boost_strong entries with a single continuous-magnitude primitive.

🔬 CI assertions (parametric): - sat_-1.0 (saturation_global=-1) → chroma_zero(12) against colorchecker - sat_+0.5 (saturation_global=0.5) → chroma_increase(3) against colorchecker - sat_+0.25 (saturation_global=0.25) → chroma_increase(1) against colorchecker

⚙️ Main row = parametric default (identity). This entry's default parameter value is the identity (no-op); the main row below shows the unchanged input by design. See the parameter sweep lower down for what the entry does at non-default values.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
saturation_global ColorChecker global (n/a) saturation_global ColorChecker masked (n/a)

vibrance

Parameterized vibrance on colorbalancergb (RFC-022 Tier 2). Pass --value V; range [-1.0, +1.0]. 0.3 = vibrance+0.3-equivalent. Vibrance protects already-saturated pixels — gentler chroma push than saturation_global. Replaces v1.5.x vibrance_+0.3._

🔬 CI assertions (parametric): - vibrance_+0.3 (vibrance=0.3) → chroma_increase(0.5) against colorchecker

⚙️ Main row = parametric default (identity). This entry's default parameter value is the identity (no-op); the main row below shows the unchanged input by design. See the parameter sweep lower down for what the entry does at non-default values.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
vibrance ColorChecker global (n/a) vibrance ColorChecker masked (n/a)

chroma_global

Parameterized global chroma on colorbalancergb (RFC-022 Tier 2). Pass --value V; range [-1.0, +1.0]. Less saturated-pixel protection than vibrance, more aggressive than saturation_global at equal magnitudes.

🔬 CI assertions (parametric): - chroma_+0.3 (chroma_global=0.3) → chroma_increase(0.3) against colorchecker

⚙️ Main row = parametric default (identity). This entry's default parameter value is the identity (no-op); the main row below shows the unchanged input by design. See the parameter sweep lower down for what the entry does at non-default values.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
chroma_global ColorChecker global (n/a) chroma_global ColorChecker masked (n/a)

hue_angle

Parameterized global hue rotation on colorbalancergb (RFC-022 Tier 2). Pass --value V in degrees; range [-180.0, +180.0]. Rotates every pixel's hue around the color wheel without changing saturation or luminance.

🔬 CI assertions (parametric): - rot_+30 (hue_angle=30) → render_completes() against colorchecker

⚙️ Main row = parametric default (identity). This entry's default parameter value is the identity (no-op); the main row below shows the unchanged input by design. See the parameter sweep lower down for what the entry does at non-default values.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
hue_angle ColorChecker global hue_angle grayscale global hue_angle ColorChecker masked hue_angle grayscale masked

brilliance_global

Parameterized global brilliance on colorbalancergb (RFC-022 Tier 2 / #86). Pass --value V; range [-1.0, +1.0]. Brilliance shapes per-zone luminance — the global axis moves all zones together. Per-zone variants (highlights/midtones/shadows) target specific tonal ranges.

🔬 CI assertions (parametric): - brilliance_+0.5 (brilliance_global=0.5) → bright_open(0.02) against grayscale

⚙️ Main row = parametric default (identity). This entry's default parameter value is the identity (no-op); the main row below shows the unchanged input by design. See the parameter sweep lower down for what the entry does at non-default values.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
brilliance_global ColorChecker global brilliance_global grayscale global brilliance_global ColorChecker masked brilliance_global grayscale masked

brilliance_highlights

Parameterized highlight-zone brilliance on colorbalancergb (RFC-022 Tier 2 / #86). Pass --value V; range [-1.0, +1.0]. Targets only the highlight tonal zone — useful for selectively brightening or compressing high-key areas without affecting shadows / midtones.

🔬 CI assertions (parametric): - brilliance_+0.5 (brilliance_highlights=0.5) → zone_lift(0.01) against grayscale

⚙️ Main row = parametric default (identity). This entry's default parameter value is the identity (no-op); the main row below shows the unchanged input by design. See the parameter sweep lower down for what the entry does at non-default values.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
brilliance_highlights ColorChecker global brilliance_highlights grayscale global brilliance_highlights ColorChecker masked brilliance_highlights grayscale masked

brilliance_midtones

Parameterized midtone-zone brilliance on colorbalancergb (RFC-022 Tier 2 / #86). Pass --value V; range [-1.0, +1.0]. Targets only the midtone tonal zone — selectively shapes the body of the tonal distribution.

🔬 CI assertions (parametric): - brilliance_+0.5 (brilliance_midtones=0.5) → zone_lift(0.01) against grayscale

⚙️ Main row = parametric default (identity). This entry's default parameter value is the identity (no-op); the main row below shows the unchanged input by design. See the parameter sweep lower down for what the entry does at non-default values.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
brilliance_midtones ColorChecker global brilliance_midtones grayscale global brilliance_midtones ColorChecker masked brilliance_midtones grayscale masked

brilliance_shadows

Parameterized shadow-zone brilliance on colorbalancergb (RFC-022 Tier 2 / #86). Pass --value V; range [-1.0, +1.0]. Targets only the shadow tonal zone — selectively lifts or deepens dark areas without affecting highlights / midtones.

🔬 CI assertions (parametric): - brilliance_+0.5 (brilliance_shadows=0.5) → render_completes() against grayscale

⚙️ Main row = parametric default (identity). This entry's default parameter value is the identity (no-op); the main row below shows the unchanged input by design. See the parameter sweep lower down for what the entry does at non-default values.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
brilliance_shadows ColorChecker global brilliance_shadows grayscale global brilliance_shadows ColorChecker masked brilliance_shadows grayscale masked

hue_shadows

Parameterized per-zone hue rotation for shadows (#91 Bucket A.5; Lightroom Color Grading shadows wheel). Pass --value V; range [0.0, 360.0] degrees. Default 0.0.

🔬 CI assertions (parametric): - 210deg (hue_shadows=210) → render_completes() against grayscale

⚙️ Main row = parametric default (identity). This entry's default parameter value is the identity (no-op); the main row below shows the unchanged input by design. See the parameter sweep lower down for what the entry does at non-default values.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
hue_shadows ColorChecker global hue_shadows grayscale global hue_shadows ColorChecker masked hue_shadows grayscale masked

hue_midtones

Parameterized per-zone hue rotation for midtones (#91 Bucket A.5; Lightroom Color Grading midtones wheel). Pass --value V; range [0.0, 360.0] degrees. Default 0.0.

🔬 CI assertions (parametric): - 30deg (hue_midtones=30) → render_completes() against grayscale

⚙️ Main row = parametric default (identity). This entry's default parameter value is the identity (no-op); the main row below shows the unchanged input by design. See the parameter sweep lower down for what the entry does at non-default values.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
hue_midtones ColorChecker global hue_midtones grayscale global hue_midtones ColorChecker masked hue_midtones grayscale masked

hue_highlights

Parameterized per-zone hue rotation for highlights (#91 Bucket A.5; Lightroom Color Grading highlights wheel). Pass --value V; range [0.0, 360.0] degrees. Default 0.0.

🔬 CI assertions (parametric): - 45deg (hue_highlights=45) → render_completes() against grayscale

⚙️ Main row = parametric default (identity). This entry's default parameter value is the identity (no-op); the main row below shows the unchanged input by design. See the parameter sweep lower down for what the entry does at non-default values.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
hue_highlights ColorChecker global hue_highlights grayscale global hue_highlights ColorChecker masked hue_highlights grayscale masked

saturation_shadows

Parameterized per-zone saturation for shadows (#91 Bucket A.5; pairs with hue_shadows for full Lightroom shadow-zone color-grading control). Pass --value V; range [-1.0, +1.0].

🔬 CI assertions (parametric): - boost (saturation_shadows=0.4) → chroma_increase(0.3) against colorchecker

⚙️ Main row = parametric default (identity). This entry's default parameter value is the identity (no-op); the main row below shows the unchanged input by design. See the parameter sweep lower down for what the entry does at non-default values.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
saturation_shadows ColorChecker global (n/a) saturation_shadows ColorChecker masked (n/a)

saturation_midtones

Parameterized per-zone saturation for midtones (#91 Bucket A.5). Pass --value V; range [-1.0, +1.0].

🔬 CI assertions (parametric): - boost (saturation_midtones=0.3) → chroma_increase(0.3) against colorchecker

⚙️ Main row = parametric default (identity). This entry's default parameter value is the identity (no-op); the main row below shows the unchanged input by design. See the parameter sweep lower down for what the entry does at non-default values.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
saturation_midtones ColorChecker global (n/a) saturation_midtones ColorChecker masked (n/a)

saturation_highlights

Parameterized per-zone saturation for highlights (#91 Bucket A.5). Pass --value V; range [-1.0, +1.0].

🔬 CI assertions (parametric): - boost (saturation_highlights=0.3) → chroma_increase(0.3) against colorchecker

⚙️ Main row = parametric default (identity). This entry's default parameter value is the identity (no-op); the main row below shows the unchanged input by design. See the parameter sweep lower down for what the entry does at non-default values.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
saturation_highlights ColorChecker global (n/a) saturation_highlights ColorChecker masked (n/a)

shadows_weight

Parameterized shadow-zone falloff weight (#91 Bucket A.5; Lightroom Color Grading 'Blending' bottom). Pass --value V; range [0.0, 4.0]; default 1.0. Higher = more aggressive zone overlap.

🔬 CI assertions (parametric): - high (shadows_weight=2) → render_completes() against grayscale

⚙️ Main row = parametric default (identity). This entry's default parameter value is the identity (no-op); the main row below shows the unchanged input by design. See the parameter sweep lower down for what the entry does at non-default values.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
shadows_weight ColorChecker global shadows_weight grayscale global shadows_weight ColorChecker masked shadows_weight grayscale masked

highlights_weight

Parameterized highlights-zone falloff weight (#91 Bucket A.5; Lightroom Color Grading 'Blending' top). Pass --value V; range [0.0, 4.0]; default 1.0.

🔬 CI assertions (parametric): - high (highlights_weight=2) → render_completes() against grayscale

⚙️ Main row = parametric default (identity). This entry's default parameter value is the identity (no-op); the main row below shows the unchanged input by design. See the parameter sweep lower down for what the entry does at non-default values.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
highlights_weight ColorChecker global highlights_weight grayscale global highlights_weight ColorChecker masked highlights_weight grayscale masked

white_fulcrum

Parameterized shadow/highlight balance point (#91 Bucket A.5; Lightroom Color Grading 'Balance' slider). Pass --value V; range [-2.0, 2.0]; default 0.0 (neutral midpoint). Negative shifts the split toward shadows; positive toward highlights.

🔬 CI assertions (parametric): - shifted (white_fulcrum=0.5) → render_completes() against grayscale

⚙️ Main row = parametric default (identity). This entry's default parameter value is the identity (no-op); the main row below shows the unchanged input by design. See the parameter sweep lower down for what the entry does at non-default values.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
white_fulcrum ColorChecker global white_fulcrum grayscale global white_fulcrum ColorChecker masked white_fulcrum grayscale masked

grade_shadows_warm

Warm shadows (orange tint, hue 30 deg, chroma 0.3).

🔬 CI assertion: lab_b_shift(0.5) against the grayscale fixture.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
grade_shadows_warm ColorChecker global grade_shadows_warm grayscale global grade_shadows_warm ColorChecker masked grade_shadows_warm grayscale masked

grade_shadows_cool

Cool shadows (blue tint, hue 210 deg, chroma 0.3).

🔬 CI assertion: lab_b_shift(0.5) against the grayscale fixture.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
grade_shadows_cool ColorChecker global grade_shadows_cool grayscale global grade_shadows_cool ColorChecker masked grade_shadows_cool grayscale masked

grade_highlights_warm

Warm highlights (orange tint, hue 45 deg, chroma 0.2).

🔬 CI assertion: lab_b_shift(0.3) against the grayscale fixture.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
grade_highlights_warm ColorChecker global grade_highlights_warm grayscale global grade_highlights_warm ColorChecker masked grade_highlights_warm grayscale masked

grade_highlights_cool

Cool highlights (blue tint, hue 200 deg, chroma 0.2).

🔬 CI assertion: lab_b_shift(0.3) against the grayscale fixture.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
grade_highlights_cool ColorChecker global grade_highlights_cool grayscale global grade_highlights_cool ColorChecker masked grade_highlights_cool grayscale masked

grade_midtones_warm

Warm midtones (orange tint, hue 35 deg, chroma 0.25).

🔬 CI assertion: lab_b_shift(0.4) against the grayscale fixture.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
grade_midtones_warm ColorChecker global grade_midtones_warm grayscale global grade_midtones_warm ColorChecker masked grade_midtones_warm grayscale masked

grade_midtones_cool

Cool midtones (blue tint, hue 215 deg, chroma 0.25).

🔬 CI assertion: lab_b_shift(0.4) against the grayscale fixture.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
grade_midtones_cool ColorChecker global grade_midtones_cool grayscale global grade_midtones_cool ColorChecker masked grade_midtones_cool grayscale masked

grade_split_warm_cool

L3 discrete kind — classic split-toning composite (#110). Combines grade_shadows_cool (blue tint, hue 210 deg / chroma 0.3) with grade_highlights_warm (orange tint, hue 45 deg / chroma 0.2) in one entry. The signature 'cinematic' split-tone in a single primitive.

🔬 CI: skipped — Compositional split-tone (shadows_cool + highlights_warm); sub-effects covered by per-zone grade entries.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
grade_split_warm_cool ColorChecker global grade_split_warm_cool grayscale global grade_split_warm_cool ColorChecker masked grade_split_warm_cool grayscale masked

chroma_boost_shadows

Boost shadow chroma +0.3.

🔬 CI assertion: chroma_increase(0.3) against the colorchecker fixture.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
chroma_boost_shadows ColorChecker global (n/a) chroma_boost_shadows ColorChecker masked (n/a)

chroma_boost_midtones

Boost mid-tone chroma +0.3.

🔬 CI assertion: chroma_increase(0.3) against the colorchecker fixture.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
chroma_boost_midtones ColorChecker global (n/a) chroma_boost_midtones ColorChecker masked (n/a)

chroma_boost_highlights

Boost highlight chroma +0.3.

🔬 CI assertion: chroma_increase(0.3) against the colorchecker fixture.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
chroma_boost_highlights ColorChecker global (n/a) chroma_boost_highlights ColorChecker masked (n/a)

gradient_top_dampen_highlights 🟦 mask-bound

Dampen top-half highlights via -0.5 EV through a top-bright gradient.

🔬 CI assertion: zone_dampen(-0.005) against the colorchecker fixture.

ColorChecker Grayscale ramp
gradient_top_dampen_highlights ColorChecker gradient_top_dampen_highlights grayscale

gradient_bottom_lift_shadows 🟦 mask-bound

Lift bottom-half shadows via +0.4 EV through a bottom-bright gradient.

🔬 CI assertion: zone_lift(0.005) against the colorchecker fixture.

ColorChecker Grayscale ramp
gradient_bottom_lift_shadows ColorChecker gradient_bottom_lift_shadows grayscale

radial_subject_lift 🟦 mask-bound

Lift +0.6 EV in a centered radial mask region (subject emphasis).

🔬 CI assertion: zone_lift(0.005) against the colorchecker fixture.

ColorChecker Grayscale ramp
radial_subject_lift ColorChecker radial_subject_lift grayscale

rectangle_subject_band_dim 🟦 mask-bound

Dim -0.3 EV in a horizontal mid-band rectangle (de-emphasize a horizon line).

🔬 CI: skipped — Mask y=[0.4, 0.6] + 0.05 border doesn't align cleanly with the ColorChecker chart's row layout — empirically the complement zone (outer rows) shows more dimming than the inner zone. The wire IS correct (verified by test_drawn_mask_shapes_effect.py and build-by-words rectangle e2e tests against real raws); the chart-isolation assertion is the wrong shape for this entry. Leave skipped until a chart-aligned fixture or a different mask geometry is set up.

ColorChecker Grayscale ramp
rectangle_subject_band_dim ColorChecker rectangle_subject_band_dim grayscale

look_portrait

L2 look — gentle skin-protective composition. exposure +0.2 EV, sigmoid_contrast 1.2 (soft s-curve), colorbalancergb saturation_global=-0.1 + vibrance=+0.2 (mild chroma push that protects saturated pixels). Targets portraiture; avoid stacking with aggressive contrast or clarity.

🔬 CI: L2 composite — auto-skipped by structural rule in test_lab_grade_primitives.py. Direction-of-effect is verified at the L3 primitive layer; this L2 look's composition is verified by visual review.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
look_portrait ColorChecker global look_portrait grayscale global look_portrait ColorChecker masked look_portrait grayscale masked

look_landscape

L2 look — vibrant dramatic landscape composition. sigmoid_contrast 2.0 (strong s-curve), colorbalancergb saturation_global=+0.3 + vibrance=+0.2, bilat_clarity_strength 1.0 (definite local-contrast pop). Aggressive — pull back via sigmoid to ~1.5 if it feels harsh.

🔬 CI: L2 composite — auto-skipped by structural rule in test_lab_grade_primitives.py. Direction-of-effect is verified at the L3 primitive layer; this L2 look's composition is verified by visual review.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
look_landscape ColorChecker global look_landscape grayscale global look_landscape ColorChecker masked look_landscape grayscale masked

look_cinematic_teal_orange

L2 look — Hollywood blockbuster teal-and-orange grade (#104). sigmoid_contrast 1.4 + colorbalancergb hue_shadows=210 deg / saturation_shadows=+0.3 (teal) + hue_highlights=30 deg / saturation_highlights=+0.2 (orange) + saturation_global=+0.1.

🔬 CI: L2 composite — auto-skipped by structural rule in test_lab_grade_primitives.py. Direction-of-effect is verified at the L3 primitive layer; this L2 look's composition is verified by visual review.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
look_cinematic_teal_orange ColorChecker global look_cinematic_teal_orange grayscale global look_cinematic_teal_orange ColorChecker masked look_cinematic_teal_orange grayscale masked

look_high_key_portrait

L2 look — high-key portrait (Adler-style fashion / commercial). exposure +0.3 EV + sigmoid_contrast 0.8 (soft s-curve) + colorbalancergb brilliance_highlights=+0.2 + saturation_global=-0.05 (retains skin saturation while reducing global). For magazine / beauty work where bright skin tones drive the look. Compose with skin_uniformity for a complete editorial pass.

🔬 CI: L2 composite — auto-skipped by structural rule in test_lab_grade_primitives.py. Direction-of-effect is verified at the L3 primitive layer; this L2 look's composition is verified by visual review.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
look_high_key_portrait ColorChecker global look_high_key_portrait grayscale global look_high_key_portrait ColorChecker masked look_high_key_portrait grayscale masked

look_low_key_portrait

L2 look — low-key portrait (Tucker / chiaroscuro voice). exposure -0.2 EV + sigmoid_contrast 1.8 (strong s-curve) + colorbalancergb brilliance_shadows=-0.3 + saturation_global=-0.10. For dramatic editorial / character portraits where deep shadows carry the mood. Compose with look_portrait_split_tone_moody for a more cinematic grade.

🔬 CI: L2 composite — auto-skipped by structural rule in test_lab_grade_primitives.py. Direction-of-effect is verified at the L3 primitive layer; this L2 look's composition is verified by visual review.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
look_low_key_portrait ColorChecker global look_low_key_portrait grayscale global look_low_key_portrait ColorChecker masked look_low_key_portrait grayscale masked

look_moody_dramatic

L2 look — moody / dramatic editorial (#104). sigmoid_contrast 2.0 (strong s-curve) + colorbalancergb saturation_global=-0.3 + vibrance=+0.1 + grain_strength=25.

🔬 CI: L2 composite — auto-skipped by structural rule in test_lab_grade_primitives.py. Direction-of-effect is verified at the L3 primitive layer; this L2 look's composition is verified by visual review.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
look_moody_dramatic ColorChecker global look_moody_dramatic grayscale global look_moody_dramatic ColorChecker masked look_moody_dramatic grayscale masked

look_subject_lift_dark_only 🟦 mask-bound

L2 look — lift only the dark pixels in a centered subject region. Drawn ellipse around the subject + luminance shadows filter. Composes RFC-029 drawn mask + RFC-024 range_filter. The user's mental model: 'in this drawn mask, only affect the dark pixels.'

🔬 CI: L2 composite — auto-skipped by structural rule in test_lab_grade_primitives.py. Direction-of-effect is verified at the L3 primitive layer; this L2 look's composition is verified by visual review.

ColorChecker Grayscale ramp
look_subject_lift_dark_only ColorChecker look_subject_lift_dark_only grayscale

look_sky_blue_deepen 🟦 mask-bound

L2 look — deepen sky blues in the upper half. Drawn gradient (top half) + color_h filter on cyan-blue range. Composes RFC-029 + RFC-024. Real-world workflow: dramatic sky without affecting foreground or non-blue elements above the horizon.

🔬 CI: L2 composite — auto-skipped by structural rule in test_lab_grade_primitives.py. Direction-of-effect is verified at the L3 primitive layer; this L2 look's composition is verified by visual review.

ColorChecker Grayscale ramp
look_sky_blue_deepen ColorChecker look_sky_blue_deepen grayscale

On the landscape raw fixture (real-raw content matching this entry's requires_content tags; the chart's module-level signal is honest, but the content-level payoff shows here):

Landscape raw
look_sky_blue_deepen content Landscape raw

look_horizon_warm_glow 🟦 mask-bound

L2 look — lift warm tones near the horizon. Horizontal gradient anchored at midline + color_h filter on warm tones (orange/red). Sunset / golden-hour enhancement without affecting cool tones.

🔬 CI: L2 composite — auto-skipped by structural rule in test_lab_grade_primitives.py. Direction-of-effect is verified at the L3 primitive layer; this L2 look's composition is verified by visual review.

ColorChecker Grayscale ramp
look_horizon_warm_glow ColorChecker look_horizon_warm_glow grayscale

look_subject_brighten_highlights 🟦 mask-bound

L2 look — brighten only the bright pixels in the subject region. Drawn ellipse + luminance highlights filter. Catchlights, skin highlights, sparkle without blowing out midtones.

🔬 CI: L2 composite — auto-skipped by structural rule in test_lab_grade_primitives.py. Direction-of-effect is verified at the L3 primitive layer; this L2 look's composition is verified by visual review.

ColorChecker Grayscale ramp
look_subject_brighten_highlights ColorChecker look_subject_brighten_highlights grayscale

look_dark_pixels_global_lift 🟦 mask-bound

L2 look — lift dark pixels globally (no spatial mask). Pure parametric range_filter — luminance shadows. Useful when the intent is purely tonal: 'open up all the dark areas in the image, regardless of where they are.' Demonstrates the parametric-only path of RFC-024 / ADR-085.

🔬 CI: L2 composite — auto-skipped by structural rule in test_lab_grade_primitives.py. Direction-of-effect is verified at the L3 primitive layer; this L2 look's composition is verified by visual review.

ColorChecker Grayscale ramp
look_dark_pixels_global_lift ColorChecker look_dark_pixels_global_lift grayscale

skin_smooth_painterly 🟦 mask-bound

Approximate frequency separation for skin smoothing (Portrait Gap #4, cheap variant). Reduces local contrast (texture-band frequency) within the skin region — the color band stays untouched. Pass --value V or --param clarity_strength=V; range [-1.0, 4.0], typical -0.3 to -0.7 for natural smoothing. -0.5 default. Pre-baked with mask_skin_region. Not Photoshop's true frequency separation (band decomposition); approximation via bilat softening on a hue-masked region. Compose orthogonally with skin_uniformity (color-band uniformity) for the full skin-uniformity-plus-smoothing move. For sharper precision, override mask_spec via render_preview + LLM-vision (see docs/guides/llm-vision-for-masks.md Pattern 7).

🔬 CI: skipped — Skin-specific bilat shaping; covered by parameterized bilat_clarity_strength entry.

ColorChecker Grayscale ramp
skin_smooth_painterly ColorChecker skin_smooth_painterly grayscale

look_portrait_editorial

Magazine / fashion editorial grade. Punchier sigmoid contrast (1.6), global saturation pull-back (-0.10) — counterintuitive but the move Adler/Woloszynowicz reach for; reduced overall sat lets the split-tone read. Cool-shadows + warm-highlights split (hue_shadows=210, hue_highlights=45). Compose with skin_uniformity if skin patches fight the grade.

🔬 CI: L2 composite — auto-skipped by structural rule in test_lab_grade_primitives.py. Direction-of-effect is verified at the L3 primitive layer; this L2 look's composition is verified by visual review.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
look_portrait_editorial ColorChecker global look_portrait_editorial grayscale global look_portrait_editorial ColorChecker masked look_portrait_editorial grayscale masked

look_portrait_background_dim 🟦 mask-bound

Dim and de-saturate the background to push the subject forward. Exposure -0.4 EV + saturation_global -0.15. Pre-baked with mask_subject + invert: true (RFC-034) — the photographer doesn't have to construct an inverse-subject mask manually. The parametric fallback for mask_subject is coarse (midtone luminance + center-bias); for clean subject vs. background separation override the mask_spec at apply time with a manually-drawn inverted ellipse, or escalate via render_preview + LLM-vision construction (llm-vision-for-masks.md Pattern 7) for a path-form subject mask.

🔬 CI: L2 composite — auto-skipped by structural rule in test_lab_grade_primitives.py. Direction-of-effect is verified at the L3 primitive layer; this L2 look's composition is verified by visual review.

ColorChecker Grayscale ramp
look_portrait_background_dim ColorChecker look_portrait_background_dim grayscale

look_portrait_split_tone_moody

Cinematic split-tone portrait — cool blue shadows (hue 210, sat 0.30) + warm orange highlights (hue 45, sat 0.20), sigmoid contrast 1.4. Stronger split than look_portrait_editorial; some photographers (Adler) consider this 'fashion-only' rather than a general portrait move. Borderline survey candidate — ships, but exercise judgment.

🔬 CI: L2 composite — auto-skipped by structural rule in test_lab_grade_primitives.py. Direction-of-effect is verified at the L3 primitive layer; this L2 look's composition is verified by visual review.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
look_portrait_split_tone_moody ColorChecker global look_portrait_split_tone_moody grayscale global look_portrait_split_tone_moody ColorChecker masked look_portrait_split_tone_moody grayscale masked

look_landscape_grand_vista

Heaton/PureRAW-style grand vista. Sigmoid contrast 1.4, mildly warm shadows (hue 30, sat 0.10), vibrance +0.10, bilat clarity_strength 0.5. The chemigram shape of LR's adaptive sky + foreground lift workflow rendered globally; for sky-specific work compose with look_landscape_sky_enhance instead.

🔬 CI: L2 composite — auto-skipped by structural rule in test_lab_grade_primitives.py. Direction-of-effect is verified at the L3 primitive layer; this L2 look's composition is verified by visual review.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
look_landscape_grand_vista ColorChecker global look_landscape_grand_vista grayscale global look_landscape_grand_vista ColorChecker masked look_landscape_grand_vista grayscale masked

On the landscape raw fixture (real-raw content matching this entry's requires_content tags; the chart's module-level signal is honest, but the content-level payoff shows here):

Landscape raw
look_landscape_grand_vista content Landscape raw

look_landscape_intimate_quiet

Marino-style intimate / small-scene restraint. Very gentle sigmoid contrast (1.05), saturation pulled back (-0.10), bilat softened (clarity_strength -0.3 — opposite of clarity boost). The defining stylistic choice for forest interiors, abstract details, and any scene where drama would betray the subject. Applies LESS than the baseline does, deliberately.

🔬 CI: L2 composite — auto-skipped by structural rule in test_lab_grade_primitives.py. Direction-of-effect is verified at the L3 primitive layer; this L2 look's composition is verified by visual review.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
look_landscape_intimate_quiet ColorChecker global look_landscape_intimate_quiet grayscale global look_landscape_intimate_quiet ColorChecker masked look_landscape_intimate_quiet grayscale masked

On the landscape raw fixture (real-raw content matching this entry's requires_content tags; the chart's module-level signal is honest, but the content-level payoff shows here):

Landscape raw
look_landscape_intimate_quiet content Landscape raw

look_landscape_dramatic_moody

Page/Adamus-style dramatic atmospheric. Sigmoid contrast 1.7 (strong), cool shadows (hue 210, sat 0.20) + warm highlights (hue 30, sat 0.15), bilat clarity_strength 0.6. The dramatic counterpart to intimate_quiet — for stormy skies, rugged terrain, and weather drama. Pair with mask_luminosity_brightest_quartile darkening for stormy-cloud emphasis.

🔬 CI: L2 composite — auto-skipped by structural rule in test_lab_grade_primitives.py. Direction-of-effect is verified at the L3 primitive layer; this L2 look's composition is verified by visual review.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
look_landscape_dramatic_moody ColorChecker global look_landscape_dramatic_moody grayscale global look_landscape_dramatic_moody ColorChecker masked look_landscape_dramatic_moody grayscale masked

look_landscape_sky_enhance 🟦 mask-bound

Sky-targeted enhancement (Heaton 'adaptive sky' shape). Cool-tone highlights shift (hue 200, sat 0.15) + slight vibrance (+0.05). Pre-baked with mask_sky (RFC-032) so the move scopes to the sky region automatically. Compose, don't replace — this is a focused enhancement to stack on top of any landscape look. For complex skies (sunsets, partial clouds, trees protruding into sky), override mask_spec with a constructed path mask via render_preview + LLM-vision (llm-vision-for-masks.md Pattern 7).

🔬 CI: L2 composite — auto-skipped by structural rule in test_lab_grade_primitives.py. Direction-of-effect is verified at the L3 primitive layer; this L2 look's composition is verified by visual review.

ColorChecker Grayscale ramp
look_landscape_sky_enhance ColorChecker look_landscape_sky_enhance grayscale

On the landscape raw fixture (real-raw content matching this entry's requires_content tags; the chart's module-level signal is honest, but the content-level payoff shows here):

Landscape raw
look_landscape_sky_enhance content Landscape raw

look_landscape_water_silk 🟦 mask-bound

Water surfaces — silky water in long-exposure work, glassy lakes. Bilat clarity_strength -0.4 (smooths the texture, OPPOSITE of clarity), cool-tone shadows (hue 200, sat 0.10), vibrance +0.05. Pre-baked with mask_water_blue_cyan so the smoothing scopes to water without affecting rocks, foliage, or sky. Reduces clarity selectively to enhance the smoothness photographers spent shutter-time creating.

🔬 CI: L2 composite — auto-skipped by structural rule in test_lab_grade_primitives.py. Direction-of-effect is verified at the L3 primitive layer; this L2 look's composition is verified by visual review.

ColorChecker Grayscale ramp
look_landscape_water_silk ColorChecker look_landscape_water_silk grayscale

On the landscape raw fixture (real-raw content matching this entry's requires_content tags; the chart's module-level signal is honest, but the content-level payoff shows here):

Landscape raw
look_landscape_water_silk content Landscape raw

look_wildlife_subject_sharpen 🟦 mask-bound

Subject-isolated wildlife sharpening — feather / fur / scale detail lifted ON THE SUBJECT only via mask_subject (RFC-032). Sharpen amount 2.0 + bilat clarity 0.3. The chemigram realization of LR's Subject-mask + Sharpening + selective Texture pattern (Sweileh, Matiash, Dale, Gardner all reach for this). Compose with mask_subject in the manifest; pair with look_wildlife_background_blur for compositional subject emphasis.

🔬 CI: L2 composite — auto-skipped by structural rule in test_lab_grade_primitives.py. Direction-of-effect is verified at the L3 primitive layer; this L2 look's composition is verified by visual review.

ColorChecker Grayscale ramp
look_wildlife_subject_sharpen ColorChecker look_wildlife_subject_sharpen grayscale

look_wildlife_background_blur 🟦 mask-bound

Background softening for wildlife — bilat clarity_strength -0.5 (the softening direction; opposite of clarity boost). Pre-baked with mask_subject + invert: true (RFC-034) so the softening scopes to everything-except-subject. Mimics longer-lens / shallower-DOF rendering at edit time. Pair with look_wildlife_subject_sharpen for complete subject emphasis. Marc/Bushcrafter darktable-discipline made portable.

🔬 CI: L2 composite — auto-skipped by structural rule in test_lab_grade_primitives.py. Direction-of-effect is verified at the L3 primitive layer; this L2 look's composition is verified by visual review.

ColorChecker Grayscale ramp
look_wildlife_background_blur ColorChecker look_wildlife_background_blur grayscale

look_wildlife_eye_lift 🟦 mask-bound

Catchlight emphasis on the wildlife subject's eye — exposure +0.3 EV + sharpen amount 1.5, scoped to mask_eye_region (RFC-032). The eye becomes the brightest, sharpest point in the frame; gives the bird / animal its 'life.' Cross-genre echo of Portrait Move 7 (eye-detail lift). For close-up wildlife where the subject's gaze is the picture.

🔬 CI: L2 composite — auto-skipped by structural rule in test_lab_grade_primitives.py. Direction-of-effect is verified at the L3 primitive layer; this L2 look's composition is verified by visual review.

ColorChecker Grayscale ramp
look_wildlife_eye_lift ColorChecker look_wildlife_eye_lift grayscale

look_food_texture_subtle 🟦 mask-bound

Subtle texture lift for food — bread crust, pastry layers, meat fibers, fruit skin texture. Bilat clarity_strength +0.20 — explicit ceiling matching the food-photography-academy 'never overdone' discipline (Kopcok: 'overdoing clarity makes food look dry and unappealing'). Pre-baked with mask_subject so the texture lift scopes to the food, not the table / plate. Compose with look_food_appetizing_warm.

🔬 CI: L2 composite — auto-skipped by structural rule in test_lab_grade_primitives.py. Direction-of-effect is verified at the L3 primitive layer; this L2 look's composition is verified by visual review.

ColorChecker Grayscale ramp
look_food_texture_subtle ColorChecker look_food_texture_subtle grayscale

On the landscape raw fixture (real-raw content matching this entry's requires_content tags; the chart's module-level signal is honest, but the content-level payoff shows here):

Landscape raw
look_food_texture_subtle content Landscape raw

look_product_packshot_clean

Commercial packshot baseline — gentle sigmoid 1.10 (avoids the punch-the-product look), subtle vignette -0.10 (-10% brightness edges; pulls the eye to the centered product). Karl Taylor / Zoe Noble's commercial-product clean-on-white starting point. Assumes WB has been gray-card-corrected (use wb_from_gray_card MCP tool / CLI before this look applies).

🔬 CI: L2 composite — auto-skipped by structural rule in test_lab_grade_primitives.py. Direction-of-effect is verified at the L3 primitive layer; this L2 look's composition is verified by visual review.

ColorChecker (global) Grayscale (global) ColorChecker (centered ellipse mask) Grayscale (centered ellipse mask)
look_product_packshot_clean ColorChecker global look_product_packshot_clean grayscale global look_product_packshot_clean ColorChecker masked look_product_packshot_clean grayscale masked

Real-raw entries

These entries touch raw-domain darktable modules (colorequal, denoiseprofile, lens, hazeremoval, ashift, crop, retouch, filmicrgb, diffuse) — or compose looks that include one. The synthetic chart can't represent the input these modules expect; rendering against it produces structurally-misleading output. Each entry is routed to either the landscape or portrait CC BY-SA 4.0 fixture from tests/fixtures/raws/ so the after-image is honest. Apply-path correctness is independently verified by the unit + integration + e2e test coverage.

crop 📷 landscape raw

Parameterized crop (RFC-022 Tier 2). Pass --param cx=V cy=V cw=V ch=V — each in [0.0, 1.0]. Default 0,0,1,1 (no crop). cx/cy = top-left margin, cw/ch = bottom-right margin (so crop region is [cx..cw] x [cy..ch] in normalized coords). First workflow-primitive parameterized entry; aspect-ratio constraint preserved at -1/-1 (free).

🔬 CI assertions (parametric): - center_80pct (cx=0.1, cy=0.1, cw=0.9, ch=0.9) → render_completes() against colorchecker - top_half (cx=0, cy=0, cw=1, ch=0.5) → render_completes() against colorchecker

📷 Real-raw rendering (fixture: landscape.ARW, CC BY-SA 4.0). This entry touches a raw-domain darktable module that needs the full input-profile chain. Rendered against the landscape fixture so the after-image is honest. Apply-path correctness is independently verified by the unit + integration + e2e test coverage. See tests/fixtures/raws/README.md for provenance and attribution.

Landscape raw
crop landscape raw

transform 📷 landscape raw

Parameterized perspective / transform (#101). Closes the Lightroom Transform panel parity gap via darktable's ashift module. 5 magnitude axes: --param transform_rotation=V (image rotation in degrees), --param transform_lensshift_v=V (vertical perspective / keystone), --param transform_lensshift_h=V (horizontal perspective), --param transform_shear=V, --param transform_aspect=V (post-transform aspect adjust; default 1.0). Axis names use transform prefix. Lens-tuning floats (focal length, crop factor, ortho-correction) and the user-drawn-lines storage are preserved verbatim — those are darktable-GUI-authored when needed._

🔬 CI assertions (parametric): - rotation (transform_rotation=5) → render_completes() against grayscale - keystone (transform_lensshift_v=0.3, transform_lensshift_h=-0.2) → render_completes() against grayscale - all_axes (transform_rotation=3, transform_lensshift_v=0.2, transform_lensshift_h=-0.1, transform_shear=0.05, transform_aspect=1.1) → render_completes() against grayscale

📷 Real-raw rendering (fixture: landscape.ARW, CC BY-SA 4.0). This entry touches a raw-domain darktable module that needs the full input-profile chain. Rendered against the landscape fixture so the after-image is honest. Apply-path correctness is independently verified by the unit + integration + e2e test coverage. See tests/fixtures/raws/README.md for provenance and attribution.

Landscape raw
transform landscape raw

lens_correction 📷 landscape raw

Parameterized lens correction (#95). 10 manual-override magnitude axes via darktable's lens module: --param lens_scale=V (output scaling), --param lens_tca_r=V / lens_tca_b=V (manual TCA shifts; 1.0 = no shift), --param lens_cor_distortion=V / lens_cor_vignette=V / lens_cor_ca_r=V / lens_cor_ca_b=V (per-correction-type strengths for embedded-metadata method), --param lens_v_strength=V / lens_v_radius=V / lens_v_steepness=V (manual vignette correction). NOTE: this entry's photographic effect requires lensfun identifier strings (camera/lens) and shooting metadata (focal/aperture/distance) to be populated. EXIF auto-binding for these is a follow-up; until then, the entry is most useful for overriding strength sliders on a darktable-GUI-authored baseline.

🔬 CI assertions (parametric): - v_strength (lens_v_strength=0.5) → render_completes() against grayscale - tca_shift (lens_tca_r=1.005, lens_tca_b=0.995) → render_completes() against grayscale - all_strength_axes (lens_scale=1, lens_cor_distortion=0.8, lens_cor_vignette=0.6, lens_v_strength=0.4) → render_completes() against grayscale

📷 Real-raw rendering (fixture: landscape.ARW, CC BY-SA 4.0). This entry touches a raw-domain darktable module that needs the full input-profile chain. Rendered against the landscape fixture so the after-image is honest. Apply-path correctness is independently verified by the unit + integration + e2e test coverage. See tests/fixtures/raws/README.md for provenance and attribution.

Landscape raw
lens_correction landscape raw

denoise 📷 landscape raw

Parameterized denoising via darktable's denoiseprofile module (#96). NLMEANS (non-local-means) mode with 4 magnitude axes: --param denoise_strength=V (primary noise slider; range [0.001, 1000.0]), --param denoise_shadows=V (preserve shadow noise vs detail; range [0.0, 1.8]), --param denoise_radius=V (patch size; range [0.0, 12.0]), --param denoise_scattering=V (search-zone spread; range [0.0, 20.0]). Axis names carry the denoise prefix to disambiguate from same-named axes on other modules (e.g. dehaze.strength). Per-channel noise calibration a[3]/b[3] auto-populated by darktable from camera+ISO database. WAVELETS mode would need an empirically-captured wavelet-curve baseline (tracked under #100 / task C); for now NLMEANS ships clean and lines up with Lightroom's patch-similarity Noise Reduction._

🔬 CI assertions (parametric): - strength_strong (denoise_strength=5) → render_completes() against grayscale - shadows_protect (denoise_shadows=1.6) → render_completes() against grayscale - all_axes (denoise_strength=3, denoise_shadows=1.4, denoise_radius=2, denoise_scattering=1) → render_completes() against grayscale

📷 Real-raw rendering (fixture: landscape.ARW, CC BY-SA 4.0). This entry touches a raw-domain darktable module that needs the full input-profile chain. Rendered against the landscape fixture so the after-image is honest. Apply-path correctness is independently verified by the unit + integration + e2e test coverage. See tests/fixtures/raws/README.md for provenance and attribution.

Landscape raw
denoise landscape raw

filmic 📷 landscape raw

Parameterized filmic v6 tone mapping (#97). Modern darktable tone-mapping; ships parallel to sigmoid (~80% of tone-mapping use cases). 8 magnitude axes: grey_point_source (default 18.45%), black_point_source (default -8.0 EV), white_point_source (default 4.0 EV), output_power (default 4.0 gamma), latitude (default 0.01), contrast (default 1.0), saturation (default 0.0), balance (default 0.0). Curve mode enums (shadows/highlights/preserve_color/version/spline_version) are pinned at darktable defaults; author discrete entries for non-default modes.

🔬 CI assertions (parametric): - contrast_strong (contrast=2) → render_completes() against grayscale - saturation_boost (saturation=25) → render_completes() against grayscale - all_axes (grey_point_source=18.45, black_point_source=-8, white_point_source=4, output_power=4, contrast=1.5, saturation=15, balance=5) → render_completes() against grayscale

📷 Real-raw rendering (fixture: landscape.ARW, CC BY-SA 4.0). This entry touches a raw-domain darktable module that needs the full input-profile chain. Rendered against the landscape fixture so the after-image is honest. Apply-path correctness is independently verified by the unit + integration + e2e test coverage. See tests/fixtures/raws/README.md for provenance and attribution.

Landscape raw
filmic landscape raw

texture 📷 landscape raw

Parameterized texture (#92 Bucket A.6). Lightroom-style Texture via darktable's diffuse-or-sharpen module. Three axes: --param first=V (finest detail scale, primary Texture axis; range [-1.0, 1.0]), --param second=V (next-up scale; range [-1.0, 1.0]), --param sharpness=V (global sharpening; range [-1.0, 1.0]). Negative values smooth, positive enhance. All default 0.0. Closes the Lightroom Texture parity gap.

🔬 CI assertions (parametric): - first_strong (first=0.5) → render_completes() against grayscale - first_smoothing (first=-0.3) → render_completes() against grayscale - all_axes (first=0.5, second=0.3, sharpness=0.4) → render_completes() against grayscale

📷 Real-raw rendering (fixture: landscape.ARW, CC BY-SA 4.0). This entry touches a raw-domain darktable module that needs the full input-profile chain. Rendered against the landscape fixture so the after-image is honest. Apply-path correctness is independently verified by the unit + integration + e2e test coverage. See tests/fixtures/raws/README.md for provenance and attribution.

Landscape raw
texture landscape raw

hsl_saturation 📷 landscape raw

Parameterized HSL Saturation row (RFC-023). Lightroom HSL Color Mixer Saturation parity via darktable's colorequal module. 8 per-color axes (sat_red, sat_orange, sat_yellow, sat_green, sat_cyan, sat_blue, sat_lavender, sat_magenta); each range [-1.0, 1.0]; default 0.0. Negative desaturates that color zone (e.g. sat_orange=-0.3 → mute skin tones); positive boosts. Compose with hsl_hue and hsl_luminance for the full HSL Color Mixer.

🔬 CI assertions (parametric): - sat_blue (sat_blue=0.5) → render_completes() against grayscale - sat_orange_negative (sat_orange=-0.3) → render_completes() against grayscale - full_row (sat_red=0.2, sat_orange=-0.1, sat_blue=0.3, sat_green=0.2) → render_completes() against grayscale

📷 Real-raw rendering (fixture: landscape.ARW, CC BY-SA 4.0). This entry touches a raw-domain darktable module that needs the full input-profile chain. Rendered against the landscape fixture so the after-image is honest. Apply-path correctness is independently verified by the unit + integration + e2e test coverage. See tests/fixtures/raws/README.md for provenance and attribution.

Landscape raw
hsl_saturation landscape raw

hsl_hue 📷 landscape raw

Parameterized HSL Hue row (RFC-023). Lightroom HSL Color Mixer Hue parity via colorequal. 8 per-color hue-shift axes (hue_red, hue_orange, hue_yellow, hue_green, hue_cyan, hue_blue, hue_lavender, hue_magenta); each range [-180.0, 180.0] degrees; default 0.0. Shifts that color zone toward an adjacent hue (e.g. hue_green=15.0 → foliage warmer toward yellow).

🔬 CI assertions (parametric): - hue_green (hue_green=15) → render_completes() against grayscale - multi_axis (hue_blue=20, hue_orange=-10) → render_completes() against grayscale

📷 Real-raw rendering (fixture: landscape.ARW, CC BY-SA 4.0). This entry touches a raw-domain darktable module that needs the full input-profile chain. Rendered against the landscape fixture so the after-image is honest. Apply-path correctness is independently verified by the unit + integration + e2e test coverage. See tests/fixtures/raws/README.md for provenance and attribution.

Landscape raw
hsl_hue landscape raw

hsl_luminance 📷 landscape raw

Parameterized HSL Luminance row (RFC-023). Lightroom HSL Color Mixer Luminance parity via colorequal. 8 per-color brightness axes (bright_red, bright_orange, bright_yellow, bright_green, bright_cyan, bright_blue, bright_lavender, bright_magenta); each range [-1.0, 1.0]; default 0.0. Negative darkens that color zone (e.g. bright_blue=-0.3 → deeper sky); positive lightens.

🔬 CI assertions (parametric): - bright_blue_negative (bright_blue=-0.4) → render_completes() against grayscale - multi_axis (bright_red=0.2, bright_yellow=-0.2) → render_completes() against grayscale

📷 Real-raw rendering (fixture: landscape.ARW, CC BY-SA 4.0). This entry touches a raw-domain darktable module that needs the full input-profile chain. Rendered against the landscape fixture so the after-image is honest. Apply-path correctness is independently verified by the unit + integration + e2e test coverage. See tests/fixtures/raws/README.md for provenance and attribution.

Landscape raw
hsl_luminance landscape raw

dehaze 📷 landscape raw

Parameterized dehaze (#90 Bucket A.2). Lightroom-style Dehaze via darktable's hazeremoval module. Two axes: --param strength=V (range [-1.0, 1.0]; positive removes haze, negative adds atmospheric fog) and --param distance=V (range [0.0, 1.0]; depth-falloff). Closes the Lightroom Dehaze parity gap.

🔬 CI assertions (parametric): - strength_strong (strength=0.6) → render_completes() against grayscale - strength_negative (strength=-0.4) → render_completes() against grayscale - distance_high (distance=0.7) → render_completes() against grayscale

📷 Real-raw rendering (fixture: landscape.ARW, CC BY-SA 4.0). This entry touches a raw-domain darktable module that needs the full input-profile chain. Rendered against the landscape fixture so the after-image is honest. Apply-path correctness is independently verified by the unit + integration + e2e test coverage. See tests/fixtures/raws/README.md for provenance and attribution.

Landscape raw
dehaze landscape raw

temperature 📷 landscape raw

Parameterized white balance (RFC-021; first multi-parameter ship). Three axes: --param red_coeff=V (warmer image: red↑), --param green_coeff=V (Lightroom Tint axis: green↑ → magenta-shifted, green↓ → green-shifted), --param blue_coeff=V (cooler image: blue↑). Range [0.5, 4.0] each; all default 1.0 (no shift). Replaces the v1.5.x discrete wb_cool_subtle entry. green_coeff added in #90 Bucket A.3 to close the Lightroom Tint parity gap. Starter's wb_warm_subtle remains as a discrete teaching artifact; production use of WB shifts should prefer this parameterized entry.

🔬 CI assertions (parametric): - warmer (red_coeff=2.148, blue_coeff=1.209) → render_completes() against grayscale - cooler (red_coeff=1.209, blue_coeff=2.137) → render_completes() against grayscale - tint_magenta (green_coeff=1.2) → render_completes() against grayscale - tint_green (green_coeff=0.85) → render_completes() against grayscale

📷 Real-raw rendering (fixture: landscape.ARW, CC BY-SA 4.0). This entry touches a raw-domain darktable module that needs the full input-profile chain. Rendered against the landscape fixture so the after-image is honest. Apply-path correctness is independently verified by the unit + integration + e2e test coverage. See tests/fixtures/raws/README.md for provenance and attribution.

Landscape raw
temperature landscape raw

look_vintage_film 📷 landscape raw

L2 look — nostalgia / faded film aesthetic. sigmoid_contrast 1.2 (gentle s-curve), colorbalancergb saturation_global=-0.2 (slight desaturation), grain_strength 25 (medium film grain), temperature warm shift (red 2.148 / blue 1.209). Pairs well with grade_shadows_warm.

🔬 CI: L2 composite — auto-skipped by structural rule in test_lab_grade_primitives.py. Direction-of-effect is verified at the L3 primitive layer; this L2 look's composition is verified by visual review.

📷 Real-raw rendering (fixture: landscape.ARW, CC BY-SA 4.0). This entry touches a raw-domain darktable module that needs the full input-profile chain. Rendered against the landscape fixture so the after-image is honest. Apply-path correctness is independently verified by the unit + integration + e2e test coverage. See tests/fixtures/raws/README.md for provenance and attribution.

Landscape raw
look_vintage_film landscape raw

look_film_kodachrome 📷 landscape raw

L2 look — Kodachrome film simulation (#104). sigmoid_contrast 1.4 + temperature warm (red 2.148 / blue 1.209 = wb_warm_subtle) + saturation_global=+0.2 + grain_strength=8.

🔬 CI: L2 composite — auto-skipped by structural rule in test_lab_grade_primitives.py. Direction-of-effect is verified at the L3 primitive layer; this L2 look's composition is verified by visual review.

📷 Real-raw rendering (fixture: landscape.ARW, CC BY-SA 4.0). This entry touches a raw-domain darktable module that needs the full input-profile chain. Rendered against the landscape fixture so the after-image is honest. Apply-path correctness is independently verified by the unit + integration + e2e test coverage. See tests/fixtures/raws/README.md for provenance and attribution.

Landscape raw
look_film_kodachrome landscape raw

look_film_portra 📷 landscape raw

L2 look — Kodak Portra 400 portrait film (#104). sigmoid_contrast 0.9 (soft s-curve) + temperature subtle warm (red 1.5 / blue 1.3) + saturation_global=-0.1 + grain_strength=15. Compose with hsl_saturation --param sat_orange=+0.05 if you want the canonical Portra skin-warmth boost on real raws.

🔬 CI: L2 composite — auto-skipped by structural rule in test_lab_grade_primitives.py. Direction-of-effect is verified at the L3 primitive layer; this L2 look's composition is verified by visual review.

📷 Real-raw rendering (fixture: landscape.ARW, CC BY-SA 4.0). This entry touches a raw-domain darktable module that needs the full input-profile chain. Rendered against the landscape fixture so the after-image is honest. Apply-path correctness is independently verified by the unit + integration + e2e test coverage. See tests/fixtures/raws/README.md for provenance and attribution.

Landscape raw
look_film_portra landscape raw

look_70s_film 📷 landscape raw

L2 look — 1970s film aesthetic (#104). temperature warm (red 2.0 / blue 1.4) + sigmoid_contrast 1.1 (gentle s-curve) + saturation_global=-0.1 + grain_strength=35 (medium grain).

🔬 CI: L2 composite — auto-skipped by structural rule in test_lab_grade_primitives.py. Direction-of-effect is verified at the L3 primitive layer; this L2 look's composition is verified by visual review.

📷 Real-raw rendering (fixture: landscape.ARW, CC BY-SA 4.0). This entry touches a raw-domain darktable module that needs the full input-profile chain. Rendered against the landscape fixture so the after-image is honest. Apply-path correctness is independently verified by the unit + integration + e2e test coverage. See tests/fixtures/raws/README.md for provenance and attribution.

Landscape raw
look_70s_film landscape raw

look_90s_grain 📷 landscape raw

L2 look — 1990s film aesthetic (#104). sigmoid_contrast 1.6 + temperature subtle cool (red 1.2 / blue 2.0) + grain_strength=50 (heavy grain).

🔬 CI: L2 composite — auto-skipped by structural rule in test_lab_grade_primitives.py. Direction-of-effect is verified at the L3 primitive layer; this L2 look's composition is verified by visual review.

📷 Real-raw rendering (fixture: landscape.ARW, CC BY-SA 4.0). This entry touches a raw-domain darktable module that needs the full input-profile chain. Rendered against the landscape fixture so the after-image is honest. Apply-path correctness is independently verified by the unit + integration + e2e test coverage. See tests/fixtures/raws/README.md for provenance and attribution.

Landscape raw
look_90s_grain landscape raw

look_2000s_digital 📷 landscape raw

L2 look — early-2000s digital camera aesthetic (#104). sigmoid_contrast 1.3 + temperature subtle cool (red 1.1 / blue 1.6) + saturation_global=+0.4 (oversaturated digital signature).

🔬 CI: L2 composite — auto-skipped by structural rule in test_lab_grade_primitives.py. Direction-of-effect is verified at the L3 primitive layer; this L2 look's composition is verified by visual review.

📷 Real-raw rendering (fixture: landscape.ARW, CC BY-SA 4.0). This entry touches a raw-domain darktable module that needs the full input-profile chain. Rendered against the landscape fixture so the after-image is honest. Apply-path correctness is independently verified by the unit + integration + e2e test coverage. See tests/fixtures/raws/README.md for provenance and attribution.

Landscape raw
look_2000s_digital landscape raw

skin_uniformity 📷 portrait raw

Skin-tone uniformity (RFC-033). Compresses skin-band saturation variance toward uniform appearance — Capture One's Skin Tone Uniformity equivalent for chemigram. Pre-baked with mask_skin_region so the move is scoped automatically. Pass --value V or --param sat_orange=V; range [-1.0, 0.0]. -0.3 is moderate uniformity; -0.6 is strong (typical Woloszynowicz/Adler/Nordqvist range); -1.0 fully desaturates the skin band; 0.0 is no-op. Override mask_spec for per-image manual mask if mask_skin_region's hue-range fallback leaks (Phase-1 LLM-vision fallback per RFC-032). Frequency-separation texture work composes orthogonally; this primitive is color-band uniformity only.

🔬 CI: skipped — Skin-uniformity primitive (RFC-033); needs visual review per the darkroom-session checkpoint, not flat-patch isolation.

📷 Real-raw rendering (fixture: portrait.ARW, CC BY-SA 4.0). This entry touches a raw-domain darktable module that needs the full input-profile chain. Rendered against the portrait fixture so the after-image is honest. Apply-path correctness is independently verified by the unit + integration + e2e test coverage. See tests/fixtures/raws/README.md for provenance and attribution.

Portrait raw
skin_uniformity portrait raw

look_portrait_natural_skin 📷 portrait raw

Restraint-first portrait foundation — Tucker/Marino-aligned. Slight warm temperature (+0.03 red), exposure +0.1 EV, sigmoid contrast 1.2 (gentle s-curve), saturation_global -0.05 + vibrance +0.1 (mild chroma shaping that protects skin tones). The starting point for portrait work that doesn't push contrast or saturation as a stylistic choice.

🔬 CI: L2 composite — auto-skipped by structural rule in test_lab_grade_primitives.py. Direction-of-effect is verified at the L3 primitive layer; this L2 look's composition is verified by visual review.

📷 Real-raw rendering (fixture: portrait.ARW, CC BY-SA 4.0). This entry touches a raw-domain darktable module that needs the full input-profile chain. Rendered against the portrait fixture so the after-image is honest. Apply-path correctness is independently verified by the unit + integration + e2e test coverage. See tests/fixtures/raws/README.md for provenance and attribution.

Portrait raw
look_portrait_natural_skin portrait raw

look_portrait_skin_warm_lift 📷 portrait raw

Subject-region warm + brighten. Slight warm temperature (+0.04 red) + exposure +0.2 EV. Pre-baked with mask_skin_region so the lift scopes to skin without affecting clothing or background. Pairs with skin_uniformity for a complete portrait skin pass.

🔬 CI: L2 composite — auto-skipped by structural rule in test_lab_grade_primitives.py. Direction-of-effect is verified at the L3 primitive layer; this L2 look's composition is verified by visual review.

📷 Real-raw rendering (fixture: portrait.ARW, CC BY-SA 4.0). This entry touches a raw-domain darktable module that needs the full input-profile chain. Rendered against the portrait fixture so the after-image is honest. Apply-path correctness is independently verified by the unit + integration + e2e test coverage. See tests/fixtures/raws/README.md for provenance and attribution.

Portrait raw
look_portrait_skin_warm_lift portrait raw

look_landscape_golden_hour 📷 landscape raw

Sunset / sunrise mood. Warm temperature shift (+0.07 red), sigmoid contrast 1.3, warm shadows (hue 30, sat 0.20) + amber highlights (hue 50, sat 0.15), vibrance +0.10. Pushes the warmth that golden-hour light almost has and amplifies it without breaking color credibility. For scenes already on the warm side, apply at lower strength via opacity — not authored as parametric (look-not-primitive).

🔬 CI: L2 composite — auto-skipped by structural rule in test_lab_grade_primitives.py. Direction-of-effect is verified at the L3 primitive layer; this L2 look's composition is verified by visual review.

📷 Real-raw rendering (fixture: landscape.ARW, CC BY-SA 4.0). This entry touches a raw-domain darktable module that needs the full input-profile chain. Rendered against the landscape fixture so the after-image is honest. Apply-path correctness is independently verified by the unit + integration + e2e test coverage. See tests/fixtures/raws/README.md for provenance and attribution.

Landscape raw
look_landscape_golden_hour landscape raw

look_landscape_blue_hour_cool 📷 landscape raw

Twilight / pre-dawn / blue-hour mood. Cool temperature shift (+0.07 blue), sigmoid contrast 1.3, cool shadows (hue 210, sat 0.20) + neutral-cool highlights (hue 200, sat 0.10), saturation_global -0.05. Opposite mood from golden_hour; equally valid genre signature. Composes with sigmoid_contrast for stronger drama if needed.

🔬 CI: L2 composite — auto-skipped by structural rule in test_lab_grade_primitives.py. Direction-of-effect is verified at the L3 primitive layer; this L2 look's composition is verified by visual review.

📷 Real-raw rendering (fixture: landscape.ARW, CC BY-SA 4.0). This entry touches a raw-domain darktable module that needs the full input-profile chain. Rendered against the landscape fixture so the after-image is honest. Apply-path correctness is independently verified by the unit + integration + e2e test coverage. See tests/fixtures/raws/README.md for provenance and attribution.

Landscape raw
look_landscape_blue_hour_cool landscape raw

look_landscape_atmospheric_haze 📷 landscape raw

Misty / hazy / fog-as-subject mood. Hazeremoval strength 0.5 (lift visibility while preserving the moody atmosphere), bilat clarity 0.3, warm shadows (hue 30, sat 0.10) + vibrance +0.05. The trick: lift JUST enough to read details, not enough to flatten the atmosphere. Strong hazeremoval values (>1.0) produce 'no atmosphere' results that defeat the intent — keep restrained.

🔬 CI: L2 composite — auto-skipped by structural rule in test_lab_grade_primitives.py. Direction-of-effect is verified at the L3 primitive layer; this L2 look's composition is verified by visual review.

📷 Real-raw rendering (fixture: landscape.ARW, CC BY-SA 4.0). This entry touches a raw-domain darktable module that needs the full input-profile chain. Rendered against the landscape fixture so the after-image is honest. Apply-path correctness is independently verified by the unit + integration + e2e test coverage. See tests/fixtures/raws/README.md for provenance and attribution.

Landscape raw
look_landscape_atmospheric_haze landscape raw

look_landscape_autumn_pop 📷 landscape raw

Autumn foliage / fall color. Slight warm temperature (+0.04 red), colorequal sat_orange +0.30 + sat_red +0.20 (lift autumn colors) + sat_blue -0.10 (compensating to keep skies natural — without this, skies turn cartoonish). Bilat clarity_strength 0.4 for foliage definition. A targeted seasonal grade; not for non-foliage scenes.

🔬 CI: L2 composite — auto-skipped by structural rule in test_lab_grade_primitives.py. Direction-of-effect is verified at the L3 primitive layer; this L2 look's composition is verified by visual review.

📷 Real-raw rendering (fixture: landscape.ARW, CC BY-SA 4.0). This entry touches a raw-domain darktable module that needs the full input-profile chain. Rendered against the landscape fixture so the after-image is honest. Apply-path correctness is independently verified by the unit + integration + e2e test coverage. See tests/fixtures/raws/README.md for provenance and attribution.

Landscape raw
look_landscape_autumn_pop landscape raw

bw_convert 📷 landscape raw

B&W conversion (RFC-033 follow-up; survey Gap #1). Single colorequal plugin with all 8 sat axes set to -1.0 (full saturation kill = grayscale). Exposes 8 bright_X parameters emulating Adams-school color-filter strength: bright_red +0.3 lightens skin / red flowers / darkens skies in B&W; bright_blue -0.2 darkens skies; bright_green +0.3 lightens foliage; etc. The chemigram analog of Photoshop Channel Mixer (Monochrome) and Silver Efex Color Filters. Universal Step 1 of any B&W workflow per the photographer survey (6/6 photographers reach for color-filter-driven conversion as their foundational B&W move).

🔬 CI assertion: chroma_zero(8) against the colorchecker fixture.

📷 Real-raw rendering (fixture: landscape.ARW, CC BY-SA 4.0). This entry touches a raw-domain darktable module that needs the full input-profile chain. Rendered against the landscape fixture so the after-image is honest. Apply-path correctness is independently verified by the unit + integration + e2e test coverage. See tests/fixtures/raws/README.md for provenance and attribution.

Landscape raw
bw_convert landscape raw

look_bw_classic_neutral 📷 landscape raw

Classic B&W foundation — neutral channel weighting (no filter), mid contrast (sigmoid 1.3), mild structure (clarity 0.3). The starting point for any B&W work; compose with split-tone or chiaroscuro variants for stylistic direction. Per RFC-033 / survey Gap #1.

🔬 CI: L2 composite — auto-skipped by structural rule in test_lab_grade_primitives.py. Direction-of-effect is verified at the L3 primitive layer; this L2 look's composition is verified by visual review.

📷 Real-raw rendering (fixture: landscape.ARW, CC BY-SA 4.0). This entry touches a raw-domain darktable module that needs the full input-profile chain. Rendered against the landscape fixture so the after-image is honest. Apply-path correctness is independently verified by the unit + integration + e2e test coverage. See tests/fixtures/raws/README.md for provenance and attribution.

Landscape raw
look_bw_classic_neutral landscape raw

look_bw_high_contrast_chiaroscuro 📷 landscape raw

Tucker/Thompson-style chiaroscuro B&W — strong sigmoid contrast (1.7), deep shadow brilliance (-0.20), lifted highlight brilliance (+0.10). For street/portrait B&W where dramatic light-shadow interplay defines the image. Compose with mask_subject for directional facial sculpting (Tucker portrait discipline).

🔬 CI: L2 composite — auto-skipped by structural rule in test_lab_grade_primitives.py. Direction-of-effect is verified at the L3 primitive layer; this L2 look's composition is verified by visual review.

📷 Real-raw rendering (fixture: landscape.ARW, CC BY-SA 4.0). This entry touches a raw-domain darktable module that needs the full input-profile chain. Rendered against the landscape fixture so the after-image is honest. Apply-path correctness is independently verified by the unit + integration + e2e test coverage. See tests/fixtures/raws/README.md for provenance and attribution.

Landscape raw
look_bw_high_contrast_chiaroscuro landscape raw

look_bw_landscape_dramatic 📷 landscape raw

Page/Adamus dramatic B&W landscape — red-filter-emulated conversion (bright_red +0.20 lightens land; bright_blue -0.30 darkens skies — the classic Adams-school red filter for storm-cloud drama). Sigmoid contrast 1.6 + clarity 0.5. For stormy skies, rugged terrain, weather drama. The B&W counterpart of look_landscape_dramatic_moody.

🔬 CI: L2 composite — auto-skipped by structural rule in test_lab_grade_primitives.py. Direction-of-effect is verified at the L3 primitive layer; this L2 look's composition is verified by visual review.

📷 Real-raw rendering (fixture: landscape.ARW, CC BY-SA 4.0). This entry touches a raw-domain darktable module that needs the full input-profile chain. Rendered against the landscape fixture so the after-image is honest. Apply-path correctness is independently verified by the unit + integration + e2e test coverage. See tests/fixtures/raws/README.md for provenance and attribution.

Landscape raw
look_bw_landscape_dramatic landscape raw

look_bw_split_tone_warm_shadows 📷 landscape raw

Subtle warm-shadows toned B&W — sepia / selenium print evocation. Neutral B&W conversion + mid-strong sigmoid contrast (1.35) + warm-tone shadows (hue 30, sat 0.05) + cool-tone highlights (hue 210, sat 0.03). The split-tone tinting reads as 'toned print' rather than pure neutral B&W.

🔬 CI: L2 composite — auto-skipped by structural rule in test_lab_grade_primitives.py. Direction-of-effect is verified at the L3 primitive layer; this L2 look's composition is verified by visual review.

📷 Real-raw rendering (fixture: landscape.ARW, CC BY-SA 4.0). This entry touches a raw-domain darktable module that needs the full input-profile chain. Rendered against the landscape fixture so the after-image is honest. Apply-path correctness is independently verified by the unit + integration + e2e test coverage. See tests/fixtures/raws/README.md for provenance and attribution.

Landscape raw
look_bw_split_tone_warm_shadows landscape raw

look_bw_silver_efex_zone_balanced 📷 landscape raw

Whalley/Boutwell zone-system-aware balanced B&W — the restraint discipline applied to monochrome. Neutral conversion + gentle sigmoid contrast (1.15) + subtle clarity (0.15). The defining stylistic position for B&W work that doesn't push contrast or structure as a dramatic move; reads as 'measured tonal development' (Adams-school).

🔬 CI: L2 composite — auto-skipped by structural rule in test_lab_grade_primitives.py. Direction-of-effect is verified at the L3 primitive layer; this L2 look's composition is verified by visual review.

📷 Real-raw rendering (fixture: landscape.ARW, CC BY-SA 4.0). This entry touches a raw-domain darktable module that needs the full input-profile chain. Rendered against the landscape fixture so the after-image is honest. Apply-path correctness is independently verified by the unit + integration + e2e test coverage. See tests/fixtures/raws/README.md for provenance and attribution.

Landscape raw
look_bw_silver_efex_zone_balanced landscape raw

look_wildlife_high_iso_recovery 📷 landscape raw

High-ISO wildlife recovery (low-light dance-floor, late dusk owl, early-dawn bird-burst). Manual denoiseprofile (nbhood 7, strength 1.2, scattering 2.0) + gentle sigmoid 1.25 + subtle clarity 0.2. Note: for ISO ≥ 1600 most surveyed wildlife photographers ROUTE THROUGH a sibling AI-NR tool (Topaz DeNoise / DxO PureRAW / LR AI Denoise) BEFORE this look applies; document the BYOA pattern in vocabulary-patterns.md. This look is the chemigram-only manual fallback when sibling tooling isn't configured.

🔬 CI: L2 composite — auto-skipped by structural rule in test_lab_grade_primitives.py. Direction-of-effect is verified at the L3 primitive layer; this L2 look's composition is verified by visual review.

📷 Real-raw rendering (fixture: landscape.ARW, CC BY-SA 4.0). This entry touches a raw-domain darktable module that needs the full input-profile chain. Rendered against the landscape fixture so the after-image is honest. Apply-path correctness is independently verified by the unit + integration + e2e test coverage. See tests/fixtures/raws/README.md for provenance and attribution.

Landscape raw
look_wildlife_high_iso_recovery landscape raw

look_wildlife_natural_warm 📷 landscape raw

Warm golden-hour wildlife default — temperature +0.05 red shift + sigmoid 1.25 + vibrance +0.10 with slight saturation_global pull (-0.03 to keep the warmth credible, not cartoonish). The starting point for early-morning / late-afternoon wildlife where natural warmth IS the subject. Compose with look_wildlife_subject_sharpen for full effect.

🔬 CI: L2 composite — auto-skipped by structural rule in test_lab_grade_primitives.py. Direction-of-effect is verified at the L3 primitive layer; this L2 look's composition is verified by visual review.

📷 Real-raw rendering (fixture: landscape.ARW, CC BY-SA 4.0). This entry touches a raw-domain darktable module that needs the full input-profile chain. Rendered against the landscape fixture so the after-image is honest. Apply-path correctness is independently verified by the unit + integration + e2e test coverage. See tests/fixtures/raws/README.md for provenance and attribution.

Landscape raw
look_wildlife_natural_warm landscape raw

look_food_appetizing_warm 📷 landscape raw

Default food editorial — warm WB (+0.04 red), gentle sigmoid 1.25, vibrance +0.15 + lifted midtone brilliance +0.08. Lauren C. Short / Darina Kopcok / Joanie Simon's foundational starting point for food blog and editorial work. Pre-WB-foundation (gray card recommended); downstream HSL color shaping per look_food_orange_pop / look_food_green_natural compose orthogonally.

🔬 CI: L2 composite — auto-skipped by structural rule in test_lab_grade_primitives.py. Direction-of-effect is verified at the L3 primitive layer; this L2 look's composition is verified by visual review.

📷 Real-raw rendering (fixture: landscape.ARW, CC BY-SA 4.0). This entry touches a raw-domain darktable module that needs the full input-profile chain. Rendered against the landscape fixture so the after-image is honest. Apply-path correctness is independently verified by the unit + integration + e2e test coverage. See tests/fixtures/raws/README.md for provenance and attribution.

Landscape raw
look_food_appetizing_warm landscape raw

look_food_orange_pop 📷 landscape raw

Lift the orange / red food band — tomato, carrot, salmon, paprika, peach. Colorequal sat_orange +0.30 + sat_red +0.20 (saturation lift on warm food colors) + slight brightness lifts. The HSL-per-color discipline that food photographers use INSTEAD of global saturation (which would destroy whites and greens). Compose on top of look_food_appetizing_warm.

🔬 CI: L2 composite — auto-skipped by structural rule in test_lab_grade_primitives.py. Direction-of-effect is verified at the L3 primitive layer; this L2 look's composition is verified by visual review.

📷 Real-raw rendering (fixture: landscape.ARW, CC BY-SA 4.0). This entry touches a raw-domain darktable module that needs the full input-profile chain. Rendered against the landscape fixture so the after-image is honest. Apply-path correctness is independently verified by the unit + integration + e2e test coverage. See tests/fixtures/raws/README.md for provenance and attribution.

Landscape raw
look_food_orange_pop landscape raw

look_food_green_natural 📷 landscape raw

Lift greens — fresh herbs, salad, parsley, basil — without crossing into the cartoonish lime-green that over-edited food photography shows. Colorequal sat_green +0.20 + sat_yellow +0.10 + bright_green +0.05. The restraint discipline applied to color shaping (Tucker / Marino voice in food work). Compose on top of look_food_appetizing_warm.

🔬 CI: L2 composite — auto-skipped by structural rule in test_lab_grade_primitives.py. Direction-of-effect is verified at the L3 primitive layer; this L2 look's composition is verified by visual review.

📷 Real-raw rendering (fixture: landscape.ARW, CC BY-SA 4.0). This entry touches a raw-domain darktable module that needs the full input-profile chain. Rendered against the landscape fixture so the after-image is honest. Apply-path correctness is independently verified by the unit + integration + e2e test coverage. See tests/fixtures/raws/README.md for provenance and attribution.

Landscape raw
look_food_green_natural landscape raw

Notes

  • Inputs are sRGB PNGs, not raw files. darktable processes them through its non-raw path — input color profile applies, demosaic does not. Some primitives (e.g., raw-aware white-balance moves) behave differently from how they would on a real raw. The gallery is for visual response validation, not pipeline calibration; for raw-pipeline direction-of-change validation see the e2e suite in tests/e2e/.

  • Mask-bound entries (gradient/ellipse/rectangle, marked 🟦 above) route through the drawn-mask apply path per ADR-076. The mask geometry encodes into the XMP's masks_history; you see the spatial shaping in the rendered chart.

  • Out-of-gamut patches on the ColorChecker (notably patch #18 Cyan) clip to nearest in-gamut sRGB; that clipping is in the input, not the primitive. See reference-targets/README.md.