dreative 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,131 @@
1
+ # Dreative Specialist Skill — 3D, WebGL & Shaders
2
+
3
+ Load this file when `plan.skills` includes `3d`, or the brief/prompt mentions 3D,
4
+ WebGL, three.js, shaders, particles, globes, or point clouds. DESIGN.md still
5
+ governs everything around the canvas (layout, color, type, motion budgets).
6
+
7
+ ## 0. Does 3D earn its place?
8
+
9
+ 3D is the most expensive pixel on the web — in bytes, battery, and attention.
10
+ It earns its place when the SUBJECT is spatial (a physical product, a device, a
11
+ map/globe, an environment, data with real dimensionality) or when the brand brief
12
+ explicitly buys a signature 3D moment. It does not earn its place as ambient
13
+ decoration: a random floating torus/blob behind hero text is the 3D equivalent of
14
+ the gradient blob — banned as a default reach. One 3D moment per page; make it the
15
+ signature element (DESIGN.md §2) or don't ship it.
16
+
17
+ Cheaper substitutes to consider first: CSS 3D transforms (`perspective` +
18
+ `rotateX/Y` on real DOM — free, accessible, great for cards/mockups/tilt), a
19
+ pre-rendered video/image sequence scrubbed on scroll, or a Lottie/Rive vector
20
+ animation. If the object never needs live lighting or user-driven rotation,
21
+ pre-render it.
22
+
23
+ ## 1. Stack
24
+
25
+ - **React app → React Three Fiber (`@react-three/fiber`) + `@react-three/drei`.**
26
+ Never hand-roll a three.js imperative setup inside React. Drei gives you 80%:
27
+ `Environment`, `ContactShadows`, `Float`, `ScrollControls`, `Html`, `Text`,
28
+ `useGLTF`, `MeshTransmissionMaterial`, `Center`, `Bounds`.
29
+ - **Non-React → three.js** with a small render-loop module; or **OGL** when the
30
+ scene is one shader plane and three.js is overkill.
31
+ - Post-processing via `@react-three/postprocessing` (Bloom, DoF, Noise) — 1-2
32
+ effects max; the stacked-postFX look reads as demo-scene, not product.
33
+ - Physics only if interaction demands it (`@react-three/rapier`).
34
+
35
+ Lazy-load the entire 3D bundle (`next/dynamic` / `React.lazy`) with an SSR-off
36
+ canvas and a styled poster fallback. Three.js must never be in the critical path.
37
+
38
+ ## 2. Scene fundamentals (where amateur scenes fail)
39
+
40
+ - **Lighting is the craft.** Default: `<Environment preset="studio"|"city">` for
41
+ image-based lighting + ONE key directional light for shadows. Ambient light
42
+ alone = flat plastic. Match light temperature to the page palette.
43
+ - **Color management:** renderer defaults in modern three are correct
44
+ (`outputColorSpace: SRGBColorSpace`, `ACESFilmicToneMapping`) — don't disable
45
+ them; DO set `toneMappingExposure` deliberately. Convert hex from the page
46
+ palette with `new THREE.Color(hex)` — scene colors and page colors must read as
47
+ one system.
48
+ - **Ground the object:** `<ContactShadows opacity={0.4} blur={2.5}>` or a real
49
+ shadow plane. Floating unanchored objects read as clipart.
50
+ - Camera: 35-50° FOV for product shots (85°+ distorts); frame with
51
+ `<Bounds fit clip>` or `<Center>`; subtle idle via `<Float>` or damped
52
+ mouse-parallax (`useFrame` + `THREE.MathUtils.damp`), amplitude ≤ 3°.
53
+ - Materials: `meshStandardMaterial`/`meshPhysicalMaterial` with `roughness`/
54
+ `metalness` chosen from the real object; `MeshTransmissionMaterial` for glass
55
+ (expensive — one object max). Untextured default-gray = unfinished.
56
+
57
+ ## 3. Models
58
+
59
+ - glTF/GLB only, Draco or Meshopt compressed (`gltf-transform optimize in.glb
60
+ out.glb --compress draco`). Budget: hero model ≤ 2-3 MB, ≤ 100k triangles.
61
+ - `useGLTF.preload(url)`; wrap in `<Suspense>` with a poster (not a spinner).
62
+ - No model available? Build from primitives + good materials/lighting (a laptop
63
+ from rounded boxes with an `Html` screen reads better than a bad download), or
64
+ tell the user what asset is needed — never ship an unrelated placeholder model.
65
+
66
+ ## 4. Shaders (the highest-leverage 100 lines)
67
+
68
+ A fullscreen/plane fragment shader is the cheapest way to a signature visual:
69
+ animated gradient meshes, flowfields, displacement on hover, image transitions.
70
+
71
+ - Structure: `shaderMaterial` (drei) with `uTime`, `uMouse`, `uResolution`,
72
+ palette colors as `uColorA/B/C` uniforms fed FROM the page palette.
73
+ - Vocabulary: fbm/simplex noise for organic movement (inline a noise fn; don't
74
+ import a library for it), `smoothstep` for banding-free ramps, domain warping
75
+ (`noise(p + noise(p))`) for the expensive look, `mix()` between palette colors
76
+ only — never rainbow hue-rotation.
77
+ - Displace vertices in the vertex shader for cloth/terrain/blob effects; compute
78
+ normals or fake lighting with the noise derivative.
79
+ - Animate `uTime` at 0.05-0.2 speed; slow reads as premium, fast as screensaver.
80
+ - Image effects: sample two textures + a noise mask for transitions; barrel/flow
81
+ distortion on scroll velocity for editorial galleries.
82
+
83
+ ## 5. Particles and points
84
+
85
+ Points/instancing, never meshes-per-particle: `<Points>` + `BufferAttribute`
86
+ positions animated in a shader (`uTime` in the vertex shader), or
87
+ `<Instances>`/`InstancedMesh` for repeated geometry (≤ ~10k instances). Counts:
88
+ 2-5k points desktop, halve on mobile. Particle color from the page palette at 1-2
89
+ hues; size attenuation on; additive blending only on dark surfaces.
90
+
91
+ ## 6. Scroll- and layout-integration
92
+
93
+ - Canvas placement: either a bounded block IN the layout (preferred — it composes
94
+ with the grid) or a full-bleed fixed background with content scrolling over.
95
+ Full-page persistent canvases with DOM scrolled on top: use drei
96
+ `ScrollControls` + `<Scroll html>` so 3D and DOM share one scroll.
97
+ - Scroll-linked 3D: map scroll progress (Motion `useScroll` / ScrollTrigger /
98
+ drei `useScroll`) to camera position along a path or object rotation — damped
99
+ (`damp3`, `dampE`), never raw-set per frame.
100
+ - DOM/3D registration (labels pinned to model parts): drei `<Html transform
101
+ occlude>`; keep text as real DOM for accessibility, never texture-baked type.
102
+ - The block's `data-dreative-id` goes on the wrapper div around the Canvas.
103
+
104
+ ## 7. Performance & fallbacks (ship-blockers)
105
+
106
+ - `<Canvas dpr={[1, 2]}>` (cap device pixel ratio), `frameloop="demand"` +
107
+ `invalidate()` for static-until-interacted scenes; pause the loop when the
108
+ canvas leaves the viewport (IntersectionObserver) and on `document.hidden`.
109
+ - One `useFrame` per concern; no allocations inside it (reuse vectors created
110
+ outside). Dispose on unmount (R3F handles it; imperative three must
111
+ `dispose()` geometries/materials/textures).
112
+ - Mobile: halve particle counts, drop post-processing, consider a poster image
113
+ below 768px — a janky 3D hero is worse than none.
114
+ - `prefers-reduced-motion`: stop idle rotation/particle drift; render one static
115
+ well-lit frame (`frameloop="demand"` makes this free).
116
+ - WebGL unavailable/context-lost → the poster fallback, never a blank block.
117
+ - Keyboard/screen-reader: canvas gets `role="img"` + `aria-label`; any 3D-driven
118
+ interaction has a DOM equivalent.
119
+
120
+ ## 8. Recipes
121
+
122
+ - **Product hero**: GLB + `Environment` + key light + `ContactShadows`, `Float`
123
+ idle, damped mouse parallax, scroll scrubs a 90° orbit. Poster until loaded.
124
+ - **Gradient-mesh hero background**: one plane, fbm + domain-warp fragment shader
125
+ mixing 3 palette colors, `uTime` 0.08, `uMouse` warps locally. ~120 lines, no
126
+ model, no lighting — the best effort/impact ratio in this file.
127
+ - **Point-cloud globe**: sphere-distributed points, shader-animated shimmer,
128
+ arcs as `TubeGeometry`/fat lines between coords, slow idle rotation, drag to
129
+ spin (damped).
130
+ - **Scroll story**: `ScrollControls pages={4}` + camera on a `CatmullRomCurve3`
131
+ path, DOM copy in `<Scroll html>`, one damped lookAt target per section.
@@ -0,0 +1,126 @@
1
+ # Dreative Specialist Skill — Micro-interactions & Effect Craft
2
+
3
+ Load this file when `plan.skills` includes `interaction`, or the brief/prompt asks
4
+ for hover effects, cursor work, tilt, glow, "make it feel alive/tactile/premium".
5
+ It EXTENDS DESIGN.md §6/§9/§10 — every ban there still stands (no hover-scale on
6
+ `<img>`, custom cursors only on explicit request, one marquee max). This skill is
7
+ about the last 5% of feel: small, physical, consistent responses to input.
8
+
9
+ ## 0. The feel system
10
+
11
+ Micro-interactions are a SYSTEM, not garnish. Before adding any, fix three global
12
+ constants and apply them everywhere: one hover response vocabulary, one press
13
+ response, one focus style. A page where every card hovers differently reads as
14
+ assembled, not designed.
15
+
16
+ - **Press** (all clickables): `active:scale-[0.98]` (buttons) or
17
+ `active:scale-[0.99]` (large cards) + 100ms ease-out. This single rule adds more
18
+ perceived quality per byte than anything else in this file.
19
+ - **Hover** (pick ONE per element class): background tint shift, border-color
20
+ lift, shadow deepen (tinted to bg hue), or underline draw. 150-200ms.
21
+ - **Focus**: `:focus-visible` ring, 2px, offset 2px, accent color — identical on
22
+ every interactive element, never removed.
23
+ - Everything targets the 80ms "feels instant" threshold for input feedback.
24
+
25
+ ## 1. Pointer-tracking effects (the premium tier)
26
+
27
+ All pointer tracking is springs/damping (Motion `useSpring` on `useMotionValue`,
28
+ or lerp in rAF: `x += (target - x) * 0.12`) — raw 1:1 tracking feels robotic.
29
+ Desktop-only: gate behind `@media (hover: hover) and (pointer: fine)`; touch gets
30
+ the static design, not a broken half-effect. All of these are decoration — cap at
31
+ 1-2 distinct pointer effects per page, on the signature element's territory.
32
+
33
+ - **Magnetic elements**: on pointer-move within a proximity zone, translate the
34
+ element toward the cursor at 15-25% of offset (buttons) with the LABEL moving
35
+ a further ~10% for parallax depth; spring back on leave
36
+ (`stiffness 150, damping 15`). Reserve for 1-2 primary CTAs or nav items.
37
+ - **Spotlight cards**: radial-gradient that follows the pointer —
38
+ `background: radial-gradient(240px circle at var(--x) var(--y),
39
+ <accent 6-10% alpha>, transparent 65%)` on an overlay div; update CSS vars in
40
+ rAF. For grids, track on the CONTAINER and light borders of all cards from one
41
+ listener (the Aceternity/Linear look). Alpha ≤ 0.1; visible-but-subtle.
42
+ - **3D tilt**: perspective 800-1000px, max tilt 4-8° (10°+ is 2015 flash),
43
+ computed from pointer offset to card center, damped; add a moving specular
44
+ `linear-gradient` highlight at low alpha for material realism. Cards with text:
45
+ ≤ 5° or readability suffers.
46
+ - **Image distortion / lens effects** need WebGL — that's `skills/3d.md` §4
47
+ territory; don't fake them with CSS filters.
48
+
49
+ ## 2. Hover reveals and state morphs
50
+
51
+ - **Underline draw**: `background-image: linear-gradient(accent, accent)` sized
52
+ `0% 1.5px → 100% 1.5px` on hover, 250ms expo-out, origin left. The correct link
53
+ hover for editorial registers.
54
+ - **Text swap/scramble**: label slides up revealing a duplicate from below
55
+ (wrap in `overflow-hidden`, translateY both spans). Scramble/decode effects
56
+ only on dark-tech/playful briefs, ≤ 600ms, never on body copy.
57
+ - **Card reveals**: secondary info (arrow, meta row, CTA) slides/fades in ON TOP
58
+ of a stable layout — the card must never change size on hover (layout shift =
59
+ amateur tell). Arrows translate 2-4px on hover (`group-hover:translate-x-1`),
60
+ they don't appear from nothing.
61
+ - **Icon morphs**: hamburger↔close, play↔pause as two-path SVG morphs or rotated
62
+ strokes, 200ms. Icons that rotate/bounce on every hover = noise; icons respond
63
+ only when the response means something (chevron rotates because the section
64
+ opened).
65
+ - Checkbox/toggle/radio: hand-styled with an SVG check that draws in
66
+ (`stroke-dashoffset` 200ms) — the native-looking-but-smoother tier. Toggles
67
+ slide with a spring, thumb squashes slightly at rest ends.
68
+
69
+ ## 3. Surface effects (no pointer needed)
70
+
71
+ - **Glow borders**: `conic-gradient` rotating behind a masked 1px border
72
+ (`@property --angle` + animation, or padding-box/border-box double background).
73
+ One element per page, dark surfaces only, accent-hued — this is a signature
74
+ move, not a card default.
75
+ - **Border beam / tracer**: an accent segment orbiting a card border via
76
+ `offset-path: border-box` (or rect()) — same rationing as glow.
77
+ - **Gradient shift**: oversized `background-size: 200%` + position animation on
78
+ a CTA, ≤ 2 hues from the palette. Never on text (gradient text is banned).
79
+ - **Noise/grain**: a tiled 128px PNG/data-URI at 2-4% opacity as a fixed overlay
80
+ can kill flat-gradient banding on brand pages; `feTurbulence` inline SVG is
81
+ banned (DESIGN.md §7) — use a pre-baked texture.
82
+ - **Blend modes**: `mix-blend-mode: difference` for text crossing light/dark
83
+ boundaries (fixed nav over sections); `multiply/screen` to sit imagery into
84
+ tinted surfaces. Test in both themes; blend modes are the #1 source of
85
+ invisible-text bugs.
86
+ - Shadows that feel physical: 2-3 stacked layers, tinted to the background hue,
87
+ y-offset ≈ blur/2 (`0 1px 2px, 0 4px 8px, 0 16px 32px` at descending alpha).
88
+ One elevation scale page-wide.
89
+
90
+ ## 4. Scroll-adjacent feel
91
+
92
+ (Choreography lives in `skills/motion.md`; these are ambient behaviors.)
93
+
94
+ - **Sticky nav transform**: past ~80px scroll, nav gains blur backdrop
95
+ (`backdrop-blur-md` + bg at 70-85% alpha + hairline border-b), height eases
96
+ 72→60px. Drive from IntersectionObserver on a sentinel, not scroll position.
97
+ - **Scroll progress**: thin accent bar (2px) via `scroll-timeline` /
98
+ `animation-timeline: scroll()`, CSS-only. Long-form articles only.
99
+ - **Hide-on-scroll-down nav**: product register only, translate ±100% with 300ms
100
+ ease, 8px hysteresis so it doesn't flicker.
101
+
102
+ ## 5. Feedback micro-moments (product register)
103
+
104
+ - Button loading: label crossfades to spinner INSIDE the button at fixed width
105
+ (measure or `min-w`), never a layout jump; success flashes a check 600ms before
106
+ reverting.
107
+ - Copy-to-clipboard: icon morphs to check + 1.2s revert; optional 150ms
108
+ background pulse. No toast for copy.
109
+ - Form errors: input border→error color + one 4px x-axis shake (3 oscillations,
110
+ 250ms total, reduced-motion: none) + message fades in below. Shake ONCE per
111
+ submit, never loop.
112
+ - Optimistic toggles (likes, stars): fill instantly with a 1→1.2→1 spring pop on
113
+ the icon; reconcile silently on failure with an inline note.
114
+ - Skeletons: shaped like the real layout, shimmer via one masked gradient sweep
115
+ (1.4s linear infinite), same radius system as the content it becomes.
116
+
117
+ ## 6. Guardrails
118
+
119
+ - Decorative pointer effects: max 1-2 distinct kinds per page, desktop-only,
120
+ `prefers-reduced-motion` disables tracking (element stays styled, static).
121
+ - Nothing in this file may cause layout shift, block scrolling, steal focus, or
122
+ attach a raw `scroll`/`mousemove` listener without rAF batching + cleanup.
123
+ - Every effect must survive keyboard use: whatever hover reveals, focus reveals.
124
+ - Effects use palette tokens (accent/neutral), never introduce new hues.
125
+ - If an effect can't be justified in one sentence of communication value
126
+ (affordance, state, hierarchy, brand voice), it's noise — cut it (DESIGN.md §6).
@@ -0,0 +1,125 @@
1
+ # Dreative Specialist Skill — Motion & Scroll Choreography
2
+
3
+ Load this file when `plan.skills` includes `motion`, or the brief/prompt asks for
4
+ animation, parallax, scroll storytelling, kinetic type, or "cinematic" feel.
5
+ It EXTENDS DESIGN.md §6 (which still applies: 100/300/500 durations, ease-out
6
+ exponential curves, reduced-motion fallbacks, no scroll listeners, no bounce).
7
+ This file is about doing ambitious motion WELL, not about adding more of it.
8
+
9
+ ## 0. Pick the tool by the job, not by habit
10
+
11
+ - **CSS only** — hover/focus/press states, one-shot entrances, marquees, simple
12
+ scroll reveals via `animation-timeline: view()`. Zero JS cost; always first choice.
13
+ - **Motion (`motion/react`, formerly Framer Motion)** — React apps: presence
14
+ (`AnimatePresence`), layout animation (`layout` prop = free FLIP), springs,
15
+ `whileInView`, gesture props. The default for React product+brand pages.
16
+ - **GSAP + ScrollTrigger** — timeline choreography: multiple elements coordinated
17
+ over one scroll range, scrubbed sequences, pinned sections, kinetic type.
18
+ Use when a Motion version would need 4+ manually-synced `useScroll` hooks.
19
+ - **Lenis** — smooth scroll wrapper for scroll-driven brand pages. Only on brand
20
+ register with motion dial ≥7; never in product UI. Sync ScrollTrigger with
21
+ `lenis.on('scroll', ScrollTrigger.update)`.
22
+
23
+ One animation system per page. Motion AND GSAP on the same page = two spring
24
+ vocabularies fighting; pick one and commit.
25
+
26
+ ## 1. Springs beat durations for anything interactive
27
+
28
+ Duration+easing is for one-shot choreography (entrances, exits). Anything that
29
+ tracks input or can be interrupted (drag, hover follow, toggles, layout shifts)
30
+ uses springs — they redirect mid-flight without a visible restart.
31
+
32
+ - Motion defaults: `{ type: "spring", stiffness: 300, damping: 30 }` = snappy UI;
33
+ `stiffness: 120, damping: 20` = soft brand movement. Overshoot (`damping < 15`)
34
+ only on playful briefs, and only on small elements — never on layout.
35
+ - `visualDuration` (Motion ≥11.13) sets spring feel by time: easier to reason about.
36
+ - Never spring opacity or color; springs are for transform. Crossfade those.
37
+
38
+ ## 2. Orchestration: one timeline, one story
39
+
40
+ The scattered-reveals look (every section fades up independently) is the #1 motion
41
+ tell. Instead:
42
+
43
+ - **Hero entrance** = ONE composed sequence: parent `staggerChildren: 0.08`,
44
+ `delayChildren` after nav settles; elements enter in reading order; total ≤ 900ms.
45
+ Nothing else on the page gets entrance choreography.
46
+ - **Below the fold**: at most 2-3 sections get `whileInView` reveals (`once: true`,
47
+ `margin: "-20% 0px"`), and they should differ (a clip reveal here, a stagger
48
+ there) — not the same fade-and-rise stamped on everything.
49
+ - Stagger direction carries meaning: top-down for lists, center-out for grids
50
+ (`delay: Math.abs(i - mid) * 0.05`), left-right only for horizontal sequences.
51
+ - Exits are faster than entrances (~75%) and simpler (fade + small offset; never
52
+ reverse the full entrance).
53
+
54
+ ## 3. Scroll choreography (motion dial ≥ 7)
55
+
56
+ - **Scrub vs trigger**: scrub (`scrub: 0.5–1` or Motion `useScroll`+`useTransform`)
57
+ for progress-bound narrative (a product rotating, a number counting, a diagram
58
+ assembling). Triggered one-shots for everything else. Scrubbed text reveals are
59
+ worn out; scrub things that MOVE, trigger things that APPEAR.
60
+ - **Pinning**: max ONE pinned sequence per page (`ScrollTrigger pin: true`, or
61
+ `position: sticky` + a tall parent — prefer sticky, it's free and un-janks).
62
+ Pin length ≤ 2.5 viewport heights; past that users feel trapped.
63
+ - **Parallax**: subtle = 8-15% differential (`useTransform(scrollYProgress, [0,1],
64
+ ["-8%","8%"])`); apply to media/decoration, never body text. 2-3 layers max.
65
+ - **CSS scroll-driven animations** (`animation-timeline: view(); animation-range:
66
+ entry 0% cover 40%`) handle simple reveals/parallax with zero JS — use for
67
+ progressive enhancement, gate with `@supports (animation-timeline: view())`.
68
+ - Progress-linked values snap to keyframes users can feel: use eased ranges
69
+ (`useTransform` with cubic arrays), not raw linear mapping.
70
+ - Never scroll-jack (hijacking wheel delta into slide-snapping). `scroll-snap` on
71
+ a horizontal strip is fine; taking over vertical page scroll is not.
72
+
73
+ ## 4. Kinetic type and text reveal
74
+
75
+ - Split text with `SplitText` (GSAP, now free) or manual word-`<span>` wrapping;
76
+ animate **words or lines, not characters** for readability (chars only for short
77
+ display words ≤ 12 chars). Wrap split parents in `overflow-hidden` line masks and
78
+ slide lines up `y: "110%" → 0` — the line-mask reveal reads as premium; per-char
79
+ fade reads as 2021 template.
80
+ - `aria-label` the original string on the split container; split spans get
81
+ `aria-hidden`. Re-splitting on resize: debounce, or use `SplitText`'s autoSplit.
82
+ - Counters: animate with `useSpring`/gsap `snap: 1`, `tabular-nums` mandatory,
83
+ duration ≤ 1.2s, trigger once in view.
84
+
85
+ ## 5. Layout & presence
86
+
87
+ - Motion `layout` prop for reflow (filtering grids, expanding cards, reordering) —
88
+ it's FLIP under the hood, transform-only. `layoutId` for shared-element morphs
89
+ (card → modal). Wrap conditional trees in `AnimatePresence mode="popLayout"`.
90
+ - Accordion/height: `grid-template-rows: 0fr → 1fr` (CSS, cheap) or Motion
91
+ `height: "auto"` (it measures for you). Never `max-height: 9999px`.
92
+ - **View Transitions API** for page-level transitions (`document.startViewTransition`,
93
+ or the framework wrapper e.g. Next `<ViewTransition>`): name persistent elements
94
+ with `view-transition-name` so they morph across routes. Feature-gate; fall back
95
+ to instant navigation, not a JS fade.
96
+
97
+ ## 6. Performance and accessibility (non-negotiable)
98
+
99
+ - Transform/opacity only in hot paths; promote animating layers sparingly
100
+ (`will-change` set just-in-time, removed after). > 6 simultaneously-animating
101
+ elements = re-choreograph.
102
+ - All scroll work driven by IntersectionObserver / ScrollTrigger / `useScroll`
103
+ (rAF-batched) — a raw `scroll` listener is a hard ban (DESIGN.md).
104
+ - Test the tab hidden→visible case: loops must not accumulate; `whileInView` must
105
+ not re-fire (`once: true`).
106
+ - `prefers-reduced-motion`: scrubbed narratives get a static end-state, entrances
107
+ become plain fades ≤ 200ms, marquees stop. In Motion use `useReducedMotion()`
108
+ and branch the variants — don't just shorten durations.
109
+ - Content exists without JS: initial styles are the VISIBLE state; animation
110
+ libraries then hide/offset from JS before first paint (`gsap.set`, Motion
111
+ `initial`). An SSR'd page must never flash-then-hide.
112
+
113
+ ## 7. Recipes (copy the shape, restyle the skin)
114
+
115
+ - **Hero sequence**: nav fades in (150ms) → headline lines mask-slide up, 80ms
116
+ stagger → subtext + CTA fade-rise together → hero media scales 1.04→1 with 6px
117
+ blur→0. Total 900ms, expo-out.
118
+ - **Sticky product walkthrough**: `sticky` media column + scrolling step copy;
119
+ step index from IntersectionObserver on copy blocks; media crossfades/transforms
120
+ per step (springy, 300ms).
121
+ - **Marquee**: duplicated track, `animation: scroll Xs linear infinite`,
122
+ `width: max-content`, pause on hover, speed from content width (px/s constant,
123
+ ~60-90px/s), masked edges with `mask-image: linear-gradient`.
124
+ - **Scrub showcase**: sticky canvas/image sequence, `useScroll` on the wrapper,
125
+ map progress to frame index / rotation; preload frames; ≤ 2.5 viewports tall.