kinetic-typography
This skill should be used when the user asks to "animate a headline", "make a kinetic typography video", "do a split-text reveal", "stagger text by character/word/line", "make a lyric or caption video", "animate a variable font weight", "put text on a path", or "create an animated title card". Covers reveal techniques in CSS, GSAP SplitText, Framer Motion, and Remotion.
1How It Works & Mechanism
The core implementation principle is "lock down static typography first, then discuss motion": motion cannot rescue bad typography, so line-height, letter-spacing, alignment, and font-weight must be locked before splitting and animating.
Motion cannot rescue bad type. Before animating, lock line-height (1.1-1.2 for display headlines, 1.4-1.6 for body), tracking (tighten display by -1% to -3%, e.g. `letter-spacing: -0.02em`), alignment, and weight. Then split and animate.
Splitting granularity is strictly divided into three tiers (line/word/character), each bound to specific emotions and use cases, accompanied by the empirical rule that "splitting long copy by character feels noisy."
- **By character** — most kinetic/playful; risk of feeling busy on long copy. Reserve for short strings.
Splitting destroys text semantics, making accessibility a hard rule rather than a suggestion: provide the container with an aria-label containing the full string, and mark all split fragments as aria-hidden.
Critical accessibility note: splitting into per-character spans destroys the text for screen readers and breaks copy-paste. Always set `aria-label` on the container with the full string and `aria-hidden="true"` on the split fragments.
Four primary reveal methods offer distinct trade-offs: mask/crop slide-up is the most stable (no blur artifacts, GPU-cheap, industry standard), blur-in is costlier but softer, clip-path directional wipe, and character stagger.
- **Mask / clip reveal (most robust)** — wrap each line in `overflow: hidden`; animate the child from `translateY(100%)` to `0`. The text wipes up from a hidden baseline. No blur artifacts, GPU-cheap, the industry-standard headline reveal.
Timing parameters are inlined with concrete values (easeOutExpo, 400–600ms per fragment, 60–100/40–70/20–40ms stagger for line/word/char, capped at ~800ms total duration), making the skill self-contained without requiring external knowledge.
Enter with ease-out: `cubic-bezier(0.16, 1, 0.3, 1)` (easeOutExpo) feels premium.
Variable font animation requires animating font-variation-settings rather than font-weight, mandating an upfront check to ensure the font is truly a variable font and within axis ranges to prevent values from being silently clamped.
Animate `font-variation-settings` (covers any axis: `wght`, `wdth`, `slnt`, `opsz`, plus custom axes), not `font-weight`, to hit non-standard values and to interpolate smoothly.
Font loading timing is treated as an acceptance prerequisite: splitting must occur only after document.fonts.ready, otherwise frozen frame line breaks will diverge from real devices (supported by the delivery contract of a single-file HTML + single animation driver + ?t=N frozen harness).
Split AFTER `document.fonts.ready` so line breaks are correct in the frozen frame.
2Core Capabilities
3External Dependencies
| Kind | Dependency / Endpoint |
|---|---|
| cli | npx playwright screenshot(验证回路:截 file:// 页面冻结帧) |
| cli | 仓库根共享脚本 scripts/seek-shot.sh、scripts/contact-sheet.sh(截图与接触表拼图;不在 skill 目录内) |
| package | 前端动画生态(按技法选用):SplitType / GSAP SplitText、Framer Motion、Remotion |
| network | 产物期引用:输出契约允许用一条 CDN 的 GSAP <script>;仓库根演示页 showcase.html 另引 Google Fonts 与 cdnjs 的 gsap |
| package | 字体:变量字体(如 Inter var)与示例字体家族——产物期由浏览器加载,且 SKILL.md 要求先确认是变量字体与轴范围 |
4Recommended Governance & Evidence
- scripts/: Local script or command execution: (Per SKILL.md instruction) npx playwright screenshot --wait-for-timeout=500 "file://$PWD/
- 网络端点: Declared external network access: No network call code within the skill directory; execution-time network surface is limited to tool fetching by `npx playwright` (npm registry + Chromium binaries)
- 本地工作目录: File read/write and artifact output: Core deliverable: single type.html (created by the agent according to the output contract)
5Second-Pass Verification
- [ok] 「skill 目录内无脚本」是否成立(蓝档的关键前提) — 文件清单实证:目录内只有 SKILL.md、README.md(0 B)、references/reveal-recipes.md。SKILL.md 引用的 scripts/seek-shot.sh 与 scripts/contact-sheet.sh 属仓库根资产,已在 reason/risks 记录为「单装 skill 目录会悬空」。
- [ok] 凭证/环境变量读取是否存在 — 本仓全仓 `process.env|API_KEY|TOKEN|SECRET|Authorization` 零命中;credential_reads 为空成立。
- [ok] 是否有更高的触发条件被漏掉(红档特征) — `sandbox|automationcontrolled|no-verify|stealth|bypass|ignoreHTTPSErrors|dangerously` 全仓零命中;产物是浏览器沙箱内的 CSS/SVG 动画,无任意代码执行面。
- [unlocatable] 任务提示的「安全区(title safe)规则」是否能定位 — 对 skill 目录与全仓检索 `safe[- ]area|title safe|overscan|margin` 均未发现「安全区/标题安全」类版式规则;文档里的版式规则只有:静态排版前置(行高/字距/对齐/字重)、切分后的 aria 补偿,以及「文字不压脸与关键物体」这类通用要求与「裁切字形/descender」验收项。故不把它写成 capability,仅记录为「任务提示与源码不符:本 skill 无安全区规则」;竖屏或平台裁切场景需使用者自行加边距。
- [ok] 无障碍声明是否有可执行形态(非口号) — SKILL.md 要求容器 aria-label + 碎片 aria-hidden,完成清单第 5 条写成验收项;reveal-recipes.md 第 1 节的 HTML 已按此写(<span class="line"><span aria-hidden="true">Built for</span></span>),并在开头声明 'Accessibility rule for every per-fragment split'。属可照抄实现。
- [ok] 时间参数与「单一动画驱动」是否自洽 — SKILL.md 内联给出 easeOutExpo、400–600ms、行/词/字错位区间与约 800ms 上限;输出契约要求「CSS @keyframes 或单条 GSAP timeline,不能两者并存」,harness 也对两种驱动给分支写法(负延迟暂停 / tl.pause()+seek),无相互矛盾。
- [ok] 「字体就绪后再切分」是否真能解决冻结帧换行问题 — SKILL.md 写 'Split AFTER `document.fonts.ready` so line breaks are correct in the frozen frame.';冻结 harness 在 ?t=N 时把动画钉到负延迟 + paused 并置 window.__ready 供无头等待。先等字体、再切分、再冻结,三段配合成立。
6Verdict & Scenarios
7defb6b40cabee55…