- name
- motion-web
- description
- Design and build motion-first creative websites — page design (structure, type scale, palette, spacing) plus interaction choreography: scroll animation, Framer Motion, GSAP, and light 3D via Three.js/R3F. Use for animated landing pages, creative portfolios, product showcases, WebGL-lite scenes, and motion audits. Also use when tuning interaction handfeel (手感差/太生硬/不跟手), replicating motion from a video or URL reference (复刻), building 3D depth from flat image assets (伪3D/抠图), diagnosing dead scroll-timeline stretches, mixing scene audio, auditing discoverability (点不开/没人会发现), building headless verification probes, or fixing a page that moves well but looks generated (不好看/像AI做的/没设计感). Equally for building a whole site from nothing (从0到1做个网页/落地页/官网/作品集): stack choice, sections and copy, components (导航/hero/表单/卡片/定价表), and production polish (favicon/OG/404/空状态/暗色模式). Not for dashboards, admin UI, or full 3D scene generation.
# 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 — "做个落地页", "帮我把这个官网做出来" — 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:**
1. Motion concept and interaction choreography
2. **Page design** — structure, type scale, palette, spacing rhythm, the thing it looks like before anything moves
3. **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`)
4. Light 3D or canvas only when it strengthens the page
5. 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 |
|---|---|---|
| "做个网页" / "做个落地页/官网/作品集" with a topic, no reference | `full-build` | **The whole site, not a mechanic.** [page-blueprints.md](./references/page-blueprints.md) → [project-setup.md](./references/project-setup.md) → [page-design.md](./references/page-design.md) → build → [components.md](./references/components.md) → [production-polish.md](./references/production-polish.md) |
| "这页要放什么" / "该有哪些 section" / "信息架构" / "文案怎么写" | `blueprint` | [page-blueprints.md](./references/page-blueprints.md) — pick a spine, write real copy, mark every invented fact |
| "导航" / "按钮" / "表单" / "卡片" / "footer" / "FAQ" / "定价表" / "弹窗" / "组件" | `component` | [components.md](./references/components.md) — the dialect table first, then the state matrix. A component without its states is not done |
| "用什么技术栈" / "Astro 还是 Next" / "怎么起项目" / "design token" / "字体" / "部署" | `setup` | [project-setup.md](./references/project-setup.md) — page ladder ≠ motion ladder; start at rung 0 and climb |
| "像 demo 不像成品" / "OG 预览是空的" / "没有 favicon" / "404" / "空状态" / "暗色模式" / "表单没校验" | `polish` | [production-polish.md](./references/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 + "做个网页" or "参考这个" | `replicate → build` | Deconstruct the URL first (Replicate Mode), then propose a motion concept for the user's own content |
| 参考 + "复刻出来并收录成 case" / "存进 skill" / "做成案例" | `case-authoring` | [cases/AUTHORING.md](./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` | **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 ("做个很酷的网页" / "做个 portfolio") | `freeform-build` | Orchestrate via [composition-guide.md](./references/composition-guide.md) → choose style+arc independently |
| A topic only ("做一个关于 AI 的落地页") | `spec → build` | Orchestrate via [composition-guide.md](./references/composition-guide.md) → propose visual direction, build immediately |
| A detailed brief with references | `spec → build` | Write MOTION_SPEC.md → get approval → build |
| "审查" / "有什么问题" / "gap" | `audit` | Inspect existing work for motion/perf/accessibility gaps — **including the still frame**, per [design-slop.md](./references/design-slop.md) |
| "不好看" / "太丑" / "像 AI 做的" / "没设计感" / "普通" | `design-audit` | Screenshot with motion **off** and run the gates in [design-slop.md](./references/design-slop.md). Do not tune springs — the complaint is about the still frame |
| "版式" / "排版" / "字太小" / "留白" / "结构" / "section 都长一样" | `design` | [page-design.md](./references/page-design.md) — macrostructure, type scale, spacing rhythm, measured against current award winners |
| "加上…" 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** |
| "手感差" / "太生硬" / "不跟手" / "四平八稳" on existing motion | `handfeel-tune` | Audit against [handfeel.md](./references/handfeel.md) — springs, velocity coupling, secondary motion |
| "跟手但总差一点" / "一抖一抖" / 手感随帧率变 on anything that **follows** (camera, cursor, rail, tooltip) | `handfeel-tune` | Not §1's spring — [handfeel.md](./references/handfeel.md) §7: `1-exp(-k·dt)`, the `speed/k` lead term, and never correcting after the filter |
| "能不能不用 GSAP" / 只是个入场或视差 / 想要更轻 | `build` | Check rung **1.5** first — native `animation-timeline` / `animation-trigger` / `sibling-index()` → [build-mode.md](./references/build-mode.md) ladder + [pattern-recipes.md](./references/pattern-recipes.md) #16. Firefox gets the static end-state |
| 素材是一个**真实存在的地方**(实拍/扫描),要走进去 | `build` | Rung **5.5** — 3D Gaussian splats before models → [build-mode.md](./references/build-mode.md) ladder |
| 卡片/图片要**弯折**、旗帜、翻页、把截图钉进立体面、"skew 不够用" | `warp` | Corner-pin homography → [pattern-recipes.md](./references/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 |
| "点不开" / "只有一个能点" / "没人会发现" / "看不到" on existing motion | `affordance-audit` | **Do not touch hit-test code first.** Audit against [affordance.md](./references/affordance.md) — the mechanism is usually fine; the invitation is missing or expired |
| A pile of **image assets** + "做成一个 3D 场景" / "要有纵深" / "camera 要能走进去" | `image-plane-3d` | **Do not reach for models.** Build the scene from flat planes in a real perspective camera → [image-plane-3d.md](./references/image-plane-3d.md) (ladder rung 5) |
| "有拼接感" / "没融进去" / "像贴上去的" 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](./references/image-plane-3d.md) §6–7 |
| "这个该用什么画" / "DOM 还是 canvas" / 页面只会输出 div 和系统字体 / 参考明显不是 DOM 能做的 | `render-layer` | **先定层再定机制** → [render-layer.md](./references/render-layer.md) §1。层是一个声明,写进 case README,由 `verify_case.py --layer` 核对 |
| 手绘 / 墨线 / 描边风的 3D,"像画出来的不像渲出来的",boil / 抖线 / 纸纹 | `ink-render` | [render-layer.md](./references/render-layer.md) §3 — 深度不连续描边(法线折痕关掉)、静态 warp 与动态 boil 分离、boil 时钟 11Hz 对 60fps 渲染 |
| Raw plates / renders that still need cutting out, "抠图", "素材怎么进场景", "图糊了" | `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](./references/image-asset-pipeline.md) |
| Any headless check; a number disagrees with what you see; "怎么验" | `verify` | Build the probe surface first — pinnable clocks, `__seek`, `__hold`, state exits — then measure → [verification-harness.md](./references/verification-harness.md) |
| "这一段什么都没发生" / "节奏不好" / "一堆字一下就出来了" 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](./references/timeline-orchestration.md) |
| Long scroll scene with many assets; "卡", "加载慢", "内存爆了", hundreds of plates | `scene-streaming` | Activate by screen window, slice big uploads, yield inside the scan, dispose completely → [scene-streaming.md](./references/scene-streaming.md) |
| Anything with sound — BGM, ambience, interaction SFX, "音效太少", "氛围音听不清但也别吵" | `scene-audio` | Three buses (bgm / hand / world), per-act curves, discrete events over a louder bed → [scene-audio.md](./references/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 (硬规则 — 不许猜)
**Trigger: the reference is a video you cannot actually watch** — Pinterest pin, Dribbble shot, X clip, 站外短链. A title or text description is NOT motion information.
0. **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.md` Phase 1). `safe-x tweet <url> --json`, then resolve
every `t.co` link in the replies.
1. **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).
2. **Ask for 2–3 keyframes immediately.** One sentence: "这个视频我打不开,截 2-3 帧关键画面(入场/中间/离场)发我"。
3. **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: "右下入场 → 中心 → 左上离场的上升对角线,鱼头恒定朝左上" — wrong guesses die here, not in code
4. 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 "复刻" / "做一个类似的" / "能不能做这种效果" — deconstruct it, then build. There is no storage step; the deliverable is the page.
### Replicate Execution Path
1. **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 diff `getBoundingClientRect` plus computed styles between them), and the **WebGL layer** (program
count, draw calls, custom uniform names; wrap `getContext` before 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) and
`scripts/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.
2. **Deconstruct** — state what you found, and quote the numbers rather than impressions:
- "GSAP 3.12 + ScrollTrigger + Lenis;`.home-animate__wrapper` 在 0.25–0.50 被 pin 住,
期间 `.icon` 横移 +1545px,出场是 0.25/0.38/0.62 三段 stagger"
- "背景是原生 WebGL2,14 个 program、944 draw calls,uniform 里有 bloomStrength/blurTexture1-5
和 cloudCoverage/cloudDensity —— 是 UnrealBloom + 体积云"
**Never report "用了 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.
3. **Map to pattern-recipes** — find the closest recipe in `references/pattern-recipes.md`
4. **Fill the gap** — what the reference uses that we don't have in recipes, write from scratch based on extracted values
5. **Build immediately** — scaffold the page, run it, verify visually
6. **Report** — "复刻了 [site] 的核心动效,用了 [X] 实现 [Y],和原版差异是 [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 "做个网页" / "随便做" / "自己想一个主题" or gives a simple vague topic (e.g. "做一个AI agent平台落地页"), 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 — 创造发生在执行中,不在文档里)
The user should NEVER need to supply a reference. But novelty also does NOT come
from reading these docs — docs are constraints and physics, not answers.
Novelty comes from **fresh inputs sampled at runtime + a build-test-kill loop
where you are your own critic**. Execute:
1. **Sample the present** (runtime input, not memory): open this month's
Awwwards SOTD / Godly / SiteInspire listings and look at 3–5 of the winning
pages themselves — the work, never the gallery page. You're not copying;
you're locating the current frontier so you can land past it. 2 minutes.
Look at **structure and type scale**, not only the effect — that is the half
that decides whether the page reads as current (`page-design.md` §1).
2. **Invent 3 candidate mechanics** from the topic's own physics via the
generative operators (composition-guide §5). Kill any candidate that
resembles the graveyard OR anything you just saw in step 1.
3. **Sketch before committing**: build the signature interaction as a minimal
single-file prototype (one div, one rAF loop, fake content, <15 min).
Not the page — just the mechanic.
4. **Test it on yourself**: run it and drive it with the currently available
browser tooling — Claude Preview (`preview_start` → `preview_eval`/`preview_click` →
`preview_screenshot`) first, `browser-use` as fallback — mouse sweeps, wheel
flicks, screenshots at extremes, then look at the evidence. Ask:
会不会玩 10 秒就腻? 截两帧给人看,能不能猜出交互规则? If it fails — mutate the
operator or pick the next candidate. Do not ask the user to be your eyes.
5. **Design the page — as a separate act, before the mechanic goes into it.**
Not "pick a palette and start coding". Three outputs, in order:
(a) the **blueprint and the real copy** → `references/page-blueprints.md` — which
sections exist and what they actually say; (b) the **macrostructure, type scale
and spacing rhythm** → `references/page-design.md`, with concrete values in
`data/visual-bank.json`; (c) the **token layer and scales** →
`references/project-setup.md` §2–§5. The mechanic then gets placed *into* a page
that already works, which is the opposite order from the one that produces
「一个破动效贴在没设计的页面上」.
6. **Build it**, components and their state matrices from `references/components.md`,
springs from `references/motion-tokens.md`, full-page linkage per handfeel.md.
7. **Design gate — run this before you show anything.** Screenshot the page with
Ver en GitHub