AXI-003 · Exploration · shipped 2026-09-18

The blend ledger

The Snick spec has one line about translucency: panes multiply, and the palette is closed under it — every overlap color is computed in advance and approved, so a pane crossing a field never invents a color nobody chose. This study does the computing, proves the arithmetic against the browser with a seam you are invited to find, and rules on all thirty-six products: which are new colors, which are ghosts of colors we already have, and which are nothing at all.

Method

The engine draws two kinds of translucent structure: glass (an overlay-grid block at 80% opacity, in signal, sky or navy) and slivers (the near-miss columns, signal at 85%). Both use mix-blend-mode: multiply, and browsers multiply in gamma-encoded sRGB, per channel. With the pane's opacity folded in, the whole law is one line:

out = base × (1 − a + a × top)   — per channel, 0…1; glass a = .8, sliver a = .85

Read it once more: a pane multiplies whatever is under it by a factor that depends only on the pane. Factors commute. So a stack of panes is order-free, a sliver crossing a glass is just two factors, and the entire closed palette is generated by four numbers. Everything below is derived from the live tokens in the stylesheet at load — change a color in snx.css and the ledger re-rules itself.

Two skins share the engine. On the client site the signal is cyan; here it is purple. The ledger computes both, because a ruling that only covers the studio's joke would be a poor gift upstream. Skin switches everything on this page.

Study A · The assay

A. Thirteen opaque fields, four panes, two slivers. Where a pane lies over a field, a split swatch is laid on top: transparent on the left so the browser's own multiply shows through, solid on the right in the color the ledger computed from the tokens. If the arithmetic is right the seam is invisible. The swatches are placed by reading the resolved layout back, so the test re-runs at every edition; strips thinner than a seam can hold are left honest and unassayed.

Study B · The ledger

approved & namedghost — reads as another token, slightly offnull — the pane leaves no markidentity — the pane becomes its own solidtype: which type may sit on it at body size (WCAG 4.5)
B. Rows are the opaque fields a pane may lie over — the paper tier, the structure tier, and the signal. Columns are the panes the engine actually draws. Each cell shows the product, its hex, the contrast of ink and chalk type against it, and the ruling. Hover a cell for the full-strength multiply and the reason.

Study C · Triples

C. A sliver crossing a glass over a field. The engine draws one sliver under the glass and the other over it (a quirk of ::before and ::after), and it makes no difference: factors commute, so both slivers produce the same third color. These are not ruled on individually — they are the doubles, multiplied. No new type clearance appears among them that the doubles did not already predict: a triple is always darker than either of its parents.
The ruling, in numbers

What the ledger measures before it decides

Every threshold is published so it can be argued with. They were chosen by looking at the products on screen, then written down; the ledger applies them without exception, which is the point of a ledger.

RuleValueWhy
lawout = base × (1 − a + a·top)Multiply with opacity over an opaque backdrop, in sRGB. Verified against the canvas compositor on every product; verified by eye in Study A.
panesglass .8 · sliver .85The engine's actual opacities (snx.css v0.1.3). The ledger rules on what ships, not on full-strength multiply — though the hover shows it.
nullΔE*ab(out, base) < 6The pane leaves no mark on this field. Not harmful, just pointless: a composer who puts sky glass over navy has drawn nothing.
ghostΔE*ab(out, other token) < 6The product reads as an existing color, slightly off — a misregistration, not a design. Rejected on sight because the eye will read it as a mistake.
identitynearest token is the pane itselfOver white or a field close to it the pane simply becomes its own solid. Legal, unremarkable, and not a new color.
faintΔE*ab(out, base) < 8Technically a mark, practically not. Named, so it can be used on purpose; flagged, so it is not used by accident.
typeink ≥ 4.5 · chalk ≥ 4.5 · display ≥ 3WCAG contrast for body and display sizes. Every product is cleared for ink type, chalk type, display only, or no type — and the composer reads that before placing a paragraph on a pane.
ordercommutativeFactors multiply. The ::before sliver under the glass and the ::after sliver over it produce the same color, so the engine's asymmetry costs nothing.
sourcelive tokensRead from the stylesheet at load, not copied into the script. The shipped ledger.css is checked against the live computation and the readout says whether they agree.
The extension

ledger.css — thirty-six tokens, named and ruled

The ruling serialised as custom properties, generated by build.js from the same module the page runs. A score that knows what lies under a pane may use the token as a solid fill instead of a blend: identical in every browser, no backdrop surprises on an open stage, one less compositing group. Panes are cut where the field beneath them changes — which is how a composer would draw them anyway.

loading ledger.css…

Findings