Aurora Drift
How-To Tutorial
# Shader Sample — Aurora Drift A fifteen-scene explainer built on a **living colour field** rather than a pre-rendered gradient movie. The field is layers the player already renders — no WebGL, no video asset, no timers and no randomness — so it is deterministic under frame-by-frame capture, costs nothing to fetch, and every colour in it swaps with the palette. ## The field, and what gives it texture Four mechanisms, all typed: | | | | --- | --- | | `fill` | one linear base plus soft elliptical `radial-gradient` fields | | `blend` | the fields COMBINE — `screen` on the dark grounds, `multiply` on cream — so their overlaps make colours that are in none of them | | the conic flow | an oversized `conic-gradient` on one long monotonic rotation, sweeping light across the frame | | `filters.noise` | feTurbulence grain, on the gradient layers whose paint FILLS their box | Two rules worth keeping, because both are invisible until they are wrong: - **A hue change inside a radial gradient reads as a RING. An alpha change reads as a soft edge.** So a field is one hue whose alpha ramps out; colour DRIFT across a shape is a second offset field over the first, never a second stop in the same gradient. - **Grain goes only on a gradient whose paint reaches its box edge.** `filters.noise` mounts its noise `inset: 0` at a flat opacity and does NOT follow the fill's alpha, so on a radial field that fades out inside its box the noise keeps painting the full rectangle and the box edge shows as a hard seam in the texture. Grounds, band bases, the framed outline and the panel card qualify; drifting fields do not, and lose nothing — they are translucent, so the ground's grain reads through them. It also cannot reach past its own layer, which is what keeps it off the photographs and the type. - **Entrances are `fromTo` with both ends stated, never `from`.** `from` takes its destination from the element's live value when the timeline is built, so a rebuild after GSAP has written the start state animates 0 → 0 and the layer sticks. And once both ends are stated, an `immediateRender: false` that was Rule 4 hygiene under `from` becomes harmful: it suppresses the start write, and the target never gets placed. ## Corners and seams 1. **A gradient never has a hard seam.** It bleeds — to the frame edge, or into the ground. There are no clipping containers in this package; where a scene needs a light half and a dark half, the split is a dissolve. 2. **A picture is either the frame or a card.** Full-bleed with no radius when the picture IS the frame; otherwise inset, at the card radius. 3. **One card radius: 28px, at every canvas.** It is stored as a fraction of half the box's shorter side, so it has to be restated per ratio — a card that changes shape and keeps its stored number changes its corner. A plate holding one LINE of type is a stadium (`radius: 100`); a disc is a circle or a bleeding field. Same rule from the other end: the radius follows what the box is, not which scene it sits in. ## Palette Eight roles, eight schemes, three of them dark. Three of the roles are surface/type PAIRS, and they are the reason there are eight rather than six. A single `deep` role once did both the dark surface and the dark type on the light one: in a light scheme both want the same navy, but in a dark scheme they move in OPPOSITE directions, because type on a dark ground has to go light. `violet` split for the same reason — it is a field colour AND the accent type, and a dark scheme needs the type light while the field stays saturated. So: `ground` / `ink` is the light surface and its type, `groundDark` / `inkLight` is the dark surface and its type, `accentInk` is the accent type on `ground`, and `violet`, `azure` and `indigo` are the field. Every gradient stop is one of the eight or an alpha of it, so the scheme switch reaches all of them. The pairs each variant has to hold: `ink`/`ground` and `inkLight`/`groundDark` near 10:1, `inkLight` on `violet` and on `indigo` past 4.2:1 (both carry type), `accentInk`/`ground` past 4.5:1, and `violet`/`azure` on `ground` past 1.6:1 — those two are decoration, not type. ## Type Poppins throughout — Medium for display, Regular for body, tracked in slightly (−2px at its own size) at a 1.08 line-height. Word-by-word reveals on every display line, matching the caption cadence the design came from. ## Scenes | # | scene | what carries it | | --- | --- | --- | | 1 | Opening — portrait beside a living field | a held portrait on a full-bleed field | | 2 | Evidence — panel over footage | a gradient panel over a cutaway sequence | | 3 | Cutaway — footage with a caption pill | the picture, and one line in a pill | | 4 | Statement — full-bleed living field | the field alone; no photograph | | 5 | Compare — two tiles on the field | two labelled cards | | 6 | Equation — tinted field on cream | the washes, and a line-hugging pill | | 7 | Framed — media in a gradient outline | the outline, as a gradient border | | 8 | Triptych — three tiles on cream | three cards in a row | | 9 | Contrast — two discs | two bleeding fields that mix where they meet | | 10 | Bracketed — media with gradient corner marks | corner marks, and one centred claim | | 11 | Portrait — media in a disc | a photo inside a bleeding halo | | 12 | Figure — media band beside a number | one number against a picture card | | 13 | Glow — media with gradient corners | colour bleeding in from four corners | | 14 | Close — cream dissolving into field | the dissolve between the two halves | | 15 | Sign-off — close line over a media strip | the instruction, and a strip | ## Motion Nothing is anchored to a scene's end. The ambient drifts start at 0 and yoyo back to their resting state, and the conic flows are one monotonic sweep — so a scene resized by a longer script keeps its field and simply holds.