motion-web
Motion-first creative web. The skill handles all phases: reference → concept → spec → build → audit.
This skill builds whole web pages. Motion is what makes them good; it is not the whole job. A request with no motion in it at all — "make a landing page", "help me build this official site" — is still this skill, and the deliverable is a finished site: stack, tokens, sections, copy, components, states, meta, deploy.
Priority order — 1 and 2 are co-equal:
- Motion concept and interaction choreography
- Page design — structure, type scale, palette, spacing rhythm, the thing it looks like before anything moves
- The page as a built artifact — sections and their copy, the component vocabulary, the token layer,
the states off the happy path (
page-blueprints.md,components.md,project-setup.md,production-polish.md) - Light 3D or canvas only when it strengthens the page
- Performance, accessibility, reduced-motion fallbacks
A great mechanic on a default-looking page is a failed page. Motion is the advantage, not the
excuse. The most common failure of this skill is shipping one clever interaction glued onto a layout
nobody designed — if the page would embarrass you with the motion switched off, it is not done, and
no amount of spring tuning fixes it. Design is not step 2 in time; it is a second thing that must also
be true at the end. → references/page-design.md, references/design-slop.md
This is a design-and-build skill for one class of site: creative and marketing web — landing pages,
product pages, portfolios, studio sites, campaigns, editorial, light docs. It builds them end to end.
It is not a dashboard / admin / data-dense app-UI skill, and not a full 3D-scene generator
(those route to 3d-scene-studio). A creative page containing app-shaped fragments — a pricing table, a
sign-in, a console screenshot — is in scope; a logged-in product interface is not.
Agentic Intent Detection (CRITICAL — Read This First)
The user will often say very little. Detect their intent from minimal input and act autonomously.
Signal → Intent Map
| What the user sends | Detected intent | What to do |
|---|---|---|
| "make a webpage" / "make a landing page/official site/portfolio" with a topic, no reference | full-build | The whole site, not a mechanic. page-blueprints.md → project-setup.md → page-design.md → build → components.md → production-polish.md |
| "what content goes here" / "what sections should I have" / "information architecture" / "how to write the copy" | blueprint | page-blueprints.md — pick a spine, write real copy, mark every invented fact |
| "navigation" / "button" / "form" / "card" / "footer" / "FAQ" / "pricing table" / "modal" / "component" | component | components.md — the dialect table first, then the state matrix. A component without its states is not done |
| "what tech stack" / "Astro or Next" / "how to start a project" / "design tokens" / "fonts" / "deployment" | setup | project-setup.md — page ladder ≠ motion ladder; start at rung 0 and climb |
| "looks like a demo not a finished product" / "OG preview is empty" / "no favicon" / "404" / "empty state" / "dark mode" / "form not validated" | polish | production-polish.md — all of it is checkable; run §9 rather than estimating |
| A bare URL (no other text) | url-drop | Open it and deconstruct it (Replicate Mode steps 1–2), then ask: rebuild this, or use it as the reference for something of theirs? |
| A URL + "make a webpage" or "reference this" | replicate → build | Deconstruct the URL first (Replicate Mode), then propose a motion concept for the user's own content |
| Reference + "replicate and save as a case" / "store in skill" / "make it a case study" | case-authoring | cases/AUTHORING.md — Phase 0 gate first: strip the images out of the reference; if nothing survives, settle the assets before building, not after |
| A URL + "replicate" / "make something similar" / "reference this and make one" | replicate | Deconstruct → map to patterns → build immediately. |
| A URL to a paper/article/blog | doc-drop | Read it, name the techniques with extractable values, build from one if asked (Document / Article Drop below) |
| A vague brief ("make a cool webpage" / "make a portfolio") | freeform-build | Orchestrate via composition-guide.md → choose style+arc independently |
| A topic only ("make a landing page about AI") | spec → build | Orchestrate via composition-guide.md → propose visual direction, build immediately |
| A detailed brief with references | spec → build | Write MOTION_SPEC.md → get approval → build |
| "review" / "what's wrong" / "gap" | audit | Inspect existing work for motion/perf/accessibility gaps — including the still frame, per design-slop.md |
| "doesn't look good" / "too ugly" / "looks like AI made it" / "no sense of design" / "generic" | design-audit | Screenshot with motion off and run the gates in design-slop.md. Do not tune springs — the complaint is about the still frame |
| "layout" / "typography" / "text too small" / "whitespace" / "structure" / "all sections look the same" | design | page-design.md — macrostructure, type scale, spacing rhythm, measured against current award winners |
| "add…" on existing page | incremental-build | Extend current implementation with new motion |
| A video reference (Pinterest/Dribbble/X clip) | video-ref | STOP — run the Video Reference Protocol below before writing any code |
| "feel is off" / "too stiff" / "doesn't follow the hand" / "too stable" on existing motion | handfeel-tune | Audit against handfeel.md — springs, velocity coupling, secondary motion |
| "follows the hand but missing something" / "jittery" / feel varies with frame rate on anything that follows (camera, cursor, rail, tooltip) | handfeel-tune | Not §1's spring — handfeel.md §7: 1-exp(-k·dt), the speed/k lead term, and never correcting after the filter |
| "can we avoid GSAP" / just an entrance or parallax / want something lighter | build | Check rung 1.5 first — native animation-timeline / animation-trigger / sibling-index() → build-mode.md ladder + pattern-recipes.md #16. Firefox gets the static end-state |
| The asset is a real place (photographed/scanned), one should walk into it | build | Rung 5.5 — 3D Gaussian splats before models → build-mode.md ladder |
| Card/image needs to bend, flag, page flip, pin a screenshot into a 3D plane, "skew isn't enough" | warp | Corner-pin homography → pattern-recipes.md #17. Guard every quad and clamp edge tilt to asin(h/w) — an unguarded quad paints a screen-sized block with no error |
| "can't click" / "only one is clickable" / "no one will find it" / "can't see it" on existing motion | affordance-audit | Do not touch hit-test code first. Audit against affordance.md — the mechanism is usually fine; the invitation is missing or expired |
| A pile of image assets + "make a 3D scene" / "create depth" / "camera should be able to walk in" | image-plane-3d | Do not reach for models. Build the scene from flat planes in a real perspective camera → image-plane-3d.md (ladder rung 5) |
| "feels like a collage" / "doesn't blend" / "looks pasted on" on a rendered scene | image-plane-3d | Measure before touching art: mean R−B and luminance per asset batch, contact shadows present → image-plane-3d.md §6–7 |
| "what should I use to draw this" / "DOM or canvas" / the page only outputs divs and system fonts / the reference is clearly not doable in DOM | render-layer | Determine layer first, then mechanism → render-layer.md §1. The layer is a declaration, written into the case README, verified by verify_case.py --layer |
| Hand-drawn / ink line / line-art-style 3D, "looks drawn not rendered", boil / wobbly lines / paper texture | ink-render | render-layer.md §3 — discontinuity edge detection (disable normal creases), separate static warp and dynamic boil, boil clock 11Hz against 60fps rendering |
| Raw plates / renders that still need cutting out, "cut out", "how to bring assets into the scene", "image is blurry" | asset-pipeline | Key against the image's own background, crop to the alpha bbox, script the metadata, print the per-element resolution budget → image-asset-pipeline.md |
| Any headless check; a number disagrees with what you see; "how to verify" | verify | Build the probe surface first — pinnable clocks, __seek, __hold, state exits — then measure → verification-harness.md |
| "nothing happens in this section" / "bad rhythm" / "a bunch of text appears all at once" on a scroll timeline | timeline-audit | Lay every track against one scroll axis; dead beats are coinciding plateaus, not one slow layer → timeline-orchestration.md |
| Long scroll scene with many assets; "laggy", "slow to load", "memory full", hundreds of plates | scene-streaming | Activate by screen window, slice big uploads, yield inside the scan, dispose completely → scene-streaming.md |
| Anything with sound — BGM, ambience, interaction SFX, "not enough sound effects", "ambient sound is too quiet but don't make it loud" | scene-audio | Three buses (bgm / hand / world), per-act curves, discrete events over a louder bed → scene-audio.md |
Never ask the user what mode to use. Detect it. Proceed. Only stop if the brief is truly ambiguous between two very different outputs (e.g., spec vs. immediately building).
Video Reference Protocol (Hard Rule — No Guessing)
Trigger: the reference is a video you cannot actually watch — Pinterest pin, Dribbble shot, X clip, short external link. A title or text description is NOT motion information.
- Read the thread before you conclude there is no live page. The author almost always posts the
URL in a reply, and the replies also tell you whether the piece is even a web page. Measured
2026-09-02: a previous session declared seven video references URL-less and spent its Phase 1 on
frame measurement; all seven had live sites, posted by the authors themselves, and three of
four clips in one post turned out to be Jitter / Figma Motion / Rive renders with no web
implementation at all (
cases/AUTHORING.mdPhase 1).safe-x tweet <url> --json, then resolve everyt.colink in the replies. - Never build motion from a guess. If all you extracted is a title/description, you know the topic, not the motion. Building anyway burns a full iteration — this is a documented failure mode (2026-07-06, seafood hero: guessed "orbit", actual was a rising diagonal; two rebuilds).
- Ask for 2–3 keyframes immediately. One sentence: "I can't open this video, please send me 2-3 keyframes (entry/middle/exit)."
- State the trajectory as explicit geometry before coding, and get confirmation:
- Anchor points: where the element enters / crests / exits (corners, thirds)
- Attitude: rotation follows path tangent / stays constant / lags behind
- Secondary reactions: what else moves (background shapes, lines, text) and how
- Example: "Enter bottom right → center → exit top left on a rising diagonal, fish head always points upper-left" — wrong guesses die here, not in code
- Only then map to pattern-recipes / handfeel.md and build.
A single screenshot follows the same rule: one frame gives pose, not trajectory. If the path matters, ask for more frames.
Replicate Mode
When the user sends a URL with "replicate" / "make something similar" / "can you do this effect" — deconstruct it, then build. There is no storage step; the deliverable is the page.
Replicate Execution Path
-
Open the page and read it as three layers, with whatever browser tooling is available (Claude Preview,
browser-use, Playwright): the stack (library, easing, keyframes, CSS variables — the bundle names them), the scroll choreography (which element is pinned over which band, rails and their px distance, parallax rates, scrubbed properties, entrance points — sample ~9 scroll positions and diffgetBoundingClientRectplus computed styles between them), and the WebGL layer (program count, draw calls, custom uniform names; wrapgetContextbefore page scripts run if you need the shader sources). Two scripts cover the measurable halves:scripts/measure_structure.py <url>for the static page (sections, nav, buttons, token scales, media, meta, mobile overflow) andscripts/measure_churn.py <url>for how much of the page actually moves under a real wheel. The URL must be the work itself, never a gallery listing (awwwards.com/sites/<slug>): a listing page hands you the gallery's own chrome, and six different winners come back with the same library, the same keyframes and the same font. -
Deconstruct — state what you found, and quote the numbers rather than impressions:
- "GSAP 3.12 + ScrollTrigger + Lenis;
.home-animate__wrapperis pinned between 0.25–0.50, during which.icontranslates horizontally +1545px, exit is a 0.25/0.38/0.62 three-step stagger" - "Background is native WebGL2, 14 programs, 944 draw calls, uniforms include bloomStrength/blurTexture1-5 and cloudCoverage/cloudDensity — it's UnrealBloom + volumetric clouds"
Never report "uses WebGL" off a context alone — an unsized 300×150 context with no linked program is Modernizr-style capability detection, not a scene. Count linked programs and draw calls.
- "GSAP 3.12 + ScrollTrigger + Lenis;
-
Map to pattern-recipes — find the closest recipe in
references/pattern-recipes.md -
Fill the gap — what the reference uses that we don't have in recipes, write from scratch based on extracted values
-
Build immediately — scaffold the page, run it, verify visually
-
Report — "Replicated the core motion of [site], used [X] to achieve [Y], difference from original is [Z]"
Replicate ≠ Copy
- Do: Recreate the interaction pattern, motion character, timing feel
- Don't: Copy proprietary brand colors, exact copy text, identifiable product UI
- Do: Adapt the technique to the user's own content and palette
- Note in the report what was adapted vs. what was faithful to the original
Freeform Build Mode (When User Gives Zero Direction)
When the user says "make a webpage" / "make something random" / "think of a theme yourself" or gives a simple vague topic (e.g. "make a landing page for an AI agent platform"), this is an invitation to be creative. Do NOT default to a generic template, do NOT use rigid 1-to-1 routing mapping, and do NOT ask clarification questions.
Freeform Action Path (Runtime Creative Loop — Creation Happens During Execution, Not Before)
- Choose a creative direction immediately — from the composition-guide.md style deck: pick a visual style and narrative arc. Do NOT list them and ask the user to choose; make a decision yourself.
- State your choice in one sentence — "I'm going to build a dark, cinematic landing page with a horizontal scroll narrative."
- Build the page end-to-end, following the full build path:
- page-blueprints.md → define sections and write real copy
- project-setup.md → set up tech stack (Vite + Tailwind + Framer Motion or GSAP)
- page-design.md → design tokens, layout, type scale
- Build the components → components.md
- Add motion → pattern-recipes.md, handfeel.md
- production-polish.md → favicon, OG, 404, dark mode, empty states, meta tags
- Deploy — use a free hosting platform (Vercel, Netlify) and confirm the page is live.
- Present — "I built [theme] with [style direction], here's the deployed URL and a summary of motion techniques used."
The creative loop is self-sustaining. You do not need user approval at intermediate steps. If the user later says "I don't like the color scheme" or "change the navigation style", treat it as an incremental-build and make the change.
Reference Documents
This skill is guided by a set of reference documents that define standards, patterns, and workflows.
Design & Structure
- page-design.md — Page macrostructure, type scale, spacing rhythm, color palette design
- design-slop.md — Detecting and avoiding common aesthetic failures ("AI-generated look", lazy scaling, etc.)
- page-blueprints.md — Section architecture, information design, copywriting
- components.md — Component vocabulary and state matrix (not just the happy path)
Motion & Interaction
- pattern-recipes.md — Reusable motion patterns with code examples (scroll-triggered reveals, parallax, stagger, marquee, etc.)
- handfeel.md — Spring physics, velocity coupling, secondary motion, the feel of interaction
- affordance.md — Ensuring interactive elements are discoverable and inviting
- timeline-orchestration.md — Coordinating multiple motion tracks along a scroll axis
Build & Production
- project-setup.md — Tech stack decisions, project scaffolding, design tokens, fonts, deployment
- build-mode.md — Build mode ladder (rungs 1–6), choosing between native CSS, GSAP, Framer Motion, WebGL, Three.js
- production-polish.md — Favicon, OG images, 404 page, empty states, dark mode, form validation, error boundaries, deferred loading, metadata
- verification-harness.md — Headless verification probes, pinned clocks, state testing
3D & Advanced Graphics
- image-plane-3d.md — Building 3D depth from 2D image planes, pseudo-3D from flat assets
- render-layer.md — Choosing the right rendering layer (DOM, Canvas2D, WebGL, WebGL2)
- ink-render.md — Line-art, hand-drawn, and ink-style rendering
- image-asset-pipeline.md — Image keying, cropping, resolution management
Audio & Scene Management
- scene-audio.md — BGM, ambient sound, interaction sound effects, three-bus mixing
- scene-streaming.md — Streaming large scenes (asset priorities, unloading, memory management)
Cases & Templates
- cases/AUTHORING.md — Guidelines for creating, saving, and reusing case studies from built pages
Following the Path
After detecting intent, the skill should follow the corresponding route above. Every route leads to building a complete, deployable page. The skill is designed to be autonomous — the user's initial instruction is often the only instruction needed.
Design Quality Gates
Before declaring a page complete, run the following checks (documented in design-slop.md):
- Screenshot test: Turn motion off. Does the still frame look like a designed page, not a default template?
- Type scale: Are at least four distinct text sizes used? Are headings proportional and scannable?
- Rhythm: Is spacing consistent (multiples of a base unit)? Are sections visually separated by whitespace or horizontal rules?
- Color: Are there more than two neutrals? Is the palette limited to 3–5 primary hues?
- Awareness test: Could a visitor unfamiliar with the page immediately identify the primary call to action?
- Motion sensitivity: Is there a
prefers-reduced-motionfallback? Do animations degrade gracefully? - Responsiveness: Does the page function on 320px width? Does any element overflow horizontally?
- Loading state: Is there a skeleton, placeholder, or entered animation before content appears?
Common Failure Modes
| Failure mode | Symptom | Fix |
|---|---|---|
| Motion glued onto a default layout | The page looks bad with motion off — weak layout, default Tailwind type scale, no visual hierarchy | Follow page-design.md first — design and motion are co-equal |
| Over-specified interaction | One clever scroll interaction on an otherwise generic page; motion is the only interesting thing | Treat design as a separate deliverable, with its own review before motion polish |
| Guessing motion from text | Building a scroll animation from a title description instead of keyframes or a video | Always follow the Video Reference Protocol — ask for keyframes, never guess |
| Wrong render layer | Implementing in DOM what should be done in Canvas or WebGL (or vice versa) | Layer determination before mechanism → render-layer.md §1 |
| Ignoring non-happy-path states | Buttons have no hover/focus/active states; forms have no error/validation; empty states are missing | components.md state matrix is mandatory — a component without its states is not done |
| Skipping production polish | No favicon, OG image is empty, 404 page is the browser default, no dark mode | production-polish.md — all of it is checkable; run §9 rather than estimating |
Decision Tree Summary
User sends input
↓
Is it a video reference? → YES → Run Video Reference Protocol
↓ NO
Is it a URL with "replicate"? → YES → Run Replicate Mode
↓ NO
Is it a URL alone? → YES → deconstruct, then ask: rebuild or reference?
↓ NO
Is it a detailed brief? → YES → Write MOTION_SPEC.md → get approval → build
↓ NO
Is it a vague topic or zero direction? → YES → Run Freeform Build Mode
↓ NO
Is it a technical audit or tune? → YES → Route to the corresponding intent path
↓
Detect from signal map → Proceed without asking for mode
Last updated: 2026-10-15