Build and test / Desktop (Linux) (push) Successful in 17m20s
Build and test / Layer separation (push) Successful in 33s
🐳 Android image / Build and push (push) Successful in 2s
Build and test / android-image (push) Successful in 2s
Traceability / Requirement traces (push) Failing after 26s
Build and test / Android (aarch64) (push) Failing after 8m59s
The mixer was thirty-six sliders reading "Hue / Sat / Lum" twelve times over with nothing saying which band any row belonged to. The identity was there all along — the descriptor declares param.mixer.orange.sat and BANDS carries orange at 30° — and was discarded on the way out: labels.rs had no mixer entries, so every key fell through to a derived label that yields the bare channel name. A parameter can now say which aspect it adjusts and which subject it adjusts it on, with the subject's hue where the subject is a colour (descriptor::Facet). That is data about what the operation does, not a layout: the mixer genuinely weights pixels around 30°. What to draw from 30°, and in what order to stack the runs, stay in dr-ui (ARCH §4.3a) — develop.rs brings rows sharing an aspect together and marks the first of each, and adjust.slint names the run once and draws a swatch, a track and a readout on one line. Grouped by channel rather than by band because an edit is almost never "everything about orange"; it is the saturation of the greens, made by comparing one channel across neighbouring bands. Twelve band sections put those twelve rows in twelve different places. The swatch is the label, which is what makes twelve rows fit where four did. The band name is not lost: it is the row's accessible label, so the control is not colour-only, and labels.rs is where the mapping is written down — including chartreuse as "Yellow-Green" and spring as "Blue-Green", since nobody hunting foliage scans a list for "Spring". Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
173 lines
6.5 KiB
YAML
173 lines
6.5 KiB
YAML
# The source of truth for the UI's colour and length tokens.
|
||
#
|
||
# `build.rs` reads this file and generates `theme.slint` into OUT_DIR at
|
||
# compile time; nothing here is read at runtime unless the `live-style`
|
||
# feature is on. Edit this file, never the generated one.
|
||
#
|
||
# Leaf values only. A token that binds several values into one concept — a
|
||
# panel heading's colour *and* size *and* weight — is a Slint component, not
|
||
# a row in a YAML file (see widgets.slint).
|
||
#
|
||
# Structure:
|
||
# preamble — prose emitted at the top of the generated file
|
||
# colors: — name -> "#RRGGBB", or `alias:` naming another colour token
|
||
# lengths: — name -> pixels
|
||
# Any token may carry `note:` (a `//` comment above it) or `doc:` (a `///`
|
||
# doc comment, which Slint surfaces to editors).
|
||
#
|
||
# Two entries are dividers rather than tokens, because YAML discards the blank
|
||
# lines between map entries and the generated file's grouping has to survive:
|
||
# `section: <title>` — a headed run, optionally with its own `note:`
|
||
# `break: true` — a bare blank line between related tokens
|
||
|
||
preamble: |
|
||
Near-neutral dark palette, achromatic signalling.
|
||
|
||
Two commitments, both about not lying to the photographer.
|
||
|
||
**Dark ground.** A light UI surrounding an image biases how that image is
|
||
judged — the eye adapts to the brightest thing in view, and a white panel
|
||
makes a correctly-exposed photograph look dark.
|
||
|
||
**Near-neutral greys.** The earlier palette was a warm "darkroom safelight"
|
||
brown (ground #14120F, R twelve points above B). That is worse than it
|
||
sounds: simultaneous contrast pushes perception of the image *away* from the
|
||
surround, so a warm chrome makes a neutral photograph read cool, and the
|
||
photographer corrects toward warm to compensate. Every export drifts yellow.
|
||
It is the same reason a print viewing booth is neutral grey rather than
|
||
whatever colour the room happens to be.
|
||
|
||
These greys carry a 2–3 point blue lift rather than being flatly achromatic.
|
||
Pure R=G=B reads as dead to most eyes; a trace of cool reads as instrument
|
||
rather than absence, and biases far less than warmth because the eye is more
|
||
tolerant of a cool surround. The lift is small enough not to matter
|
||
perceptually and deliberate enough not to be mistaken for drift.
|
||
|
||
**No hue in the chrome.** Active and modified states are signalled by
|
||
brightness alone. An accent sitting beside the image competes with it for
|
||
attention and shifts the perception of nearby colours; a photo editor cannot
|
||
afford either. The one exception is `warn-ink` — a caution is genuinely a
|
||
different kind of thing from an active state, and hue is the fastest way to
|
||
say so.
|
||
|
||
colors:
|
||
ground: "#121314"
|
||
surface: "#1B1C1E"
|
||
surface-raised: "#252629"
|
||
rule: "#323438"
|
||
|
||
_inks: { break: true }
|
||
ink: "#EDEEF0"
|
||
ink-dim: "#9EA1A6"
|
||
ink-faint: "#71747A"
|
||
|
||
hover:
|
||
value: "#2E3034"
|
||
note: |
|
||
Interactive states for surfaces. Named rather than written inline so a
|
||
button, a section header and a list row cannot drift apart: hover lifts
|
||
toward the light, press sinks back past the resting surface so the
|
||
control reads as depressed rather than merely lit.
|
||
pressed: "#17181A"
|
||
|
||
_signalling:
|
||
section: signalling
|
||
note: |
|
||
Achromatic, so the separation has to come from luminance. These are
|
||
spaced further apart than a coloured palette would need: with hue
|
||
unavailable, a two-step brightness difference is invisible, and a
|
||
modified marker that cannot be spotted at a glance is not a marker.
|
||
|
||
active:
|
||
value: "#FFFFFF"
|
||
doc: |
|
||
An active or engaged control: a slider fill, a curve line, a checked
|
||
box. Brighter than `ink` so it reads as lit rather than merely present.
|
||
active-dim:
|
||
value: "#C6C9CE"
|
||
doc: Active, at rest — a filled control that is not under the pointer.
|
||
active-pressed:
|
||
value: "#8E9298"
|
||
doc: Active, pressed. Sinks rather than lifts, matching `pressed`.
|
||
|
||
modified:
|
||
alias: active
|
||
note: |
|
||
"This differs from its default." Deliberately the brightest thing in the
|
||
chrome: it is the one piece of state the photographer scans for, and
|
||
with no hue to carry it, brightness is all there is.
|
||
|
||
selected:
|
||
value: "#383B40"
|
||
doc: |
|
||
A selected grid cell. A lifted neutral rather than a tint — distinct
|
||
from `hover` because a multi-selection must stay legible after the
|
||
pointer has moved on, which is the whole point of selecting several
|
||
before dragging them.
|
||
selected-ring:
|
||
value: "#D5D8DD"
|
||
doc: |
|
||
The ring around a selected cell. Brighter than the fill so selection
|
||
survives against a pale thumbnail, where the fill alone would vanish.
|
||
|
||
warn-ink:
|
||
value: "#C9A05A"
|
||
note: |
|
||
Semantic, and the only hue in the palette. A caution is not an active
|
||
state, and it is worth the one exception to say that instantly. Muted
|
||
rather than saturated so it does not shift perception of a nearby image.
|
||
|
||
lengths:
|
||
_gaps: { break: true }
|
||
gap-sm: 6
|
||
gap: 12
|
||
gap-lg: 20
|
||
|
||
_text: { break: true }
|
||
text-sm: 11
|
||
text: 13
|
||
text-lg: 17
|
||
text-xl: 24
|
||
|
||
radius-sm:
|
||
value: 3
|
||
note: |
|
||
Corner radii. Two steps only: `radius-sm` for things that sit inside
|
||
other things, `radius` for the controls themselves.
|
||
radius: 4
|
||
|
||
touch-target:
|
||
value: 44
|
||
note: "FR-UI-3: minimum 44pt hit target under touch."
|
||
|
||
row-height:
|
||
value: 26
|
||
note: |
|
||
One row of the collections tree, and one level of nesting. Both are
|
||
tokens because a tree's indentation has to stay proportional to its row
|
||
height; hard-coding either makes the hierarchy read wrong when the other
|
||
changes.
|
||
indent: 14
|
||
|
||
control-height:
|
||
value: 28
|
||
note: |
|
||
The drawn height of a button or section header. Deliberately shorter
|
||
than `touch-target` — chrome this tall in every row would crowd the
|
||
photograph — so controls grow their TouchArea past their own bounds to
|
||
meet FR-UI-3 rather than growing their ink.
|
||
control-min-width:
|
||
value: 88
|
||
doc: |
|
||
Floor on button width, so a one-word label is still a comfortable
|
||
target and a row of buttons has an even rhythm.
|
||
|
||
swatch:
|
||
value: 12
|
||
note: |
|
||
The colour square identifying which hue band a row edits. Small on
|
||
purpose: a swatch is data, not chrome — the one sanctioned exception to
|
||
an achromatic palette — and it earns that exception by identifying the
|
||
row without competing with the photograph beside it. Big enough to name
|
||
a hue at a glance, and no bigger.
|