Lexicon / Colour
Colour as one system · 5 named effects, each running below
Every colour on the card is held to one dial. Scroll, and they all turn together, in step, never landing on a combination nobody chose.
also called scroll-driven theme · animated custom properties · palette rotation
The whole palette is one number. @property is what makes it animatable at all — an unregistered custom property has no interpolable type. Every token keeps its lightness and chroma and shares the angle, so nothing can drift out of step.
@property --rot { syntax: '<angle>'; inherits: true }
--accent: oklch(0.637 0.145 calc(40.2deg + var(--rot)));Twelve plates, one angle.
OpenThe same colour change, asked of a few elements or of a great many. Press the switch and watch the counter beside it.
also called custom property invalidation · style recalc scope
Where the angle is declared decides what it costs. On the root, every element on the page re-resolves its colours each frame; on the stage, only the stage does. Scope is the whole difference between a palette that animates for free and one that eats the frame budget.
.stage { --rot: 0deg; animation: turn linear both; animation-timeline: scroll(root) }
/* declared on .stage, not :root — only this subtree re-resolves each frame */-- · 0 consumers
Two ways to get from terra to blue. The left field goes round the outside and is a full colour the whole way; the right one goes straight across and turns to mud halfway.
also called hue path · chroma preservation · colour interpolation
How much colour a screen can hold changes with hue: the space bulges towards violet and pinches near cyan, so it is not a cylinder. That makes the route between two colours a gamut question rather than a matter of taste — and the default route, a straight line through the middle of the space, is the one that passes closest to grey. The strips under each field are the whole journey at once.
/* round the outside */
background: oklch(0.637 0.148 calc(40.2deg + var(--t) * -135.8deg));
/* straight across — what you get by default */
background: color-mix(in srgb, <end> calc(var(--t) * 100%), <start>);along the rimfull colour the whole way
straight acrossgrey in the middle
The words turn themselves into the opposite of whatever passes behind them, so they stay readable over a photograph, over white and over black — and then vanish over one particular grey.
also called mix-blend-mode · invert on crossing · self-inverting overlay
One property, no JavaScript, and the overlay never has to know what is behind it. What it cannot survive is mid-grey, where inverting a value returns very nearly the value you started from. Plan for that band rather than discovering it on the one slide that has it.
mix-blend-mode: difference;Legible on anything
At one point on the way down, the whole panel changes its colours at once rather than easing between them.
also called section theming · discrete palette swap · data-theme
The common form, and the honest one when two palettes are unrelated rather than a rotation apart. Everything rests on the transition: without one it strobes, and much past a second it lags the scroll and reads as a bug.
new IntersectionObserver(fn, { rootMargin: '-45% 0px -45% 0px' })
.flip { transition: background-color .7s var(--settle) }
/* these three palettes are unrelated by design, so they are written out
rather than derived from the house tokens */