Obsidian: Black Until the Light Moves
The dcyfr.ai identity after phosphor: one stone, six cuts, and a chooser

The dcyfr.ai identity after phosphor: one stone, six cuts, and a chooser

"Obsidian: black until the light moves"
Illustration by FLUX.2 Pro (fal.ai)
Feel free to send us a message with your thoughts, or learn more about us!
dcyfr.ai has a new visual identity called phosphor: warm paper, vermilion accents, serif headlines. This post covers the theme engine behind it, the 37-variable contract both identities satisfy, and where you can flip between them live.
A short, honest changelog: what shipped in the @dcyfr/ai v3.x line, what changed for people building on it, and what comes next — catching the blog up with work the package already produced.
Phosphor lasted a month on this site. It is still in the registry, still passes every gate, and any DCYFR property can pin it. dcyfr.ai itself now ships in obsidian, and this post is about what that identity is, how its colours were measured, and what the theme engine grew to carry it.
Obsidian is volcanic glass. Held flat it is black. Tilt it and colour appears where the light crosses the surface: a mahogany mottle, a green cast, a band of blue, a whole spectrum. The identity takes that literally. One near-black ground and one warm off-white paper are shared by every variant, the surfaces, status colours and lines never change, and colour lives in three places only: the accent ramp, a single dramatic surface the contract calls the field, and a sheen laid over it.
The dark scheme is the stone; the light scheme is the same stone on paper. Both keep the contract’s AA pairs, and the static contrast gate in this repository walks every cut in both schemes on every pull request.
A cut is a colour-only variant of one identity. Obsidian declares six: black, red, blue, green, fire and rainbow. Black is the base, and the base is what a visitor sees until they choose otherwise.
Each cut’s accent ramp and field were measured from photographs of natural stone. The values are pixel statistics from those photographs: which hue bands are present and how much of the surface they cover, how dark the ground is, and how far the coloured band sits from the black. The references are all photographs of stone:
The Commons file pages carry each photographer’s licence. Nothing from the reference set ships with the site: the theme file carries the measured values and nothing else.
Contract v3 gives an identity a cut axis. data-identity on the root element still says which identity the site ships, stamped at build time. data-cut on the same element says which cut, and a cut overlay may re-author only the accent ramp, the field group and the sheen. Everything else falls through to the identity. The base cut is the absence of the attribute, so a page with no stamp and a page stamped black render the same thing.
On dcyfr.ai the visitor chooses. A button in the header shows the current cut and opens the chooser, a labelled radio group naming each cut in words beside a swatch. A pick writes one first-party cookie, dcyfr-cut, holding the cut name and nothing else for a year, restamps the page in place under the engine’s one-frame transition suppression, and stops there. The server reads the cookie on the next request and stamps the cut into the served markup, so there is no flash and no client-side guessing. Delete the cookie and the base comes back. The privacy page describes the cookie in those terms.
Satellites do not get a chooser. A satellite pins one cut at build time, the way every property pins one identity.
Three new variables and one image value carry the drama. --field is the ground of one surface a page may use for emphasis, --field-foreground and --field-accent are the text and the accent on it, and --sheen is a gradient stack (or none, on the black cut) that the engine lays over the field at low opacity. Sheen is never a fill, and three engine utilities are the only place it is drawn. .field paints the surface and shows the sheen at rest. .sheen-hover keeps it invisible until hover or focus. .sheen-scroll widens the layer and drifts it with the element’s own view timeline, a CSS scroll-driven animation with no scroll listener behind it.
Reduced motion removes the animation and keeps the information: the field keeps its static layer, the hover reveal still happens without a transition, and the scroll drift never attaches. Forced colours drop the layer, since it is decoration.
The contract stayed, at 41 variables now: surfaces, brand, status, type, motion, radius, and the field group. The engine stayed, and the cut axis is an addition to it. Slate and phosphor stayed in the registry and satisfy the same contract, so a property that wants the warm paper pins phosphor and gets it, and the design colophon still switches between all three in place. What changed is the identity this one site wears, and the cookie that lets you pick its cut.
The design colophon renders every contract token live, previews any cut without writing the cookie, and shows all six cuts side by side on one page. The registry gallery does the same for every published component. If you read the phosphor post when it went out, the engine it described is the one still running; it learned one more axis.