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>
69 lines
2.3 KiB
YAML
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);"]
|