dreative 0.1.0 → 0.3.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.
@@ -1,126 +1,131 @@
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
- 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).
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
+ DESIGN.md §13 governs the touch story: everything pointer-driven here is
9
+ fine-pointer-only, and whatever hover reveals must be reachable by tap.
10
+ If an effect needs different markup (wrappers, layers, split spans), follow
11
+ DESIGN.md §11's transformation-depth ladder offer the restructure and, once
12
+ confirmed, change the structure rather than approximating the effect in CSS.
13
+
14
+ ## 0. The feel system
15
+
16
+ Micro-interactions are a SYSTEM, not garnish. Before adding any, fix three global
17
+ constants and apply them everywhere: one hover response vocabulary, one press
18
+ response, one focus style. A page where every card hovers differently reads as
19
+ assembled, not designed.
20
+
21
+ - **Press** (all clickables): `active:scale-[0.98]` (buttons) or
22
+ `active:scale-[0.99]` (large cards) + 100ms ease-out. This single rule adds more
23
+ perceived quality per byte than anything else in this file.
24
+ - **Hover** (pick ONE per element class): background tint shift, border-color
25
+ lift, shadow deepen (tinted to bg hue), or underline draw. 150-200ms.
26
+ - **Focus**: `:focus-visible` ring, 2px, offset 2px, accent color — identical on
27
+ every interactive element, never removed.
28
+ - Everything targets the 80ms "feels instant" threshold for input feedback.
29
+
30
+ ## 1. Pointer-tracking effects (the premium tier)
31
+
32
+ All pointer tracking is springs/damping (Motion `useSpring` on `useMotionValue`,
33
+ or lerp in rAF: `x += (target - x) * 0.12`) raw 1:1 tracking feels robotic.
34
+ Desktop-only: gate behind `@media (hover: hover) and (pointer: fine)`; touch gets
35
+ the static design, not a broken half-effect. All of these are decoration cap at
36
+ 1-2 distinct pointer effects per page, on the signature element's territory.
37
+
38
+ - **Magnetic elements**: on pointer-move within a proximity zone, translate the
39
+ element toward the cursor at 15-25% of offset (buttons) with the LABEL moving
40
+ a further ~10% for parallax depth; spring back on leave
41
+ (`stiffness 150, damping 15`). Reserve for 1-2 primary CTAs or nav items.
42
+ - **Spotlight cards**: radial-gradient that follows the pointer
43
+ `background: radial-gradient(240px circle at var(--x) var(--y),
44
+ <accent 6-10% alpha>, transparent 65%)` on an overlay div; update CSS vars in
45
+ rAF. For grids, track on the CONTAINER and light borders of all cards from one
46
+ listener (the Aceternity/Linear look). Alpha 0.1; visible-but-subtle.
47
+ - **3D tilt**: perspective 800-1000px, max tilt 4-8° (10°+ is 2015 flash),
48
+ computed from pointer offset to card center, damped; add a moving specular
49
+ `linear-gradient` highlight at low alpha for material realism. Cards with text:
50
+ ≤ 5° or readability suffers.
51
+ - **Image distortion / lens effects** need WebGL — that's `skills/3d.md` §4
52
+ territory; don't fake them with CSS filters.
53
+
54
+ ## 2. Hover reveals and state morphs
55
+
56
+ - **Underline draw**: `background-image: linear-gradient(accent, accent)` sized
57
+ `0% 1.5px 100% 1.5px` on hover, 250ms expo-out, origin left. The correct link
58
+ hover for editorial registers.
59
+ - **Text swap/scramble**: label slides up revealing a duplicate from below
60
+ (wrap in `overflow-hidden`, translateY both spans). Scramble/decode effects
61
+ only on dark-tech/playful briefs, 600ms, never on body copy.
62
+ - **Card reveals**: secondary info (arrow, meta row, CTA) slides/fades in ON TOP
63
+ of a stable layout — the card must never change size on hover (layout shift =
64
+ amateur tell). Arrows translate 2-4px on hover (`group-hover:translate-x-1`),
65
+ they don't appear from nothing.
66
+ - **Icon morphs**: hamburger↔close, play↔pause as two-path SVG morphs or rotated
67
+ strokes, 200ms. Icons that rotate/bounce on every hover = noise; icons respond
68
+ only when the response means something (chevron rotates because the section
69
+ opened).
70
+ - Checkbox/toggle/radio: hand-styled with an SVG check that draws in
71
+ (`stroke-dashoffset` 200ms) the native-looking-but-smoother tier. Toggles
72
+ slide with a spring, thumb squashes slightly at rest ends.
73
+
74
+ ## 3. Surface effects (no pointer needed)
75
+
76
+ - **Glow borders**: `conic-gradient` rotating behind a masked 1px border
77
+ (`@property --angle` + animation, or padding-box/border-box double background).
78
+ One element per page, dark surfaces only, accent-hued this is a signature
79
+ move, not a card default.
80
+ - **Border beam / tracer**: an accent segment orbiting a card border via
81
+ `offset-path: border-box` (or rect())same rationing as glow.
82
+ - **Gradient shift**: oversized `background-size: 200%` + position animation on
83
+ a CTA, 2 hues from the palette. Never on text (gradient text is banned).
84
+ - **Noise/grain**: a tiled 128px PNG/data-URI at 2-4% opacity as a fixed overlay
85
+ can kill flat-gradient banding on brand pages; `feTurbulence` inline SVG is
86
+ banned (DESIGN.md §7) use a pre-baked texture.
87
+ - **Blend modes**: `mix-blend-mode: difference` for text crossing light/dark
88
+ boundaries (fixed nav over sections); `multiply/screen` to sit imagery into
89
+ tinted surfaces. Test in both themes; blend modes are the #1 source of
90
+ invisible-text bugs.
91
+ - Shadows that feel physical: 2-3 stacked layers, tinted to the background hue,
92
+ y-offset ≈ blur/2 (`0 1px 2px, 0 4px 8px, 0 16px 32px` at descending alpha).
93
+ One elevation scale page-wide.
94
+
95
+ ## 4. Scroll-adjacent feel
96
+
97
+ (Choreography lives in `skills/motion.md`; these are ambient behaviors.)
98
+
99
+ - **Sticky nav transform**: past ~80px scroll, nav gains blur backdrop
100
+ (`backdrop-blur-md` + bg at 70-85% alpha + hairline border-b), height eases
101
+ 72→60px. Drive from IntersectionObserver on a sentinel, not scroll position.
102
+ - **Scroll progress**: thin accent bar (2px) via `scroll-timeline` /
103
+ `animation-timeline: scroll()`, CSS-only. Long-form articles only.
104
+ - **Hide-on-scroll-down nav**: product register only, translate ±100% with 300ms
105
+ ease, 8px hysteresis so it doesn't flicker.
106
+
107
+ ## 5. Feedback micro-moments (product register)
108
+
109
+ - Button loading: label crossfades to spinner INSIDE the button at fixed width
110
+ (measure or `min-w`), never a layout jump; success flashes a check 600ms before
111
+ reverting.
112
+ - Copy-to-clipboard: icon morphs to check + 1.2s revert; optional 150ms
113
+ background pulse. No toast for copy.
114
+ - Form errors: input border→error color + one 4px x-axis shake (3 oscillations,
115
+ 250ms total, reduced-motion: none) + message fades in below. Shake ONCE per
116
+ submit, never loop.
117
+ - Optimistic toggles (likes, stars): fill instantly with a 1→1.2→1 spring pop on
118
+ the icon; reconcile silently on failure with an inline note.
119
+ - Skeletons: shaped like the real layout, shimmer via one masked gradient sweep
120
+ (1.4s linear infinite), same radius system as the content it becomes.
121
+
122
+ ## 6. Guardrails
123
+
124
+ - Decorative pointer effects: max 1-2 distinct kinds per page, desktop-only,
125
+ `prefers-reduced-motion` disables tracking (element stays styled, static).
126
+ - Nothing in this file may cause layout shift, block scrolling, steal focus, or
127
+ attach a raw `scroll`/`mousemove` listener without rAF batching + cleanup.
128
+ - Every effect must survive keyboard use: whatever hover reveals, focus reveals.
129
+ - Effects use palette tokens (accent/neutral), never introduce new hues.
130
+ - If an effect can't be justified in one sentence of communication value
131
+ (affordance, state, hierarchy, brand voice), it's noise — cut it (DESIGN.md §6).
@@ -1,125 +1,147 @@
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
- duration1.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.
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
+ Every effect here needs a mobile strategy per DESIGN.md §13 (shorter pins,
9
+ halved parallax, 600ms mobile entrance budget) decide it at design time.
10
+ If the requested motion needs structure the current markup can't express (pinned
11
+ sections, split text, persistent stages), use DESIGN.md §11's transformation-depth
12
+ ladder: offer restructure as an option and, once confirmed, rebuild the markup —
13
+ don't fake choreography onto the old skeleton.
14
+
15
+ ## 0. Pick the tool by the job, not by habit
16
+
17
+ - **CSS only** hover/focus/press states, one-shot entrances, marquees, simple
18
+ scroll reveals via `animation-timeline: view()`. Zero JS cost; always first choice.
19
+ - **Motion (`motion/react`, formerly Framer Motion)** React apps: presence
20
+ (`AnimatePresence`), layout animation (`layout` prop = free FLIP), springs,
21
+ `whileInView`, gesture props. The default for React product+brand pages.
22
+ - **GSAP + ScrollTrigger** — timeline choreography: multiple elements coordinated
23
+ over one scroll range, scrubbed sequences, pinned sections, kinetic type.
24
+ Use when a Motion version would need 4+ manually-synced `useScroll` hooks.
25
+ - **Lenis** — smooth scroll wrapper for scroll-driven brand pages. Only on brand
26
+ register with motion dial ≥7; never in product UI. Sync ScrollTrigger with
27
+ `lenis.on('scroll', ScrollTrigger.update)`.
28
+
29
+ One animation system per page. Motion AND GSAP on the same page = two spring
30
+ vocabularies fighting; pick one and commit.
31
+
32
+ ## 1. Springs beat durations for anything interactive
33
+
34
+ Duration+easing is for one-shot choreography (entrances, exits). Anything that
35
+ tracks input or can be interrupted (drag, hover follow, toggles, layout shifts)
36
+ uses springs they redirect mid-flight without a visible restart.
37
+
38
+ - Motion defaults: `{ type: "spring", stiffness: 300, damping: 30 }` = snappy UI;
39
+ `stiffness: 120, damping: 20` = soft brand movement. Overshoot (`damping < 15`)
40
+ only on playful briefs, and only on small elements never on layout.
41
+ - `visualDuration` (Motion ≥11.13) sets spring feel by time: easier to reason about.
42
+ - Never spring opacity or color; springs are for transform. Crossfade those.
43
+
44
+ ## 2. Orchestration: one timeline, one story
45
+
46
+ The scattered-reveals look (every section fades up independently) is the #1 motion
47
+ tell. Instead:
48
+
49
+ - **Hero entrance** = ONE composed sequence: parent `staggerChildren: 0.08`,
50
+ `delayChildren` after nav settles; elements enter in reading order; total ≤ 900ms.
51
+ Nothing else on the page gets entrance choreography.
52
+ - **Below the fold**: at most 2-3 sections get `whileInView` reveals (`once: true`,
53
+ `margin: "-20% 0px"`), and they should differ (a clip reveal here, a stagger
54
+ there) not the same fade-and-rise stamped on everything.
55
+ - Stagger direction carries meaning: top-down for lists, center-out for grids
56
+ (`delay: Math.abs(i - mid) * 0.05`), left-right only for horizontal sequences.
57
+ - Exits are faster than entrances (~75%) and simpler (fade + small offset; never
58
+ reverse the full entrance).
59
+
60
+ ## 3. Scroll choreography (motion dial 7)
61
+
62
+ - **Scrub vs trigger**: scrub (`scrub: 0.5–1` or Motion `useScroll`+`useTransform`)
63
+ for progress-bound narrative (a product rotating, a number counting, a diagram
64
+ assembling). Triggered one-shots for everything else. Scrubbed text reveals are
65
+ worn out; scrub things that MOVE, trigger things that APPEAR.
66
+ - **Pinning**: max ONE pinned sequence per page (`ScrollTrigger pin: true`, or
67
+ `position: sticky` + a tall parent — prefer sticky, it's free and un-janks).
68
+ Pin length 2.5 viewport heights; past that users feel trapped.
69
+ - **Parallax**: subtle = 8-15% differential (`useTransform(scrollYProgress, [0,1],
70
+ ["-8%","8%"])`); apply to media/decoration, never body text. 2-3 layers max.
71
+ - **CSS scroll-driven animations** (`animation-timeline: view(); animation-range:
72
+ entry 0% cover 40%`) handle simple reveals/parallax with zero JS — use for
73
+ progressive enhancement, gate with `@supports (animation-timeline: view())`.
74
+ - Progress-linked values snap to keyframes users can feel: use eased ranges
75
+ (`useTransform` with cubic arrays), not raw linear mapping.
76
+ - Never scroll-jack (hijacking wheel delta into slide-snapping). `scroll-snap` on
77
+ a horizontal strip is fine; taking over vertical page scroll is not.
78
+
79
+ ## 4. Kinetic type and text reveal
80
+
81
+ - Split text with `SplitText` (GSAP, now free) or manual word-`<span>` wrapping;
82
+ animate **words or lines, not characters** for readability (chars only for short
83
+ display words 12 chars). Wrap split parents in `overflow-hidden` line masks and
84
+ slide lines up `y: "110%" → 0` — the line-mask reveal reads as premium; per-char
85
+ fade reads as 2021 template.
86
+ - `aria-label` the original string on the split container; split spans get
87
+ `aria-hidden`. Re-splitting on resize: debounce, or use `SplitText`'s autoSplit.
88
+ - Counters: animate with `useSpring`/gsap `snap: 1`, `tabular-nums` mandatory,
89
+ duration 1.2s, trigger once in view.
90
+
91
+ ## 5. Layout & presence
92
+
93
+ - Motion `layout` prop for reflow (filtering grids, expanding cards, reordering) —
94
+ it's FLIP under the hood, transform-only. `layoutId` for shared-element morphs
95
+ (card modal). Wrap conditional trees in `AnimatePresence mode="popLayout"`.
96
+ - Accordion/height: `grid-template-rows: 0fr → 1fr` (CSS, cheap) or Motion
97
+ `height: "auto"` (it measures for you). Never `max-height: 9999px`.
98
+ - **View Transitions API** for page-level transitions (`document.startViewTransition`,
99
+ or the framework wrapper e.g. Next `<ViewTransition>`): name persistent elements
100
+ with `view-transition-name` so they morph across routes. Feature-gate; fall back
101
+ to instant navigation, not a JS fade.
102
+
103
+ ## 6. Performance and accessibility (non-negotiable)
104
+
105
+ - Transform/opacity only in hot paths; promote animating layers sparingly
106
+ (`will-change` set just-in-time, removed after). > 6 simultaneously-animating
107
+ elements = re-choreograph.
108
+ - All scroll work driven by IntersectionObserver / ScrollTrigger / `useScroll`
109
+ (rAF-batched) a raw `scroll` listener is a hard ban (DESIGN.md).
110
+ - Test the tab hidden→visible case: loops must not accumulate; `whileInView` must
111
+ not re-fire (`once: true`).
112
+ - `prefers-reduced-motion`: scrubbed narratives get a static end-state, entrances
113
+ become plain fades 200ms, marquees stop. In Motion use `useReducedMotion()`
114
+ and branch the variants — don't just shorten durations.
115
+ - Content exists without JS: initial styles are the VISIBLE state; animation
116
+ libraries then hide/offset from JS before first paint (`gsap.set`, Motion
117
+ `initial`). An SSR'd page must never flash-then-hide.
118
+
119
+ ## 7. Recipes (copy the shape, restyle the skin)
120
+
121
+ - **Hero sequence**: nav fades in (150ms) headline lines mask-slide up, 80ms
122
+ stagger → subtext + CTA fade-rise together hero media scales 1.04→1 with 6px
123
+ blur→0. Total 900ms, expo-out.
124
+ - **Sticky product walkthrough**: `sticky` media column + scrolling step copy;
125
+ step index from IntersectionObserver on copy blocks; media crossfades/transforms
126
+ per step (springy, 300ms).
127
+ - **Marquee**: duplicated track, `animation: scroll Xs linear infinite`,
128
+ `width: max-content`, pause on hover, speed from content width (px/s constant,
129
+ ~60-90px/s), masked edges with `mask-image: linear-gradient`.
130
+ - **Scrub showcase**: sticky canvas/image sequence, `useScroll` on the wrapper,
131
+ map progress to frame index / rotation; preload frames; ≤ 2.5 viewports tall.
132
+ - **Canvas product story** (capsul-in-pro.com's form): a single-product launch
133
+ page as one scroll-scrubbed narrative — the product renders on a full-page
134
+ canvas (image-sequence or WebGL) and scroll drives its assembly/rotation
135
+ while short copy beats fade in at fixed progress stops; the site ships as
136
+ one bundled app with explicit portrait/landscape variants (it gates on
137
+ orientation rather than half-working in both). Copy the shape: one subject,
138
+ one scrubbed timeline, copy anchored to progress ranges, per-orientation
139
+ choreography decided up front.
140
+ - **Text on a path** (verified on epic.net): a manifesto paragraph flows along a
141
+ curved SVG path (`<textPath>` or per-word transforms sampled from a curve) and
142
+ relaxes toward straight lines as scroll progress advances — the curve
143
+ amplitude is the scrubbed value. One per site; body text elsewhere stays flat.
144
+ - **Orbiting cursor label** (epic.net's video CTA): a circular text ring
145
+ ("PLAY VIDEO ⟲") slowly rotates around the pointer while it's over the media
146
+ region — SVG `<textPath>` on a circle, damped position follow, constant
147
+ rotation. Replaces the play button; fine pointers only, real button fallback.