diff --git a/skills/hyperframes/SKILL.md b/skills/hyperframes/SKILL.md
index f68c52dac..f37141bca 100644
--- a/skills/hyperframes/SKILL.md
+++ b/skills/hyperframes/SKILL.md
@@ -9,32 +9,68 @@ HTML is the source of truth for video. A composition is an HTML file with `data-
## Approach
-### Discovery (exploratory requests only)
+### Brief (exploratory requests only)
-For open-ended requests ("make me a product launch video", "create something for our brand") where the user hasn't committed to a direction, understand intent before picking colors:
+For open-ended requests ("make me a product launch video", "create something for our brand"), gather what's missing from the prompt before building a design system. For specific requests ("add a title card", "fix the timing on scene 3"), skip this.
-- **Audience** — who watches this? Developers? Executives? General consumers?
-- **Platform** — where does it play? Social (15s), website hero, product demo, internal?
-- **Priority** — what matters most? Motion quality? Content accuracy? Brand fidelity? Speed?
-- **Variations** — does the user want options, or a single best shot?
+Extract what you can from the prompt itself — only ask about what's genuinely missing. Ask **one question at a time** and let each answer inform the next. Combine two questions in one message when they're naturally related, but never dump a list.
-For specific requests ("add a title card", "fix the timing on scene 3"), skip discovery.
+**Format each question as a lettered multiple choice** (A, B, C, D) so the user can respond with just a letter. Include 2-4 contextual options plus the option to give a custom answer. Tailor the options to the specific prompt — don't use generic choices.
-For exploratory requests, consider offering 2-3 variations that differ meaningfully — not just color swaps, but different pacing, energy levels, or structural approaches. One safe/expected, one ambitious. Don't mandate this — it's a tool available when appropriate.
+The questions (in rough priority order):
+
+- **Audience** — who watches this? (Developers, executives, consumers — changes type scale, density, easing)
+- **Emotion** — what should the viewer feel? (Maps directly to mood board clustering in the picker. Sharpen this based on the audience answer — "technical precision or breakthrough excitement?" is better than "what mood?")
+- **Brand assets** — do they have a logo, existing colors, fonts, website? (If yes, palettes and type pairings derive from them. If no, skip — full creative freedom.)
+- **Light or dark?** (Eliminates half the palette options. Can often combine with another question.)
+- **Surface** — where does this play? (Social → portrait/punchy, website hero → landscape/looping, presentation → widescreen/breathable, internal → information-dense)
+- **Key takeaway** — what's the one thing the viewer should remember? (Drives focal hierarchy in architecture previews)
+
+Most prompts already answer 2-3 of these — a typical brief is 2-3 questions, not 6. These answers seed the design picker in Step 1 — pass them when generating mood boards, palettes, and architectures.
### Step 1: Design system
-If `design.md` or `DESIGN.md` exists in the project, read it first (check both casings — they're different files on Linux). It's the source of truth for brand colors, fonts, and constraints. Use its exact values — don't invent colors or substitute fonts. Any format works (YAML frontmatter, prose, tables — just extract the values).
+**Always check for DESIGN.html first.** At the start of any composition task, look for `DESIGN.html` in the project root. This is the primary design system format — a self-contained HTML document with rendered sections for palette, typography, surface, motion, background shader, guidelines, and template slide gallery.
+
+**Check in this order:**
+
+1. **`DESIGN.html` exists** → Read it using the guide at [references/design-html.md](references/design-html.md). The guide covers both token extraction AND template extraction (the page has TWO design systems — build from the templates, not the page chrome). If a shader background exists, port it using the GSAP-proxy pattern in the guide. Proceed to Step 2.
+
+2. **No `DESIGN.html`, but `design.md` or `DESIGN.md` exists** → Generate a bespoke DESIGN.html:
+
+ Read [references/design-showcase.md](references/design-showcase.md) for the full generation process. This is NOT a template fill — the agent must craft a page that embodies the brand's visual personality. An HP design.md produces angular chevrons and sharp 4px buttons. A Meta design.md produces pill-shaped elements and photography-first 32px-radius cards. Same sections, completely different visual treatment.
+
+ The generation process:
+ 1. Extract palette, typography, motion, surface tokens from the design.md
+ 2. Place the system on character axes (rounded vs sharp, flat vs elevated, photo-first vs type-first, warm vs clinical)
+ 3. Write each section (cover, palette, type, surface, motion, background, guidelines, templates) styled to the brand's character
+ 4. The cover/hero section must have a signature decorative gesture derived from the brand (not generic)
+ 5. Save as `DESIGN.html` in the project root
+
+ Then offer the picker for fine-tuning: read [references/design-picker.md](references/design-picker.md) to serve the visual picker with the generated DESIGN.html pre-loaded. The user can adjust palette, typography, corners, density, depth, and shader background. The picker loads the DESIGN.html in its iframe preview.
+
+ If the user declines both generation and picker → extract palette, font, and constraint values directly from the markdown. Proceed to Step 2.
+
+3. **User provides a Figma URL** → Read [references/figma-to-design-html.md](references/figma-to-design-html.md) for the lossless extraction process. Pull colors, typography, and component properties directly from the Figma API. Craft a bespoke DESIGN.html using exact Figma values — no approximation. Then offer the picker for fine-tuning.
+
+4. **Neither exists and no Figma URL** → Prompt the user:
-If it names fonts you can't find locally (no `fonts/` directory with `.woff2` files, not a built-in font), warn the user before writing HTML: "design.md specifies [font name] but no font files found. Please add .woff2 files to `fonts/` or I'll fall back to [closest built-in alternative]."
+ > "No design file found. Would you like to:
+ > **A) Browse templates visually** — Open a template picker in your browser. Choose from 34 visual directions, then configure palette, typography, corners, motion, and shader background. Exports a DESIGN.html ready for video composition.
+ > **B) Describe a style** — Tell me the mood, energy, or a style reference (e.g. "dark editorial", "warm minimal", "brutalist"). I'll match it to one of 8 named presets.
+ > **C) Skip design, go fast** — Jump straight to building. I'll ask 2-3 quick questions and pick a palette."
+ - **A) Template picker** → Read [references/design-picker.md](references/design-picker.md) for the full workflow.
+ - **B) Style or mood** → Read [visual-styles.md](./visual-styles.md) for the 8 named presets. Pick the closest match.
+ - **C) Fast path** → Ask: mood, light or dark, any brand colors/fonts? Then pick a palette from [house-style.md](./house-style.md).
-If no `design.md` exists, offer the user a choice:
+**Font resolution:** When a design file names a font, resolve it in this order:
-1. **User named a style or mood?** → Read [visual-styles.md](./visual-styles.md) for the 8 named presets. Pick the closest match.
-2. **Want to browse options visually?** → Run the design picker: read [references/design-picker.md](references/design-picker.md) for the full workflow. This serves a visual picker page. The user configures mood, palette, typography, and motion in the browser, then copies the generated design.md and pastes it back into the conversation.
-3. **Want to skip and go fast?** → Ask: mood, light or dark, any brand colors/fonts? Then pick a palette from [house-style.md](./house-style.md).
+1. Check `fonts/` directory for `.woff2` files matching the family name → use `@font-face` with local files
+2. Check if the font is on Google Fonts (IBM Plex Sans, Inter, etc.) → use `` tag directly
+3. Check the design.md's "Font Substitutes" section → use the first recommended substitute
+4. If none found, warn: "The design specifies [font name] but no font files found. Add .woff2 files to `fonts/` or I'll fall back to [closest built-in alternative]."
-**design.md defines the brand. It does not define video composition rules.** Those come from [references/video-composition.md](references/video-composition.md) and [house-style.md](./house-style.md). Use brand colors at video-appropriate scale — not at web-UI opacity.
+**The design file defines the brand. It does not define video composition rules.** Those come from [references/video-composition.md](references/video-composition.md) and [house-style.md](./house-style.md). Use brand colors at video-appropriate scale — not at web-UI opacity.
### Step 2: Prompt expansion
@@ -476,6 +512,7 @@ Skip on small edits (fixing a color, adjusting one duration). Run on new composi
- **[references/techniques.md](references/techniques.md)** — 11 visual techniques with code patterns: SVG drawing, Canvas 2D, CSS 3D, kinetic type, Lottie, video compositing, typing effect, variable fonts, MotionPath, velocity transitions, audio-reactive. Read when planning techniques per beat.
- **[references/narration.md](references/narration.md)** — Pacing, tone, script structure, number pronunciation, opening line patterns. Read when the composition includes voiceover or TTS.
- **[references/design-picker.md](references/design-picker.md)** — Create a design.md via visual picker. Read when no design.md exists and the user wants to create one.
+- **[references/shader-backgrounds.md](references/shader-backgrounds.md)** — GLSL shader patterns for contextual scene backgrounds. Noise library, domain warping, pattern recipes by context (travel, medical, tech, industrial). Read when building shader backgrounds for compositions or the design picker.
- **[visual-styles.md](visual-styles.md)** — 8 named visual styles with hex palettes, GSAP easing signatures, and shader pairings. Read when user names a style or when generating design.md.
- **[house-style.md](house-style.md)** — Default motion, sizing, and color palettes when no design.md is specified.
- **[patterns.md](patterns.md)** — PiP, title cards, slide show patterns.
diff --git a/skills/hyperframes/house-style.md b/skills/hyperframes/house-style.md
index 892c2ebed..3994c02d2 100644
--- a/skills/hyperframes/house-style.md
+++ b/skills/hyperframes/house-style.md
@@ -32,9 +32,9 @@ If the content genuinely calls for one of these — centered layout for a solemn
## Background Layer
-Every scene needs visual depth — persistent decorative elements that stay visible while content animates in. Without these, scenes feel empty during entrance staggering.
+Decoratives add depth when a scene needs it — during entrance staggering, during holds, or when the content is sparse and the frame feels flat. They're a tool, not a requirement.
-Ideas (mix and match, 2-5 per scene):
+Ideas:
- Radial glows (accent-tinted, low opacity, breathing scale)
- Ghost text (theme words at 3-8% opacity, very large, slow drift)
@@ -42,9 +42,7 @@ Ideas (mix and match, 2-5 per scene):
- Grain/noise overlay, geometric shapes, grid patterns
- Thematic decoratives (orbit rings for space, vinyl grooves for music, grid lines for data)
-All decoratives should have slow ambient GSAP animation — breathing, drift, pulse. Static decoratives feel dead.
-
-**Decorative count vs motion count.** The "2-5 per scene" count refers to decorative _elements_. If a project's `design.md` says "single ambient motion per scene", it means one looping motion applied to these decoratives (a shared breath/drift/pulse) — not one element total. A scene with 4 decoratives sharing one breathing motion is correct; a scene with 1 decorative is under-dressed.
+Use as many or as few as the scene earns. A data-dense scene with 4 decoratives and shared breathing motion is rich. A single word on a black frame with no decoration is powerful. Both are valid — the question is whether the density matches the emotional beat.
## Motion
diff --git a/skills/hyperframes/references/design-html-templates.md b/skills/hyperframes/references/design-html-templates.md
new file mode 100644
index 000000000..68e331461
--- /dev/null
+++ b/skills/hyperframes/references/design-html-templates.md
@@ -0,0 +1,108 @@
+# Design HTML Template Extraction
+
+A design.html with embedded templates contains TWO separate design systems. Mix them up and the output looks nothing like the reference. This guide prevents that.
+
+## The Two Systems
+
+Every design.html with a template gallery has:
+
+| Layer | What it is | Where it lives | Fonts | Use for |
+| ------------------- | -------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ | ----------------------------------------------------- | ------------------------------------------------- |
+| **Page chrome** | The design system document itself — headers, swatches, specimen rows, rules grid | `
+```
+
+```html
+
+```
+
+```html
+
+
+
+
+
+
+
{{headline}}
+
{{body}}
+
+
+
+
+
cover01 / N
+
+
+
+```
+
+**Placeholders only.** Use `{{label}}`, `{{headline}}`, `{{body}}`, `{{number}}`, `{{text}}` — never real example copy. Real copy adds 5–10kb of bloat per template and confuses the downstream agent.
+
+The runtime script that injects + scales the gallery should be the last thing in `
`:
+
+```html
+
+```
+
+The `.tmpl-thumb` has `aspect-ratio: 16/9` and `overflow: hidden`. The `.scale-wrap` is exactly `1920px × 1080px` with `transform-origin: top left`. The script reads each thumb's width and applies the matching scale.
+
+If the system has a shader background (Three.js + GLSL), keep the GLSL in collapsible `` + `
` / `
` blocks. The runtime reads them at startup — the GLSL is documentation AND code.
+
+---
+
+## 9. Voice — write like the system speaks
+
+Most failed showcases are technically correct but mute. The voice of every visible string — section numbers, manifesto, do/don't bullets, endcap — must sound like the system's character.
+
+| Character | Section numbers | Manifesto tone | Endcap |
+| --------------- | ------------------------ | ----------------------------------------------------------- | -------------------------------- |
+| Loud editorial | `01 — palette` | "type is _image_. accent is _environment_." | "end." (huge, lowercase, accent) |
+| Scholarly | `i — Palette` | "the page is _record_. type is _voice_." | "_fin._" (italic, on paper) |
+| Brutalist | `▶ 01 / PALETTE` | "borders are _structural_. shadows are _weight_." | "END OF FILE." (caps, accent) |
+| Playful | `~ palette ~` | "_yes please._ / _no thank you._" (with handwritten asides) | "thanks everyone!" (handwritten) |
+| Industrial B2B | `01 — Palette` | "the page is a _document_. type is _precise_." | "Thank you." (small, restrained) |
+| Win95 retro | `Palette.exe — 01 of 06` | "Surfaces are _3D_. Chrome is _structural_." | "Shut Down." (in a window) |
+| 8-bit arcade | `01 // PALETTE` | "type is _display_. color is _signal_." | "GAME OVER." (blinking) |
+| Activist poster | `★ 01 / PALETTE` | "the page is a _protest_. type is _volume_." | "JOIN US." (caps, accent) |
+
+The mono labels everywhere should also speak in voice. A scholarly system writes `// folio · pp. 04 / 16`. A brutalist system writes `▶ CARD · EXAMPLE`. An arcade writes `▸ PRESS START`. The mono is the system's footnote voice — let it carry character too.
+
+---
+
+## 10. Concrete failure modes and fixes
+
+| Failure | Fix |
+| ------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| Neutral grey-on-white page chrome | Re-skin every section in the system's palette. The body background isn't neutral — it's `--secondary` or `--primary`. |
+| Cover headline at 48–64px | Push to `clamp(80px, 15vw, 280px)` minimum. The cover dominates or fails. |
+| Accent used as a 12% background wash everywhere | Reserve accent for solid hits: one swatch, one section-head highlight, one cover-foot cell, one stat. Power comes from repetition + restraint, not opacity. |
+| Filled example copy inside slide gallery | Replace with `{{placeholders}}`. |
+| Same section-head treatment six times in a row | Vary: cover huge, manifesto on a slab, palette normal, type paired with a label. Pulse the rhythm. |
+| More than 4 palette tokens at the top | Compress to 4. Move extras into `.ds-slide-frame` as `--c-pink`, `--c-yellow` costume vars. |
+| Reveal-on-scroll animations bolted on | Cut them. They bloat the file. |
+| Identical 12-section showcase regardless of system | Match section count to system density. Loud poster system needs 5 sections; scholarly system uses all 9. |
+| Display font is Inter or Helvetica or system-ui | Pick a memorable display face from §3. |
+| All cards drop-shadowed identically | Brutalist: offset solid. Quiet: none. Modern B2B: 4% opacity. Don't mix philosophies. |
+| Manifesto reads like marketing | Rewrite in the system's voice. Three clauses, two italicized emphasis words, fits in 22–30ch. |
+| Endcap is a meta block with the same chrome as the rest | Make it a single huge word at maximum scale, on accent or inverted canvas. Mirror the cover. |
+
+---
+
+## 11. Process (the actual sequence)
+
+1. **Read the source completely.** Don't skim. Note palette, fonts, mood words, slide variants.
+2. **Write the one-sentence character.** If hazy, re-read.
+3. **Place on the six axes.** Loud/quiet, hard/soft, modern/retro, sans/serif, single/multi, editorial/industrial.
+4. **Pick three fonts.** Display by character (§3), body to pair, mono usually JetBrains.
+5. **Write the `:root` block.** Four palette tokens, three fonts, derived `--ink-dim`/`--hairline`, padding clamps.
+6. **Write the `template-css` block.** All slide variants with internal alias vars (`--c-bg`, `--c-fg`, `--c-accent`) so slides re-skin cleanly.
+7. **Build the outer chrome — embodying the system at every step.** Sticky rail → cover → manifesto → palette → type → surface → motion → guidelines → templates → endcap.
+8. **Re-read the cover.** If you only saw the cover, would you keep going? If no, the cover is too quiet.
+9. **Re-read the manifesto.** Could this sentence work as a slide in a real deck made with this system? If no, the voice is wrong.
+10. **Mental squint test.** Imagine this showcase next to a generic startup landing page. Are they unmistakably different objects? If they look the same, the chrome isn't committing.
+
+---
+
+## 12. The three tests that catch failures
+
+Before delivering, apply these three:
+
+1. **Cover test.** Could a stranger glance at the cover and describe the system in one sentence? If they'd only see "design system," your cover is mute.
+2. **Voice test.** Read the manifesto out loud. Does it sound like a sentence the system itself would speak? Or does it sound like generic design-system copy?
+3. **Squint test.** Squint at the page so type blurs. The shapes and colors alone should communicate the system's character — loud color blocks, quiet hairlines, soft tilted cards, hard grid lines. If squinting reveals a generic page structure, the chrome isn't committing to the system.
+
+A showcase that passes all three feels like a portfolio piece. A showcase that fails any of them feels like a spec sheet.
+
+---
+
+## 13. Mining the source for slide templates — the BMW M test
+
+The default 7-template set (cover, chapter, statement, stats, quote, list, end) is a _floor_. A great showcase mines the source document for system-specific components and turns each one into its own slide variant. If the source mentions a `spec-cell`, the slide gallery has a `slide--spec` template. If it mentions a `motorsport-photo-card`, the gallery has a `slide--photo-band` template. **One signature component in the source = one slide variant in the gallery.**
+
+Common system-specific components that must become slide variants:
+
+| Source component pattern | Slide variant | Why |
+| --------------------------------------------------- | ------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------- |
+| "Photo band" / "hero photo" / "full-bleed image" | `slide--photo-band` | A 16:9 placeholder block + overlay caption. Full-bleed inside the 1920×1080 canvas. |
+| "Spec cell" / "spec table" / numbered metrics grid | `slide--spec` | 3 or 4-up grid of large numbers (`{{value}}` at 96px+) with mono labels below |
+| "Model card" / "product card" / 3-up image cards | `slide--lineup` | Three columns of photo placeholder + name + caption + accent link |
+| "Magazine grid" / "article cards" / editorial cards | `slide--magazine` | Photo + category tag + title + excerpt, 2- or 3-up |
+| "Configurator" / "comparison" / option pickers | `slide--compare` | Two-column with swatches/options on left, summary on right |
+| "Motorsport / racing / hero feature" | `slide--feature` | Large photo placeholder with single overlay headline |
+| "Ledger" / "spec table rows" / 2-column data | `slide--ledger` | Hairline-divided rows with key/value pairs |
+| "CTA band" / pre-footer photo CTA | `slide--cta` | Photo placeholder + centered headline + outlined button |
+| Tricolor stripe / signature divider | Used **inside** other slides, not its own variant — a structural marker at slide top |
+
+For the BMW M source: `cover`, `statement`, `spec`, `stat`, `quote`, `ledger`, `split`, `end` is good — but it should also include `photo-band` (full-bleed car image), `lineup` (3-up model cards), and `motorsport-feature` (full-bleed photo with overlay caption). Eight slides is the floor for a system this rich; ten to twelve is the target.
+
+### Photography-led systems get photo placeholders
+
+When the source says "photography is the brand voice" / "full-bleed automotive photography fills entire bands" / "cars are the visual subject," **every slide except the pure-statement slide gets a photo placeholder zone.** Render the placeholder as a styled empty block:
+
+```css
+.photo-placeholder {
+ width: 100%;
+ aspect-ratio: 16/9;
+ background: linear-gradient(135deg, var(--c-surface-elevated), var(--c-surface-card));
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ position: relative;
+}
+.photo-placeholder::before {
+ content: "// PHOTOGRAPHY";
+ font-family: var(--c-f-mono);
+ font-size: 14px;
+ letter-spacing: 0.18em;
+ color: var(--c-dim);
+ opacity: 0.5;
+}
+.photo-placeholder::after {
+ content: "";
+ position: absolute;
+ inset: 24px;
+ border: 1px solid var(--c-dim);
+ opacity: 0.3;
+}
+```
+
+This signals to the downstream agent: _replace this block with a real photo when filling slides._ Without it, the gallery reads as content-light and the system's photographic voice is invisible.
+
+### Placeholder content must match the system's domain
+
+Generic `+42%` is wrong for an automotive system. Mine the source for what the system actually talks about and use that as the placeholder text. For BMW M:
+
+| Slide variant | Domain-appropriate `{{placeholder}}` |
+| ------------- | ------------------------------------------------------- |
+| Stat | `{{number}}` = `523HP` / `3.2s` / `305KM/H` / `1,470KG` |
+| Spec cell | label = `0–100 KM/H`, value = `3.2s` |
+| Ledger | rows like `ENGINE → 4.4L V8 TWINPOWER` |
+| Quote | `"M IS NOT A LETTER. IT'S A LANGUAGE."` |
+| Cover | `BMW M.` / `THE ULTIMATE DRIVING MACHINE.` |
+| Photo caption | `// M4 CSL · NÜRBURGRING · 2024` |
+
+For Vellum (scholarly journal): `{{number}}` becomes `42 folios` not `42%`. For Studio (design agency): `{{number}}` becomes `2003` (founded year) or `12 awards`. For 8-Bit Orbit (arcade): `{{number}}` becomes `999,999` or `LEVEL 7`.
+
+The skill should explicitly read the source's example copy + glossary and reuse those phrases as placeholder text in the slide gallery. Generic numbers signal that the agent didn't actually read the source.
+
+---
+
+## 14. Surface ladder — 4 tokens is the contract, but the system needs more
+
+The four sacred palette tokens (paper / canvas / chrome / accent) are the contract. But many systems — especially industrial, automotive, luxury, financial — have a _surface ladder_ of 3–5 dark/light surfaces that step up from canvas. The skill should extract these from the source and put them in `template-css` under `--c-surface-*` aliases:
+
+```css
+.ds-slide-frame {
+ --c-bg: var(--secondary); /* canvas — true black or true white */
+ --c-surface-soft: #0d0d0d; /* one notch above canvas */
+ --c-surface-card: #1a1a1a; /* card surface */
+ --c-surface-elevated: #262626; /* one more notch */
+ --c-carbon: #2b2b2b; /* domain-specific (BMW: carbon-fiber) */
+ --c-hairline: #3c3c3c; /* divider tone */
+ --c-fg: var(--primary);
+ --c-fg-2: #bbbbbb; /* body text */
+ --c-fg-3: #7e7e7e; /* muted, captions */
+ --c-accent: var(--accent);
+}
+```
+
+The four `--primary/--secondary/--tertiary/--accent` at the `:root` level stay sacred for the downstream agent's re-skinning. The surface ladder lives inside `.ds-slide-frame` as costume — the agent reading template CSS gets the full vocabulary, but a simple re-theming only needs to touch the four root tokens.
+
+**When to extract a surface ladder:** any time the source mentions more than two dark or two light surface colors (e.g., `canvas` + `surface-soft` + `surface-card` + `surface-elevated`). Industrial / luxury / automotive systems almost always have this. Editorial / scholarly systems often don't.
+
+### Body text ladder
+
+Same principle for type colors. The source likely names `ink` + `body` + `body-strong` + `muted`. Map these to `--c-fg` / `--c-fg-2` / `--c-fg-3` inside the slide frame. Use them in slide CSS:
+
+- `.headline` uses `--c-fg` (pure white/black)
+- `.lead` / body uses `--c-fg-2` (slightly muted)
+- `.caption` / metadata uses `--c-fg-3` (very muted)
+
+This is what makes slides feel hierarchically considered rather than flat.
+
+---
+
+## 15. Signature elements — find the one decorative thing
+
+Every system has one decorative element that isn't type or palette. The skill must hunt for it explicitly:
+
+- **Broadside**: nothing decorative — type IS the decoration
+- **BlockFrame**: chunky offset shadows
+- **Vellum**: drop caps + `§` marginalia glyphs
+- **Daisy Days**: hand-drawn daisy SVGs scattered as decoration
+- **8-Bit Orbit**: CRT scanlines + pixel glow
+- **Retro Windows**: bevels + title bars
+- **Sakura Chroma**: diagonal ribbon stripes
+- **Pin & Paper**: tilted safety-pin SVGs
+- **Scatterbrain**: sticky-note tilt + offset shadow
+- **BMW M**: the M tricolor stripe (`#0066b1 → #1c69d4 → #e22718`)
+
+The signature element appears in 3 places in the showcase, at minimum:
+
+1. Inside the brand mark on the nav rail (small)
+2. As a divider between major sections — replacing or accompanying the hairline `border-top` on `.section-head`
+3. As a structural marker inside relevant slide templates (e.g., a 4px stripe at the top of the cover slide, a hairline accent rule on chapter slides)
+
+For BMW M specifically: the M tricolor stripe must appear:
+
+- Below the brand mark in the nav rail
+- As a 4px-tall divider between the cover and the manifesto, and between the manifesto and palette
+- At the top of every slide in the template gallery (`.m-stripe-slide`)
+
+Without the signature element, the showcase looks like a generic dark system. With it consistently placed, the showcase reads as unmistakably BMW M.
+
+### How to encode signature elements
+
+Inline as a tiny reusable HTML pattern + CSS class. The BMW stripe is six lines of CSS and one `` element that can be dropped anywhere:
+
+```css
+.m-stripe {
+ height: 4px;
+ background: linear-gradient(
+ 90deg,
+ var(--m-blue-light) 0% 33%,
+ var(--m-blue-dark) 33% 66%,
+ var(--m-red) 66% 100%
+ );
+}
+```
+
+Then place it three times in the page. Cheap to add, identity-defining.
+
+---
+
+## 16. The BMW M case — what was missing and how to fix
+
+Looking at a typical first-pass BMW M showcase:
+
+- ✅ Black canvas, white type, M red accent — correct
+- ✅ Saira Condensed for display, Inter Light for body — correct
+- ✅ M tricolor stripe present — correct
+- ✅ Zero radius, hairline borders — correct
+- ❌ Slide gallery uses generic stat (`+42%`) instead of automotive (`523HP`, `3.2s`)
+- ❌ No `slide--photo-band` template even though "photography is the brand voice"
+- ❌ No `slide--lineup` for the 3-up model card grid
+- ❌ Surface ladder collapsed to 4 tokens; `surface-soft` / `surface-card` / `surface-elevated` missing from `template-css`
+- ❌ Body color ladder collapsed; everything uses `--c-fg`, no `--c-fg-2` / `--c-fg-3`
+- ❌ Heritage BMW blue (`#1c69d4`) missing — should be in `--c-bmw-blue` inside `.ds-slide-frame`
+- ❌ Photo placeholders missing on cover, spec, split, and (added) photo-band templates
+- ❌ Placeholder copy in templates is generic instead of automotive
+
+A great BMW M showcase has all six of those failures fixed. The skill should drive the agent to actively look for each.
+
+---
+
+## 17. The four-test gauntlet — run before delivering
+
+Before declaring a showcase done, run these four tests in order:
+
+1. **Cover test** (§12.1) — can a stranger glance at the cover and describe the system in one sentence?
+2. **Voice test** (§12.2) — does the manifesto sound like the system speaks, or like generic design-system copy?
+3. **Squint test** (§12.3) — does the page shape alone communicate the system's character?
+4. **Mine test** (§13) — has every signature component from the source become a slide variant? Has every placeholder been replaced with domain-appropriate copy? Has the signature element been placed at least three times?
+
+A showcase that passes 4/4 is portfolio-worthy. 3/4 is good. 2/4 or fewer is a spec sheet.
diff --git a/skills/hyperframes/references/figma-to-design-html.md b/skills/hyperframes/references/figma-to-design-html.md
new file mode 100644
index 000000000..a741ad3d7
--- /dev/null
+++ b/skills/hyperframes/references/figma-to-design-html.md
@@ -0,0 +1,272 @@
+# Figma to DESIGN.html
+
+Extract a design system from a Figma file and generate a bespoke DESIGN.html. This is the lossless path — exact hex values, font weights, border radii, padding, and shadow definitions come directly from the Figma API, not approximated from screenshots.
+
+## Prerequisites
+
+- Figma MCP tools available (`get_design_context`, `search_design_system`), OR
+- Figma REST API access via personal access token + `curl`
+
+## When to use
+
+- User provides a Figma URL (`figma.com/design/:fileKey/...`)
+- User says "use this Figma file" or "extract from Figma"
+- User has a Figma design system file and wants a DESIGN.html for video composition
+
+## Extraction process
+
+### Step 1: Get the file structure
+
+**Via MCP:**
+
+```
+get_design_context(fileKey, nodeId="0:1", excludeScreenshot=true)
+```
+
+**Via REST API (if MCP rate-limited):**
+
+```bash
+curl -s -H "X-Figma-Token: $TOKEN" \
+ "https://api.figma.com/v1/files/$FILE_KEY?depth=1"
+```
+
+This returns the page list. Identify the relevant pages by name:
+
+| Look for | Contains |
+| ------------------------------------ | ------------------------------------------ |
+| "Colours", "Colors", "Palette" | Color swatches with hex values |
+| "Typography", "Type", "Fonts" | Font specimens with family/weight/size |
+| "Buttons", "Components" | Button components with radius/padding/fill |
+| "Brand Guidelines", "Brand Overview" | Complete brand summary |
+| "Grids", "Shadows", "Elevation" | Spacing system and shadow definitions |
+| "Logo", "Brand Mark" | Logo treatment |
+| "Icons", "Iconography" | Icon style |
+
+### Step 2: Extract colors
+
+Fetch the Colors page at depth 6-8:
+
+```bash
+curl -s -H "X-Figma-Token: $TOKEN" \
+ "https://api.figma.com/v1/files/$FILE_KEY/nodes?ids=$COLORS_PAGE_ID&depth=8"
+```
+
+Walk the node tree. For each node with `type: "RECTANGLE"` or `"ELLIPSE"` that has solid fills, extract:
+
+- The `color` RGBA values → convert to hex: `#${Math.round(r*255).toString(16)}...`
+- The parent/ancestor `name` for the color role (e.g., "Primary", "Green Grass", "Info Blue")
+
+Group colors by their section headings (found in adjacent TEXT nodes). Map to the 4-role model:
+
+| Figma section | → Picker role |
+| ------------------------------ | ------------- |
+| Primary brand color / main CTA | `--accent` |
+| Background / canvas | `--secondary` |
+| Body text / ink / dark neutral | `--primary` |
+| Muted / secondary text / gray | `--tertiary` |
+
+### Step 3: Extract typography
+
+Fetch the Typography page at depth 6:
+
+```bash
+curl -s -H "X-Figma-Token: $TOKEN" \
+ "https://api.figma.com/v1/files/$FILE_KEY/nodes?ids=$TYPE_PAGE_ID&depth=6"
+```
+
+For each TEXT node, extract from the `style` object:
+
+- `fontFamily` — the exact font name
+- `fontWeight` — numeric weight (400, 500, 600, 700, 800, 900)
+- `fontSize` — in px
+- `lineHeightPx` — line height in px (compute ratio: `lineHeightPx / fontSize`)
+- `letterSpacing` — in px (convert to em: `letterSpacing / fontSize`)
+
+Build the hierarchy table from the token names (found in adjacent TEXT nodes like "Title/XXL", "Text/M", "Tag/S").
+
+**Font resolution:** Check if the extracted fonts are on Google Fonts. If yes, use directly. If proprietary, check `fonts/` directory for `.woff2` files, then fall back to the design.md's substitute recommendations.
+
+### Step 4: Extract surface properties
+
+Fetch the Buttons/Components page at depth 6:
+
+```bash
+curl -s -H "X-Figma-Token: $TOKEN" \
+ "https://api.figma.com/v1/files/$FILE_KEY/nodes?ids=$BUTTONS_PAGE_ID&depth=6"
+```
+
+For each COMPONENT or INSTANCE node, extract:
+
+- `cornerRadius` — border-radius in px
+- `paddingTop/Right/Bottom/Left` — padding values
+- `itemSpacing` — gap between children
+- `strokeWeight` — border width
+- `strokes[].color` — border color
+- `fills[].color` — background color
+- `effects[]` — shadow definitions (type, color, offset, radius, spread)
+
+Build the radius scale from unique `cornerRadius` values across all components.
+Build the spacing scale from unique padding/gap values.
+Identify the shadow tier(s) — often 0 (flat), 1 (subtle), or 2 (elevated).
+
+### Step 5: Craft the DESIGN.html
+
+With the extracted tokens, follow [design-showcase.md](design-showcase.md):
+
+1. Write the one-sentence character description
+2. Place on the 6 character axes
+3. Map colors to the 4-token model (`--primary`, `--secondary`, `--tertiary`, `--accent`)
+4. Set the extracted fonts (display + body from the Figma type page)
+5. Set surface properties (radius scale, padding, gap, shadow from components)
+6. Build each section styled to the brand's character — using the EXACT values from Figma
+
+**Critical:** Use the extracted values verbatim. Don't round `cornerRadius: 12.0` to `12px` and then decide "that's close to 16px." The Figma API gives exact values — use them.
+
+### Step 6: Export components as SVG
+
+The Figma REST API exports any node as a lossless SVG:
+
+```bash
+curl -s -H "X-Figma-Token: $TOKEN" \
+ "https://api.figma.com/v1/images/$FILE_KEY?ids=$NODE_ID1,$NODE_ID2&format=svg"
+```
+
+Returns `{ "images": { "node:id": "https://...s3.amazonaws.com/..." } }`. Download each URL — the SVG contains exact shapes, colors, text-as-paths, strokes. Truly lossless vector exports.
+
+**What to export:**
+
+- Logo/brand mark — the most important asset. Always export as SVG.
+- Illustrations — character art, decorative graphics, scene illustrations. These define the brand's visual personality in video frames. Export as SVG when vector; note dimensions for raster.
+- Icons — line icons, filled icons, emoji sets. Export as SVG for inline use.
+- Graphics & shapes — decorative elements, patterns, dividers, ornaments. Export as SVG.
+- Tags/badges/pills — visual label treatments. Export as SVG.
+
+**Prioritize visual assets over UI components.** A brand's illustrations, icons, and decorative graphics appear directly in video frames. UI components (buttons, inputs, forms) inform the CSS vocabulary but don't appear as-is in video — there's nothing to click.
+
+**Always prefer SVG format.** SVG exports from Figma contain exact shapes, colors, and strokes as vector paths. They can be:
+
+- Inlined directly in composition HTML
+- Scaled to any size without quality loss
+- Color-modified via CSS (fill, stroke attributes)
+- Animated via GSAP (path morphing, drawing, transforms)
+
+**SVG color tokenization:** Figma exports SVGs with hardcoded hex fills (`fill="#88E655"`). For the picker's palette controls to affect SVGs in slides, replace hardcoded colors with `currentColor` and set the color via CSS vars on the parent container:
+
+```html
+
+
+
+
+
+
+
+```
+
+For multi-color SVGs, use CSS class selectors on SVG elements:
+
+```css
+.brand-fill {
+ fill: var(--tp-accent);
+}
+.ink-fill {
+ fill: var(--tp-primary);
+}
+.ink-stroke {
+ stroke: var(--tp-primary);
+}
+```
+
+For raster-only assets (photographs, complex textures), export as PNG at 2x and note in the DESIGN.html that the asset requires a file reference rather than inline SVG.
+
+### Step 7: Build slides as component references
+
+The slides in `summary.html` are **component references for the composition agent**. Each slide shows actual Figma components at 1920×1080 scale. The agent copies the slide's HTML/SVG structure and swaps content — no guessing.
+
+**Inline the exported SVGs** directly in the slide HTML. The agent reads the SVG source to extract exact CSS values or uses the SVG as-is.
+
+| Slide | Shows | Source |
+| ----- | --------------------------------------------------------------- | ------------------------------------------------------- |
+| 1 | Hero frame using the brand's illustrations + headline treatment | Inline SVG illustrations from Step 6, fonts from Step 3 |
+| 2 | Feature/product frame with inline SVG graphics as hero imagery | SVG graphics/shapes from Step 6 |
+| 3 | Data/stats frame with numbers in the brand's display weight | Fonts + colors from extraction |
+| 4 | Split layout with inline SVG icons + body content | SVG icons from Step 6, layout from Step 4 |
+| 5 | Quote/testimonial frame | Fonts from Step 3 |
+| 6 | Dark closing frame with logo SVG | Logo SVG from Step 6 |
+
+**The slides are VIDEO FRAMES, not component catalogues.** There are no buttons in video — nothing to click. The Figma's visual assets (illustrations, icons, graphics, logo) appear directly in the slides as inline SVGs. The CSS vocabulary (radius, padding, stroke, fill) styles the frame elements. The agent sees a complete video frame and reproduces its structure.
+
+**Asset priority for slides:**
+
+1. Illustrations and character art — these ARE the brand in video
+2. Icons and graphic shapes — decorative elements and data visualization
+3. Logo — appears in hero and closing frames
+4. Color treatment — the palette applied to containers and backgrounds
+5. Typography — headline scale and weight at video size
+
+**Via MCP (if available):** Call `get_design_context` on individual component nodes for full HTML/CSS. Adapt to vanilla HTML.
+
+**Via REST API:** Export as SVG for lossless vector components. Use node properties for CSS values.
+
+## REST API reference
+
+### File structure
+
+```
+GET /v1/files/:key?depth=1
+→ { document: { children: [{ id, name, type:"CANVAS" }] } }
+```
+
+### Node details
+
+```
+GET /v1/files/:key/nodes?ids=:id1,:id2&depth=N
+→ { nodes: { ":id1": { document: { ...node tree... } } } }
+```
+
+### Key node properties for extraction
+
+| Property | What it gives you |
+| ------------------------------ | ------------------------------------------------------- |
+| `fills[].color.{r,g,b,a}` | Background color (0-1 floats → multiply by 255 for hex) |
+| `strokes[].color` | Border color |
+| `strokeWeight` | Border width |
+| `cornerRadius` | Border-radius |
+| `paddingTop/Right/Bottom/Left` | CSS padding |
+| `itemSpacing` | CSS gap |
+| `effects[].type` | `DROP_SHADOW`, `INNER_SHADOW`, `BACKGROUND_BLUR` |
+| `effects[].color` | Shadow color |
+| `effects[].offset.{x,y}` | Shadow offset |
+| `effects[].radius` | Shadow blur |
+| `effects[].spread` | Shadow spread |
+| `style.fontFamily` | Font family name |
+| `style.fontWeight` | Font weight (numeric) |
+| `style.fontSize` | Font size in px |
+| `style.lineHeightPx` | Line height in px |
+| `style.letterSpacing` | Letter spacing in px |
+| `characters` | Text content |
+
+### Authentication
+
+```bash
+curl -H "X-Figma-Token: $PERSONAL_ACCESS_TOKEN" "https://api.figma.com/v1/..."
+```
+
+Generate a personal access token at: figma.com → Settings → Personal access tokens
+
+## Integration with HyperFrames skill
+
+This guide runs during Step 1 (Design system) when the user provides a Figma URL:
+
+1. Extract file structure → identify color/type/component pages
+2. Pull each page via REST API or MCP
+3. Extract tokens (colors, fonts, radii, padding, shadows)
+4. Craft DESIGN.html via [design-showcase.md](design-showcase.md) using exact Figma values
+5. Craft `summary.html` slides using Figma component CSS
+6. Offer the picker for fine-tuning
+7. Continue to Step 2 (prompt expansion)
diff --git a/skills/hyperframes/references/prompt-expansion.md b/skills/hyperframes/references/prompt-expansion.md
index ab504eee1..e177a3fc5 100644
--- a/skills/hyperframes/references/prompt-expansion.md
+++ b/skills/hyperframes/references/prompt-expansion.md
@@ -21,9 +21,9 @@ If `design.md` doesn't exist yet, run Step 1 (Design system) first. Expansion wi
Even a detailed 7-scene brief lacks things only the expansion adds:
-- **Atmosphere layers per scene** (required 2–5 from house-style: radial glows, ghost type, hairline rules, grain, thematic decoratives) — the user's prompt almost never lists these; expansion adds them.
-- **Secondary motion for every decorative** — breath, drift, pulse, orbit. A decorative without ambient motion feels dead.
-- **Micro-details that make a scene feel real** — registration marks, tick indicators, monospace coord labels, typographic accents, code snippets in the background, grid patterns. Things the user didn't think to request.
+- **Atmosphere where the scene earns it** — a radial glow, ghost text, or grain texture can add depth. But a scene built around one powerful element doesn't need decoration. Add atmosphere to serve the mood, not to fill emptiness.
+- **Motion that serves pacing** — ambient motion keeps scenes alive during the breathe phase. But stillness is also a tool. Not every element needs to move.
+- **Micro-details sparingly** — registration marks, monospace labels, structural rules. These earn their place in data-dense or technical scenes. In a contemplative scene, they're clutter.
- **Transition choreography at the object level** — not "crossfade" but "X expands outward and becomes Y". Specific duration, ease, and morph source/target.
- **Pacing beats within each scene** — where tension builds, where a hold lets the viewer breathe, where the accent word lands.
- **Exact hex values, typography parameters, ease choices** from design.md — no vagueness left for the scene subagent to guess.
@@ -47,7 +47,7 @@ Expand into a full production prompt with these sections:
4. **Per-scene beats** — for each scene, use the beat-direction format:
- **Concept** — the big idea in 2-3 sentences. What visual WORLD? What metaphor? What should the viewer FEEL?
- **Mood direction** — cultural/design references, not hex codes. ("Bauhaus color studies", "cinematic title sequence", "editorial calm")
- - **Depth layers** — BG (2-5 decoratives with ambient motion), MG (content), FG (accents, structural elements, micro-details). 8-10 total elements per scene per video-composition.md.
+ - **Depth layers** — BG (atmosphere), MG (content), FG (accents). Density matches the beat — a SLAM might have one element; a proof scene might have a data grid. Don't pad sparse scenes with decoratives just to hit a count.
- **Animation choreography** — specific verbs per element. High: SLAMS, CRASHES. Medium: CASCADE, SLIDES. Low: floats, types on, counts up. Every element gets a verb. If you can't name the verb, the element is not yet designed.
- **Transition out** — shader or CSS, with specific type and parameters. Not "crossfade" but "blur crossfade, 0.4s, power2.inOut."
diff --git a/skills/hyperframes/references/shader-backgrounds.md b/skills/hyperframes/references/shader-backgrounds.md
new file mode 100644
index 000000000..bb861b450
--- /dev/null
+++ b/skills/hyperframes/references/shader-backgrounds.md
@@ -0,0 +1,173 @@
+# Shader Backgrounds
+
+WebGL fragment shaders as living, breathing scene backgrounds. Each composition can have a contextual shader that renders behind the content.
+
+## Noise Library
+
+Include this in every shader. It provides gradient noise (no grid artifacts), FBM, and domain warping.
+
+```glsl
+precision highp float;
+uniform float u_time;
+uniform vec2 u_res;
+
+vec2 h2(vec2 p) {
+ p = vec2(dot(p, vec2(127.1, 311.7)), dot(p, vec2(269.5, 183.3)));
+ return -1.0 + 2.0 * fract(sin(p) * 43758.5453);
+}
+
+float gn(vec2 p) {
+ vec2 i = floor(p), f = fract(p);
+ vec2 u = f*f*f*(f*(f*6.0-15.0)+10.0); // quintic smoothstep
+ return mix(
+ mix(dot(h2(i), f), dot(h2(i+vec2(1,0)), f-vec2(1,0)), u.x),
+ mix(dot(h2(i+vec2(0,1)), f-vec2(0,1)), dot(h2(i+vec2(1,1)), f-vec2(1,1)), u.x),
+ u.y
+ );
+}
+
+// FBM with rotated octaves — prevents directional banding
+float fbm(vec2 p) {
+ float v = 0.0, a = 0.5;
+ mat2 r = mat2(0.8, 0.6, -0.6, 0.8);
+ for (int i = 0; i < 6; i++) { v += a * gn(p); p = r * p * 2.0 + vec2(1.7, 9.2); a *= 0.5; }
+ return v;
+}
+
+// Lighter FBM for secondary detail
+float fbm4(vec2 p) {
+ float v = 0.0, a = 0.5;
+ mat2 r = mat2(0.8, 0.6, -0.6, 0.8);
+ for (int i = 0; i < 4; i++) { v += a * gn(p); p = r * p * 2.0 + vec2(1.7, 9.2); a *= 0.5; }
+ return v;
+}
+```
+
+## Domain Warping
+
+The single most important technique for natural-looking shaders. Feed noise into noise:
+
+```glsl
+// Single warp — organic but recognizable as noise
+vec2 q = vec2(fbm(uv * 2.0 + vec2(t * 0.3, t * 0.1)),
+ fbm(uv * 2.0 + vec2(t * 0.1, t * 0.4) + 5.0));
+float f = fbm(uv * 1.5 + q * 1.5);
+
+// Double warp — painterly, flowing, no visible noise pattern
+vec2 q = vec2(fbm(uv * 2.0 + vec2(t * 0.3, t * 0.1)),
+ fbm(uv * 2.0 + vec2(t * 0.1, t * 0.4) + 5.0));
+vec2 r = vec2(fbm(uv * 3.0 + q * 3.0 + vec2(1.7, t * 0.15)),
+ fbm(uv * 3.0 + q * 3.0 + vec2(8.3, t * 0.2)));
+float f = fbm(uv * 2.0 + r * 1.5);
+
+// Triple warp — truly organic, like real fluid dynamics
+vec2 q = ...; // as above
+vec2 r = ...; // as above
+vec2 s = vec2(fbm(uv * 1.0 + r * 2.0 + vec2(3.1, t * 0.05)),
+ fbm(uv * 1.0 + r * 2.0 + vec2(6.7, t * 0.03)));
+float f = fbm(uv * 1.5 + s * 1.5);
+```
+
+## Shader Patterns by Context
+
+### Warm / Travel / Lifestyle
+
+**Gradient Mesh** — flowing color blobs:
+
+```glsl
+// 5 blobs with gaussian falloff, noise-warped edges
+vec2 c1 = vec2(0.3 + sin(t*0.7)*0.15, 0.7 + cos(t*0.5)*0.12);
+float w1 = exp(-pow(length(uv - c1 + warp) * 2.5, 2.0));
+// ... repeat for each blob, weighted blend of colors
+col = (color1*w1 + color2*w2 + ...) / (w1+w2+...+0.001);
+```
+
+**Warm Caustics** — golden light on cream:
+
+```glsl
+// Double domain warp, then map to warm palette
+float c = smoothstep(0.2, 0.8, f * 0.5 + 0.5);
+vec3 col = mix(cream, gold, pow(c, 2.0) * 0.3);
+```
+
+**Sunset Horizon** — sky gradient + clouds + water reflection. Use 5+ color stops for the sky, FBM clouds with bottom-lit coloring, water below with noise-broken sun reflection.
+
+### Medical / Emergency / PSA
+
+**Biohazard Pulse** — expanding rings from center:
+
+```glsl
+for (int i = 0; i < 3; i++) {
+ float phase = fract(t * 0.3 + float(i) * 0.33);
+ float ring = abs(dist - phase * 0.7) * 30.0;
+ col += dangerColor * exp(-ring*ring) * (1.0 - phase) * 0.4;
+}
+```
+
+**Clinical Sterile** — bright white + scan line + faint grid:
+
+```glsl
+float scanY = fract(t * 0.04);
+float scan = exp(-abs(uv.y - scanY) * 100.0) * 0.08;
+float grid = max(
+ smoothstep(0.49, 0.5, fract(uv.x * 60.0)),
+ smoothstep(0.49, 0.5, fract(uv.y * 35.0))
+);
+```
+
+**Microscopic** — floating particles with membrane rings:
+
+```glsl
+float cell = exp(-pd*pd/(size*size)) * 0.2;
+float membrane = exp(-pow(abs(pd-size)*40.0, 2.0)) * 0.15;
+```
+
+**Respiratory** — breathing cycle with UV warp:
+
+```glsl
+float breath = sin(t * 0.8) * 0.5 + 0.5;
+vec2 dir = uv - center;
+vec2 warped = center + dir * (1.0 + breath * 0.04 * exp(-length(dir) * 2.0));
+```
+
+### Tech / Data / Product
+
+**Data Grid** — subtle flowing grid with accent-colored intersections. Use `fract()` for grid lines, noise for line brightness variation.
+
+**Terminal Glow** — dark base with green/blue accent scan. Monospace character rain (use noise thresholds to place bright dots in grid positions).
+
+### Industrial / Manufacturing
+
+**Heat Distortion** — UV warp increasing toward bottom:
+
+```glsl
+float heat = pow(1.0 - uv.y, 1.5);
+warped.x += sin(uv.y * 30.0 + t * 8.0) * 0.003 * heat;
+```
+
+**Warning Stripe** — diagonal hazard bands at edges:
+
+```glsl
+float stripe = sin((uv.x + uv.y) * 40.0) > 0.3 ? 1.0 : 0.0;
+float bandMask = max(smoothstep(0.88, 0.92, uv.y), smoothstep(0.12, 0.08, uv.y));
+```
+
+## Integration
+
+### In the picker
+
+Each architecture's `preview_frames` can include a `