Let an operation say what it is about, so the panel can group without naming
Tool tabs need a taxonomy, and the taxonomy was the problem: a table in `ui/` mapping operation to tab breaks FR-DEV-3a, and a `group:` field risks what `ui-refinement.md` condemned `starts-group` for — the core deciding where the panel draws things. `Attribute` threads the needle. It says what an operation *is* — tone, colour, detail, optics, geometry, effect — which is the same category as `ParamKind` and squarely on the core's side of ARCH §4.3a's line. What is drawn, where it sits and whether it is visible stay the frontend's. There is no attribute for "the third tab", the enum's order is declaration order rather than screen order, and a frontend may render these as tabs, as headings, or ignore them. The payoff is that a tab strip can be *derived*: the groups are the attributes present in the capability list, so the interface names no operation and needs no table to keep in step. An operation joins the right group by declaring what it is, which is the one thing its author is well placed to say. Plural, because the tone curve is genuinely both — an RGB curve is tonal and the per-channel curves are chromatic, and filing it under one would hide it from half the people looking for it. Required and non-empty, enforced in `build.rs`, and the failure was checked by removing the line rather than assumed. An operation with no attribute is invisible to a panel that groups by them; a build that stops costs ten seconds, a control nobody can find costs more. The vocabulary is closed for the same reason: a typo would otherwise invent a category holding exactly one operation, which looks like a deliberate one until somebody counts. Six tests over the real chain, including the hand-written operations that `build.rs` never sees and so cannot check.
This commit is contained in:
@@ -9,6 +9,29 @@ indistinguishable downstream from a hand-written operation: the same
|
||||
`&'static OpDescriptor`, the same fused-shader composition, the same sidecar
|
||||
round-trip.
|
||||
|
||||
## `attributes:` — what the operation is about
|
||||
|
||||
Required, one or more of `tone`, `colour`, `detail`, `optics`, `geometry`,
|
||||
`effect`. The build fails without it, and that is deliberate: an operation with
|
||||
no attribute is invisible to an interface that groups by them, and a control
|
||||
that silently does not exist is a worse failure than a build that stops.
|
||||
|
||||
**Say what the operation is, not where you want it drawn.** The core declares
|
||||
capabilities; the frontend composes (ARCH §4.3a). `tone` means "this is about
|
||||
lightness", not "put this in the second tab" — the interface is free to render
|
||||
attributes as tabs, as headings, or not at all, and that choice may differ
|
||||
between a tablet and a desktop without this file changing.
|
||||
|
||||
**Plural is normal.** The tone curve is `[tone, colour]` because an RGB curve
|
||||
is tonal and the per-channel curves are chromatic; it appears wherever the
|
||||
frontend decides that means. Reach for a second attribute when an operation
|
||||
genuinely answers two questions, not to make it easier to find.
|
||||
|
||||
**The vocabulary is closed.** A typo is a build error rather than a new
|
||||
category containing exactly one operation — which looks identical to a
|
||||
deliberate new category until somebody notices the group with one control in
|
||||
it.
|
||||
|
||||
## What you get for free
|
||||
|
||||
A node dropped in here arrives with:
|
||||
@@ -16,6 +39,9 @@ A node dropped in here arrives with:
|
||||
- **Controls.** The develop panel builds them from the parameters' declared
|
||||
kinds (FR-DEV-3c). It never learns the node's name.
|
||||
- **A place in the chain**, from `order:`.
|
||||
- **A place in the panel**, from `attributes:`. The interface groups by these
|
||||
and names no operation, so a node arrives in the right group by saying what
|
||||
it is rather than by anyone editing a list in `ui/`.
|
||||
- **Persistence.** Parameters are ordinary scalars, so the sidecar writes them
|
||||
with everything else.
|
||||
- **Its tests**, compiled from `tests:` and run with `cargo test`.
|
||||
@@ -28,6 +54,7 @@ A node dropped in here arrives with:
|
||||
id: exposure # must match the filename
|
||||
label: op.exposure # a localisation key, never a display string
|
||||
order: 20 # where it sits in the chain
|
||||
attributes: [tone] # what it is about; one or more, and required
|
||||
|
||||
doc: | # becomes the generated module's documentation
|
||||
Exposure — a linear gain, expressed in stops.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
id: blacks_whites
|
||||
label: op.blacks_whites
|
||||
order: 50
|
||||
attributes: [tone]
|
||||
|
||||
doc: |
|
||||
Blacks and whites — the endpoints, where the image clips.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
id: brilliance
|
||||
label: op.brilliance
|
||||
order: 70
|
||||
attributes: [tone]
|
||||
|
||||
doc: |
|
||||
Brilliance — shadows up and highlights down at once.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
id: colour_mixer
|
||||
order: 100
|
||||
attributes: [colour]
|
||||
rust: ColourMixer
|
||||
|
||||
why_rust: |
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
id: contrast
|
||||
label: op.contrast
|
||||
order: 30
|
||||
attributes: [tone]
|
||||
|
||||
doc: |
|
||||
Contrast — an S-curve about a fixed mid-point.
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
id: exposure
|
||||
label: op.exposure
|
||||
order: 20
|
||||
attributes: [tone]
|
||||
|
||||
doc: |
|
||||
Exposure — a linear gain, expressed in stops.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
id: highlights_shadows
|
||||
label: op.highlights_shadows
|
||||
order: 40
|
||||
attributes: [tone]
|
||||
|
||||
doc: |
|
||||
Highlights and shadows — broad, overlapping recovery at both ends.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
id: saturation
|
||||
label: op.saturation
|
||||
order: 90
|
||||
attributes: [colour]
|
||||
|
||||
doc: |
|
||||
Saturation — every colour's distance from grey, scaled equally.
|
||||
|
||||
@@ -8,6 +8,11 @@
|
||||
# to learn.
|
||||
id: tone_curve
|
||||
order: 60
|
||||
|
||||
# Both, and this is the case the plural exists for: the RGB curve is
|
||||
# tonal and the per-channel curves are chromatic. Filing it under one
|
||||
# would hide it from half the people looking for it.
|
||||
attributes: [tone, colour]
|
||||
rust: ToneCurve
|
||||
|
||||
why_rust: |
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
id: vibrance
|
||||
label: op.vibrance
|
||||
order: 80
|
||||
attributes: [colour]
|
||||
|
||||
doc: |
|
||||
Vibrance — saturation weighted toward the muted colours.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
id: white_balance
|
||||
label: op.white_balance
|
||||
order: 10
|
||||
attributes: [colour]
|
||||
|
||||
doc: |
|
||||
White balance — temperature and tint, relative to as-shot.
|
||||
|
||||
Reference in New Issue
Block a user