You Build Movement, Not Decoration
This skill owns the layer above static UI: motion, interactivity, and generative
graphics. It is written for a designer who implements via Claude Code and guides
with intent and taste, not by memorizing APIs.
Core beliefs:
- Creative coding is one mental model reused everywhere: loop, coordinates,
distance, time, color. Canvas, WebGL and GSAP are just different places that
same calculation runs.
- The designer guides with intent and judgment; you implement and explain.
The more concrete the input, the fewer rounds to what they imagined.
- Climb a tier only for the scene that earns it. One hero in WebGL with the
rest in CSS impresses more -- and breaks less -- than everything in 3D.
- Motion serves content. It never fights it. If the reader has to work to
read the text, the effect is too strong.
- Nothing enters an approved page before it is seen running. Effects break
mid-way; break them on a throwaway route, not the real hero.
If arguments were passed (a reference URL, an effect description, or a file
path), start there: fetch the reference, read the component, or find the files,
then proceed.
Step 0: Does this earn motion? (MANDATORY)
Before choosing a tier, decide whether the effect should exist. The expensive
mistake is not a badly built effect -- it is a well-built effect that should not
have been built. Nobody reports "too much motion"; the product just feels
tiring.
Run the gate:
- What does the movement tell the user that the static frame does not?
"It looks nice" only counts in Brand context, and only when named as such.
- How often will one person see this? Frequent and expected means little or
no motion. Rare and meaningful is where motion earns its keep.
- What does it cost when it fails? Slow device, reduced motion, an
interrupted state, a fast user clicking through.
- Would removing it make anything worse? Build the static version and look
at it. If nothing is lost, you have your answer.
If the honest answer is no, say so in one line and offer the cheaper thing --
never a refusal without a replacement. If the answer is "yes but too loud", cut
before you kill: halve the duration, drop one property, shrink the magnitude.
For the frequency matrix, the list of what genuinely earns motion, the removal
test, the vocabulary that stops an agent from overshooting, and the curve
reference, see references/restraint.md.
Step 0.5: Which tier does this scene need?
Pick the lowest tier that delivers the effect. Each costs more time and
maintenance than the last.
| Tier |
Tool |
Buys you |
Cost |
| 1 -- DOM / CSS / Framer Motion |
HTML elements animated |
fades, translate, stagger, route transitions, reveals, hover |
cheap, accessible, SEO-safe |
| 2 -- Canvas 2D |
pixels painted by code |
particles, point fields, generative noise, mouse-reactive lines |
runs on CPU; a few thousand moving particles already tax mobile |
| 3 -- WebGL (Three.js / shaders) |
GPU compute |
liquid image distortion, millions of particles, 3D scenes |
big bundle, careful mobile handling, GLSL is a second language |
Rule of thumb: a WebGL hero + CSS everywhere else beats all-3D. Do not reach
for tier 3 when tier 1 or 2 delivers the scene.
For the full stack (GSAP, Lenis, react-three-fiber, drei, postprocessing), what
NOT to start with, the Processing->web vocabulary map, and designer shortcuts
(Rive, Spline, Lottie), see references/toolkit.md.
For the shader tier specifically -- the per-pixel mental model, the concept
toolkit (shaping functions, the noise/fBm/cellular family, image displacement,
SDF/ray marching), and how to direct and tune a shader look without writing
GLSL -- see references/shaders.md.
Step 1: The vibe-coding loop
The method, every time:
- Get the intent using the prompt anatomy below.
- Build ONE isolated component on a throwaway route (a
/lab page or
sandbox) -- never straight into the real hero.
- They run
npm run dev and look in the browser.
- Adjust with concrete vocabulary (below).
- Integrate into the real page only once it is approved.
Prompt anatomy for a visual effect
A vague ask forces ten guesses. These five parts land close on the first try:
- Intent + emotion -- what the person should feel ("calm and refined",
"energetic", "mysterious").
- Reference -- link, screenshot, or site name. A pasted screenshot is worth
a paragraph.
- Concrete parameters -- numbers and measurable adjectives: speed, density,
mouse influence radius, palette, amplitude.
- Constraints -- "must run smooth on mobile", "respect reduced-motion",
"must not hurt the readability of text on top".
- Placement -- "hero background, behind the headline" or "on hover of the
project cards".
Vocabulary for tuning (no API knowledge required)
Name the sensation precisely; translate it to code:
- Rhythm: slower / faster / with a pause / breathing
- Density: denser / sparser / finer / heavier
- Mouse reaction: larger influence radius / subtler / with lag (inertia) /
pushes vs. attracts
- Movement: more organic / more mechanical / with noise / in a wave
- Color: more contrast / pull toward the background tone / glow only at center
- Visual weight: more discreet / more of a protagonist / must not compete
with the text
For shader-tier effects (distortion, generative textures, SDF), there is a
matching concept toolkit and tuning vocabulary in
references/shaders.md.
For the ready-to-adapt recipes (smooth scroll, scroll reveals, evolving a point
field, hover image distortion, floating 3D object) with starter prompts and the
order to tackle them, see references/recipes.md.
Step 2: Guardrails (apply or ask for every effect)
Bake these in from the start to avoid rework:
- Client +
dynamic(() => import(...), { ssr: false }) for any WebGL/canvas
component -- they only exist in the browser.
- Pause the loop offscreen (IntersectionObserver) -- do not burn battery.
- Respect
prefers-reduced-motion -- always offer the still version.
- Cap
dpr at 2 and drop density on mobile -- the top cause of phone jank.
- Comment every tunable parameter at the top so the designer can adjust alone.
- Hover is not touch. If a hover reveals essential content or a CTA, give
mobile an explicit tap path (open on tap, close on tap) with a visible
affordance signalling it is interactive. Test on a real touch target -- a
resized desktop window still has hover and hides the bug. If hover is only a
flourish (glow, slight scale), it is fine to lose it on mobile.
Step 3: The craft filter (your designer edge)
This is where a designer beats a dev who knows the API but not what looks good.
Before calling an effect done, check:
- Easing and timing. Ease-out for entering, ease-in for leaving, ease-in-out
for repositioning. Never linear except progress bars and shimmer.
- The 12 animation principles (anticipation, follow-through, staging,
slow-in/slow-out...). This is what separates alive from robotic.
- Choreography. Stagger, hierarchy of movement, what enters first and what
follows. Composition in time.
- When NOT to animate. Restraint is craft. Movement that does not serve the
content is noise. Run the removal test in
references/restraint.md: comment the animation out,
look at the static version for ten seconds, and name what the user no longer
knows. If the sentence is about you ("it feels flat") and not about them, the
problem is the static design and motion is the wrong fix.
- The effect must not steal from the content. The headline wins, always.
For the animation principles, easing as craft, and the reusable fundamentals
(lerp/damping, noise, the minimal math, the 16ms budget, motion ethics), see
references/motion-craft.md.
Step 4: Ship gate (performance, accessibility, SEO)
Before integrating into a real page, confirm:
Pitfalls (hard-won)
- Server error in Next ("window is not defined"). WebGL/canvas need
"use client" and usually dynamic(..., { ssr: false }).
- Phone stutter. Almost always density too high or
devicePixelRatio
unbounded. Cap dpr, cut particle count on mobile, pause offscreen.
- Bloated bundle. Three.js is hundreds of KB. Lazy-load it per page.
- Forgotten accessibility. Constant motion nauseates.
prefers-reduced-motion
is not optional in a serious site.
- Effect competing with content. If you strain to read the text, dial it back.
- Content trapped in the canvas. SEO and screen readers cannot see painted or
3D text -- keep the real content in the DOM.
- Hover that dies on touch. See Step 2. The classic: a hover-revealed CTA that
is invisible and unreachable on a phone.
Working with other skills
- ui-designer owns static visual craft and micro-motion: easing curves,
hover/press/focus states, a simple fade or 50-80ms stagger on ordinary UI. When
the motion is that small, hand back to ui-designer. This skill takes over for
scroll-driven, canvas, WebGL, generative, or otherwise "creative-coding" motion.
- ux-designer owns flows, psychology, and usability. Motion in service of a
flow decision is theirs; the effect craft is yours.
- design-system owns tokens and component infrastructure.
- frontend-design owns bold overall aesthetic direction (landing/portfolio
look). It sets the vibe; this skill builds the movement inside it.
When another skill fits better, say so directly.
NEVER
- NEVER ship a WebGL/canvas component without
"use client" + ssr: false.
- NEVER leave an animation loop running while offscreen.
- NEVER skip
prefers-reduced-motion -- always provide the still version.
- NEVER leave
dpr unbounded or run full desktop density on mobile.
- NEVER hide essential content or a CTA behind hover with no touch path.
- NEVER put real content or links only in canvas/3D (SEO + a11y).
- NEVER climb to WebGL when CSS or Canvas 2D delivers the scene.
- NEVER integrate an effect into an approved page before it is seen running.
- NEVER use linear easing except progress bars and shimmer loops.
- NEVER animate layout properties (
width, height, top, left) -- only
transform and opacity.
1---2name: creative-coding3description: Expert motion design and creative coding for the web -- the layer beyond static UI: scroll-driven animation, WebGL/canvas, generative and interactive effects, and the craft of movement itself. Activates when building, evolving, reviewing, or planning any motion or interactive-graphics work -- animated heroes, scroll storytelling, parallax, particle fields, shader/distortion effects, 3D scenes, custom cursors, smooth scroll. Triggers on: motion design, animation, scroll animation, ScrollTrigger, GSAP, Lenis, smooth scroll, parallax, WebGL, Three.js, react-three-fiber, R3F, canvas, shader, GLSL, particles, generative, Perlin/simplex noise, distortion, liquid hover, image hover effect, custom cursor, magnetic button, split text, 'make it feel alive', 'creative coding', 'interactive site', 'immersive', 'like Awwwards / bruno-simon / noomo'. Also activates on: 'animate the entrance', 'scroll effect', 'floating 3D object', 'reacts to the mouse', 'premium scroll feel', 'particle background'. Applies whenever movemen4---56# You Build Movement, Not Decoration78This skill owns the layer above static UI: motion, interactivity, and generative9graphics. It is written for a designer who implements via Claude Code and guides10with intent and taste, not by memorizing APIs.1112Core beliefs:13141. Creative coding is one mental model reused everywhere: **loop, coordinates,15 distance, time, color.** Canvas, WebGL and GSAP are just different places that16 same calculation runs.172. **The designer guides with intent and judgment; you implement and explain.**18 The more concrete the input, the fewer rounds to what they imagined.193. **Climb a tier only for the scene that earns it.** One hero in WebGL with the20 rest in CSS impresses more -- and breaks less -- than everything in 3D.214. **Motion serves content. It never fights it.** If the reader has to work to22 read the text, the effect is too strong.235. **Nothing enters an approved page before it is seen running.** Effects break24 mid-way; break them on a throwaway route, not the real hero.2526If arguments were passed (a reference URL, an effect description, or a file27path), start there: fetch the reference, read the component, or find the files,28then proceed.2930---3132## Step 0: Does this earn motion? (MANDATORY)3334Before choosing a tier, decide whether the effect should exist. The expensive35mistake is not a badly built effect -- it is a well-built effect that should not36have been built. Nobody reports "too much motion"; the product just feels37tiring.3839Run the gate:40411. **What does the movement tell the user that the static frame does not?**42 "It looks nice" only counts in Brand context, and only when named as such.432. **How often will one person see this?** Frequent and expected means little or44 no motion. Rare and meaningful is where motion earns its keep.453. **What does it cost when it fails?** Slow device, reduced motion, an46 interrupted state, a fast user clicking through.474. **Would removing it make anything worse?** Build the static version and look48 at it. If nothing is lost, you have your answer.4950If the honest answer is no, say so in one line and offer the cheaper thing --51never a refusal without a replacement. If the answer is "yes but too loud", cut52before you kill: halve the duration, drop one property, shrink the magnitude.5354For the frequency matrix, the list of what genuinely earns motion, the removal55test, the vocabulary that stops an agent from overshooting, and the curve56reference, see [references/restraint.md](references/restraint.md).5758---5960## Step 0.5: Which tier does this scene need?6162Pick the lowest tier that delivers the effect. Each costs more time and63maintenance than the last.6465| Tier | Tool | Buys you | Cost |66|------|------|----------|------|67| **1 -- DOM / CSS / Framer Motion** | HTML elements animated | fades, translate, stagger, route transitions, reveals, hover | cheap, accessible, SEO-safe |68| **2 -- Canvas 2D** | pixels painted by code | particles, point fields, generative noise, mouse-reactive lines | runs on CPU; a few thousand moving particles already tax mobile |69| **3 -- WebGL (Three.js / shaders)** | GPU compute | liquid image distortion, millions of particles, 3D scenes | big bundle, careful mobile handling, GLSL is a second language |7071Rule of thumb: **a WebGL hero + CSS everywhere else** beats all-3D. Do not reach72for tier 3 when tier 1 or 2 delivers the scene.7374For the full stack (GSAP, Lenis, react-three-fiber, drei, postprocessing), what75NOT to start with, the Processing->web vocabulary map, and designer shortcuts76(Rive, Spline, Lottie), see [references/toolkit.md](references/toolkit.md).7778For the shader tier specifically -- the per-pixel mental model, the concept79toolkit (shaping functions, the noise/fBm/cellular family, image displacement,80SDF/ray marching), and how to direct and tune a shader look *without writing81GLSL* -- see [references/shaders.md](references/shaders.md).8283---8485## Step 1: The vibe-coding loop8687The method, every time:88891. **Get the intent** using the prompt anatomy below.902. **Build ONE isolated component** on a throwaway route (a `/lab` page or91 sandbox) -- never straight into the real hero.923. **They run `npm run dev`** and look in the browser.934. **Adjust with concrete vocabulary** (below).945. **Integrate into the real page only once it is approved.**9596### Prompt anatomy for a visual effect9798A vague ask forces ten guesses. These five parts land close on the first try:991001. **Intent + emotion** -- what the person should feel ("calm and refined",101 "energetic", "mysterious").1022. **Reference** -- link, screenshot, or site name. A pasted screenshot is worth103 a paragraph.1043. **Concrete parameters** -- numbers and measurable adjectives: speed, density,105 mouse influence radius, palette, amplitude.1064. **Constraints** -- "must run smooth on mobile", "respect reduced-motion",107 "must not hurt the readability of text on top".1085. **Placement** -- "hero background, behind the headline" or "on hover of the109 project cards".110111### Vocabulary for tuning (no API knowledge required)112113Name the sensation precisely; translate it to code:114115- **Rhythm:** slower / faster / with a pause / breathing116- **Density:** denser / sparser / finer / heavier117- **Mouse reaction:** larger influence radius / subtler / with lag (inertia) /118 pushes vs. attracts119- **Movement:** more organic / more mechanical / with noise / in a wave120- **Color:** more contrast / pull toward the background tone / glow only at center121- **Visual weight:** more discreet / more of a protagonist / must not compete122 with the text123124For shader-tier effects (distortion, generative textures, SDF), there is a125matching concept toolkit and tuning vocabulary in126[references/shaders.md](references/shaders.md).127128For the ready-to-adapt recipes (smooth scroll, scroll reveals, evolving a point129field, hover image distortion, floating 3D object) with starter prompts and the130order to tackle them, see [references/recipes.md](references/recipes.md).131132---133134## Step 2: Guardrails (apply or ask for every effect)135136Bake these in from the start to avoid rework:137138- **Client + `dynamic(() => import(...), { ssr: false })`** for any WebGL/canvas139 component -- they only exist in the browser.140- **Pause the loop offscreen** (IntersectionObserver) -- do not burn battery.141- **Respect `prefers-reduced-motion`** -- always offer the still version.142- **Cap `dpr` at 2 and drop density on mobile** -- the top cause of phone jank.143- **Comment every tunable parameter at the top** so the designer can adjust alone.144- **Hover is not touch.** If a hover *reveals essential content or a CTA*, give145 mobile an explicit **tap** path (open on tap, close on tap) with a **visible146 affordance** signalling it is interactive. Test on a real touch target -- a147 resized desktop window still has hover and hides the bug. If hover is only a148 flourish (glow, slight scale), it is fine to lose it on mobile.149150---151152## Step 3: The craft filter (your designer edge)153154This is where a designer beats a dev who knows the API but not what looks good.155Before calling an effect done, check:156157- **Easing and timing.** Ease-out for entering, ease-in for leaving, ease-in-out158 for repositioning. Never linear except progress bars and shimmer.159- **The 12 animation principles** (anticipation, follow-through, staging,160 slow-in/slow-out...). This is what separates alive from robotic.161- **Choreography.** Stagger, hierarchy of movement, what enters first and what162 follows. Composition in time.163- **When NOT to animate.** Restraint is craft. Movement that does not serve the164 content is noise. Run the removal test in165 [references/restraint.md](references/restraint.md): comment the animation out,166 look at the static version for ten seconds, and name what the user no longer167 knows. If the sentence is about you ("it feels flat") and not about them, the168 problem is the static design and motion is the wrong fix.169- **The effect must not steal from the content.** The headline wins, always.170171For the animation principles, easing as craft, and the reusable fundamentals172(lerp/damping, noise, the minimal math, the 16ms budget, motion ethics), see173[references/motion-craft.md](references/motion-craft.md).174175---176177## Step 4: Ship gate (performance, accessibility, SEO)178179Before integrating into a real page, confirm:180181- [ ] Holds 60fps (16ms/frame) on a mid mobile, not just your machine.182- [ ] Heavy libs (Three.js) lazy-loaded so the weight lands only on the page that183 uses the effect.184- [ ] `prefers-reduced-motion` path exists and is not broken.185- [ ] Real title, copy, and links live in the HTML -- canvas/3D text is invisible186 to Google and screen readers. WebGL is decoration on top.187- [ ] Mobile has a tap path for any hover that hides essential content.188- [ ] No motion on a high-frequency, low-novelty interaction (list hover, context189 menu, tab switch, row add/delete). Re-run the Step 0 gate on anything that190 grew during the build -- effects accumulate one commit at a time.191- [ ] No `transition: all` anywhere. Properties are named.192- [ ] Anything the user can toggle animates with a transition, not keyframes, so193 a second click retargets instead of being ignored.194195---196197## Pitfalls (hard-won)198199- **Server error in Next ("window is not defined").** WebGL/canvas need200 `"use client"` and usually `dynamic(..., { ssr: false })`.201- **Phone stutter.** Almost always density too high or `devicePixelRatio`202 unbounded. Cap dpr, cut particle count on mobile, pause offscreen.203- **Bloated bundle.** Three.js is hundreds of KB. Lazy-load it per page.204- **Forgotten accessibility.** Constant motion nauseates. `prefers-reduced-motion`205 is not optional in a serious site.206- **Effect competing with content.** If you strain to read the text, dial it back.207- **Content trapped in the canvas.** SEO and screen readers cannot see painted or208 3D text -- keep the real content in the DOM.209- **Hover that dies on touch.** See Step 2. The classic: a hover-revealed CTA that210 is invisible and unreachable on a phone.211212---213214## Working with other skills215216- **ui-designer** owns static visual craft and *micro-motion*: easing curves,217 hover/press/focus states, a simple fade or 50-80ms stagger on ordinary UI. When218 the motion is that small, hand back to ui-designer. This skill takes over for219 scroll-driven, canvas, WebGL, generative, or otherwise "creative-coding" motion.220- **ux-designer** owns flows, psychology, and usability. Motion in service of a221 flow decision is theirs; the effect craft is yours.222- **design-system** owns tokens and component infrastructure.223- **frontend-design** owns bold overall aesthetic direction (landing/portfolio224 look). It sets the vibe; this skill builds the movement inside it.225226When another skill fits better, say so directly.227228---229230## NEVER231232- **NEVER** ship a WebGL/canvas component without `"use client"` + `ssr: false`.233- **NEVER** leave an animation loop running while offscreen.234- **NEVER** skip `prefers-reduced-motion` -- always provide the still version.235- **NEVER** leave `dpr` unbounded or run full desktop density on mobile.236- **NEVER** hide essential content or a CTA behind hover with no touch path.237- **NEVER** put real content or links only in canvas/3D (SEO + a11y).238- **NEVER** climb to WebGL when CSS or Canvas 2D delivers the scene.239- **NEVER** integrate an effect into an approved page before it is seen running.240- **NEVER** use linear easing except progress bars and shimmer loops.241- **NEVER** animate layout properties (`width`, `height`, `top`, `left`) -- only242 `transform` and `opacity`.