Files
DarkRoom/core/dr-pipeline/ops/brilliance.yaml
T
dtourolleandClaude Opus 5 65e6a96a65 Say what the application is doing, in one bar and one list
Every background job reported into a window property of its own —
library-thumbs-done, library-pin-total, library-syncing — which only the
grid ever read. A pin download that outlived the view it was started from
drew nothing at all once the user opened an image, and there was no answer
anywhere to "what is this busy with", because the answer was spread across
eight properties nothing collected.

They report to one register now (ui/dr-ui/src/activity.rs). It publishes an
aggregate, which draws a three-pixel bar across the top of the shell in
every view, and a row per job, which the settings page lists: scans,
thumbnail batches, pin and open downloads, sidecar uploads, the sync and
the trash. Failures stay on the list until they are cleared; routine
successes do not, or a scroll would bury them.

The handle removes a still-running job when it drops, so a worker that dies
mid-transfer takes its row with it rather than leaving the bar sweeping for
the rest of the session.

Also carries in-flight work from a parallel session — the drawn icon set
and the dr-pipeline ops split. dr-pipeline's build script does not compile
at this commit; ui/dr-ui does, with clippy clean and its tests passing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-16 18:32:09 +02:00

69 lines
2.3 KiB
YAML

id: brilliance
label: op.brilliance
order: 70
doc: |
Brilliance — shadows up and highlights down at once.
Apple's control, and a genuinely different idea from contrast: it applies
the opposite correction at each end of the range while leaving mid-tones
alone. The result reads as "more light in the scene" rather than "less
contrast", because local relationships survive where a plain contrast
reduction flattens them.
It overlaps with highlights/shadows deliberately — one control doing both
in a fixed relationship is easier to reach for than two controls needing
to be balanced against each other.
placement: |
After the tone curve has had the final word on tone, and before the colour
controls, which should act on the tones the photographer has settled.
params:
brilliance:
label: param.brilliance
kind: amount
uniforms:
amount:
value: brilliance / 100 * 0.5
doc: |
Half a stop at each end at full travel — the two ends move apart by a
stop in total, which is a strong but not destructive flattening.
helpers: [luminance, tone_position, apply_tone_gain]
wgsl: |
let luma = luminance(c);
let pos = tone_position(luma);
// Opposite corrections at the two ends: shadows up, highlights down, both
// tapering to nothing at the mid-point. This is what separates brilliance
// from a contrast control — mid-tones keep their local relationships, so
// the image gains apparent light rather than losing structure.
let lift = (1.0 - smoothstep(0.0, 0.5, pos)) * amount;
let pull = smoothstep(0.5, 1.0, pos) * amount;
// A mild saturation compensation. Flattening the tonal range washes colour
// out; without this, brilliance looks faded at useful settings.
let gain = exp2(lift - pull);
c = c * gain;
let luma_after = luminance(c);
c = mix(vec3<f32>(luma_after), c, 1.0 + max(amount, 0.0) * 0.15);
c = max(c, vec3<f32>(0.0));
tests:
- name: it_starts_neutral
expect_active: false
- name: full_travel_is_half_a_stop_at_each_end
set: { brilliance: 100 }
expect: { amount: 0.5 }
- name: the_two_ends_move_in_opposite_directions
why: |
The property that makes this brilliance rather than a contrast slider.
Both terms scaling the same way would flatten without lifting.
expect_wgsl: ["let gain = exp2(lift - pull);"]