1实现原理 · 为什么它能做到
实现原理是「先把静态排版定死,再谈运动」:动效救不了坏排版,所以动画之前先锁行高、字距、对齐与字重,然后才切分与动画。
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.
切分粒度只有三档(行/词/字),每档绑定情绪与适用场景,并给出「长文案按字会显得吵」的经验判断。
- **By character** — most kinetic/playful; risk of feeling busy on long copy. Reserve for short strings.
切分会破坏文本语义,因此无障碍是硬规则而非建议:容器给 aria-label 放完整字符串、所有碎片 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.
四种主力揭示法各有取舍:遮罩/裁剪上移最稳(无模糊伪影、GPU 便宜、行业标准)、模糊入更贵但柔和、clip-path 定向擦除、字符错位。
- **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.
时间参数内联给值(easeOutExpo、每碎片 400–600ms、行/词/字错位 60–100/40–70/20–40ms、总时长约 800ms 上限),使技能可独立使用而无需外部知识。
Enter with ease-out: `cubic-bezier(0.16, 1, 0.3, 1)` (easeOutExpo) feels premium.
变量字体动画要求动 font-variation-settings 而非 font-weight,并强制先确认字体确实是变量字体与轴范围,否则取值会被静默钳制。
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.
字体加载时机被当作验收前提:必须等 document.fonts.ready 之后再切分,否则冻结帧的换行会与真机不一致(配套交付契约是单文件 HTML + 一个动画驱动 + ?t=N 冻结 harness)。
Split AFTER `document.fonts.ready` so line breaks are correct in the frozen frame.
2核心能力
3外部依赖
| 类型 | 依赖 |
|---|---|
| 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 要求先确认是变量字体与轴范围 |
4风险提醒 风险提醒:蓝色 · 知晓即可
- 无安全区(title safe)规则,宽高比裁切风险自负 — 文档未提供安全区/边距规则(专项检索未定位到任何 safe-area/title-safe 条款);做竖屏短视频或被平台裁切时,字形贴近边缘可能在播放端被切掉——需自行加内边距并纳入验收。
- 验证回路依赖 npx 远程获取 Playwright 与 Chromium — SKILL.md 内联 `npx playwright screenshot`,仓库根 seek-shot.sh 为 `npx -y playwright screenshot`:首次运行安装远程包并下载浏览器二进制,版本不锁定。
- 字体与 CDN 未锁定,静态验收可能掩盖真机差异 — 产物若用网络字体/GSAP CDN,无头冻结与真机之间存在字体版本与回退差异;fonts.ready 后才切分可缓解换行问题,但 FOUC 与字体替换仍需在目标环境复看。
- 切分若不按规则实现会破坏可访问性与复制粘贴 — 这是本 skill 明确警告的固有权衡:即使文档给了 aria 方案,实际交付仍需逐件确认(完成清单第 5 条),否则屏幕阅读器会读成单字序列。
- 仓库根脚本不在 skill 目录内 — 只安装 skills/kinetic-typography 时 scripts/seek-shot.sh 引用悬空;需自行改用等价 playwright/ffmpeg 命令。
5第二遍独立确认
- [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 供无头等待。先等字体、再切分、再冻结,三段配合成立。
6结论
7defb6b40cabee55…fccc94bd32