WIP: clarity and texture

Checkpoint committed by the coordinator, not by the authoring agent: the
session hit its API limit mid-task and left this work uncommitted. Committed
so it survives, NOT because it is finished - expect failing tests and
half-applied changes. The agent resumes from here.
This commit is contained in:
2026-08-22 19:01:18 +02:00
parent c963dafd09
commit 97d4bd9061
6 changed files with 1542 additions and 1 deletions
+36
View File
@@ -0,0 +1,36 @@
# A hand-written node. `rust:` names the type in `crate::ops` that implements
# `Operation`; its descriptor, its parameters and its passes come from that
# type rather than from this file. It appears here anyway because `ops/` is
# where the pipeline's order is written down, and an order kept half in YAML
# and half in Rust would be worse than either alone.
id: clarity
order: 120
attributes: [detail]
rust: Clarity
why_rust: |
A neighbourhood operation. Clarity is defined by what the pixels around a
pixel are doing, and the schema above describes a function of one colour —
`wgsl:` is handed `c` and no coordinate, which is the wall the detail stage
exists on the other side of. It declares `Affects::Detail` and returns two
`DetailPass`es: a Gaussian of log luminance along each axis, the second of
which also applies the mask.
A kernel is also not four facts. Stretching this schema to express a
truncation rule, a soft limit and a midtone taper would produce a worse
language than Rust, aimed at one caller.
placement: |
In the detail group, after noise reduction and before sharpening.
Order inside the group is not arbitrary. Clarity multiplies local contrast,
so it multiplies noise with it — running it before noise reduction would ask
the denoiser to remove grain that clarity had already amplified into
structure. And capture sharpening belongs last, on the picture as it will
finally be, so that the acutance a photographer judges at 1:1 is the acutance
in the file.
Before texture, which is a decade finer: coarse before fine, so the fine
control's base is computed on the modelling the coarse one has already
settled.
+23
View File
@@ -0,0 +1,23 @@
# A hand-written node — see `clarity.yaml`, whose implementation this shares.
id: texture
order: 130
attributes: [detail]
rust: Texture
why_rust: |
The same neighbourhood operation as clarity, at a tenth of the scale: one
implementation in `src/ops/local_contrast.rs`, parameterised by the band it
acts on. Two nodes rather than one node with two sliders because the radius
is the *definition* of each control rather than a setting of it, and because
a texture at zero must then cost nothing at all — which `is_active()` gives
for free and a merged node would have had to hand-write.
placement: |
Immediately after clarity, and for the same reasons: after noise reduction,
which must not be handed amplified grain, and before capture sharpening,
which belongs last.
After clarity specifically, so that the fine base is computed on the
modelling the coarse control has already settled rather than the other way
round.