关于 css-animation
用于制作自包含 HTML/CSS 动画的技能,可复现应用功能,服务于产品演示、引导和营销。流程涵盖调研、访谈、生成与审核,并支持功能演示和轮播两种形式。
主要功能
- 01在 Chrome 中调研应用视觉
- 02功能演示与轮播形式
- 03桌面和移动端输出尺寸
- 04生成简报与 HTML 动画
- 05迭代审核与调整
适用场景
- 01演示应用功能的状态变化
- 02制作多屏产品演示
- 03准备桌面或移动端引导动画
MCP 相关
该技能在调研阶段需要 Claude-in-Chrome MCP 工具,用于检查目标应用并提取视觉细节。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ neonwatty/ css-animation-skill --skill css-animation安装后在 Claude Code 中输入/css-animation确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
LICENSECNAMEREADME.mdindex.htmldocs/plans/2026-02-26-css-animation-skill-design.md2026-02-26-css-animation-skill-implementation.mdexamples/seatify-optimize-brief.mdseatify-rsvp-brief.mdseatify-rsvp.htmlseatify-optimize.htmlseatify-walkthrough.html详细介绍
CSS 动画演示技能
你将创建精致、独立的 HTML/CSS 动画,模拟真实应用功能。这些动画用于功能演示、新手引导和营销。它们不是 GIF——不受分辨率限制、文件体积小,而且易于迭代。
两种动画风格
- 功能演示 — 操作前 → 执行操作 → 操作后。展示单个功能的变化(例如,点击“优化”,观察座位重新排列)。
- 轮播 — 多视图。通过交叉淡入淡出过渡,循环展示多个应用界面(例如,仪表板 → 嘉宾名单 → 画布 → RSVP)。
在访谈阶段确定用户需要哪种风格。
阶段
Phase 1: Research → Phase 2: Interview → Phase 3: Generate → Phase 4: Review Loop
阶段 1:调研
在生成任何内容之前,通过 Chrome 浏览目标应用,深入了解其视觉系统。
前提条件
- 必须能够使用 Claude-in-Chrome MCP 工具
- 必须能在浏览器中访问目标应用(本地运行或已部署)
步骤 1:设置 Chrome
- 调用
tabs_context_mcp检查现有标签页 - 创建一个新的专用标签页:
tabs_create_mcp - 保存此标签页 ID——后续所有浏览器操作都专门使用此标签页
步骤 2:导航并探索
- 导航到目标应用 URL
- 如果需要身份验证,请让用户手动登录,然后继续
- 如果目标是移动端或同时面向移动端和桌面端: 在导航到相应功能前,使用
resize_window将浏览器调整为移动视口(390×844px)。这样可以确保你调研的是应用实际的移动端布局,而不是被压缩的桌面版。如果目标是同时面向移动端和桌面端,先在全尺寸下调研桌面版,然后调整为移动视口并重新提取移动端布局。 - 导航到要制作动画的具体功能/页面
- 截取探索性屏幕截图,以了解布局
步骤 3:提取设计语言
使用 read_page、find 和 javascript_tool 提取:
- 颜色:背景、表面、边框、强调色/主色、文本、弱化文本
// Example: extract computed styles const body = getComputedStyle(document.body); JSON.stringify({ bg: body.backgroundColor, color: body.color, fontFamily: body.fontFamily }) - 字体:标题字体系列、正文字体系列、使用的字重
- 间距:内边距、外边距、圆角值
- 组件样式:按钮、卡片、徽章、头像、侧边栏面板
将这些记录为 CSS 自定义属性(例如,--bg: #0f0f0f)。
步骤 4:映射布局几何结构
针对要制作动画的具体功能:
- 容器尺寸:主要容器的宽度、高度和位置
- 元素位置:关键元素的绝对坐标
- 元素关系:哪些元素包含在其他元素中、z-index 层叠顺序
- 圆形元素:中心点和半径
- 矩形元素:原点(左上角)、宽度、高度
使用 javascript_tool 提取精确位置:
const el = document.querySelector('.selector');
const rect = el.getBoundingClientRect();
`${rect.left}, ${rect.top}, ${rect.width}, ${rect.height}`
步骤 5:截取关键状态的屏幕截图
截取以下状态的屏幕截图:
- 功能的默认/初始状态
- 所有中间状态(悬停、加载、处理中)
- 功能操作完成后的最终/结果状态
这些屏幕截图将作为生成动画的视觉参考。
阶段 2:访谈
向用户提出有针对性的问题,以确定要制作什么动画。每次使用 AskUserQuestion 提出一个问题,并提供多个选项。
问题 1:动画风格
"What style of animation should this be?"
- Feature Demo (Recommended): Before → Action → After. Shows one feature transformation.
- Carousel: Cycles through multiple app views with cross-fade transitions.
问题 2:目标尺寸
"What size should the animation target?"
- Desktop only (960×620px) — for landing pages, marketing, desktop walkthroughs
- Mobile only (360×640px) — for in-app tour tooltips, mobile onboarding
- Both — generates two files from the same brief, one per viewport
选择移动端或两者时:
- 移动端版本使用 360×640px 的画布(纵向,符合常见手机视口)
- 简化布局:减少元素数量(最多 8–12 个),适当放大元素,不使用侧边栏
- 移除不适合小屏幕的元素(宽工具栏、多列布局)
- 优先采用纵向排列,而非横向布局
- 相对于画布增大字号(正文至少 11px,标题 14px)
- 文件命名:
<app>-<feature>.html(桌面端),<app>-<feature>-mobile.html(移动端)
问题 3:功能识别
"What specific feature or flow should the animation show?"
- [Options based on research phase findings]
- Other (user describes)
问题 4:关键展示时刻
"What's the key moment — the visual 'wow' of this animation?"
- [Options relevant to the chosen feature]
- Other
问题 5:重点强调
"Is there anything specific to emphasize or avoid showing?"
- Show everything as-is
- Emphasize specific elements (user specifies)
- Hide certain elements (user specifies)
问题 6:输出位置
"Where should I save the animation files?"
- Current directory: [show cwd path]
- Desktop
- Other (user specifies path)
提出 3–6 个问题后停止——只要获得足够的信息来生成内容即可。不要过度访谈。
阶段 3:生成
此阶段会生成两个产物:一份简报(Markdown)和一个 HTML 动画文件。
3a:生成简报
编写一份结构化的 Markdown 文档,记录生成或重新生成动画所需的一切内容。将文件保存为用户所选目录中的 <app>-<feature>-brief.md。
简报格式:
---
app: <App Name>
feature: <Feature Name>
style: feature-demo | carousel
target: desktop | mobile | both
output_file: <app>-<feature>.html
output_file_mobile: <app>-<feature>-mobile.html # only when target is mobile or both
---
# Design Language
- Background: <hex>
- Surface: <hex>
- Border: <hex>
- Accent: <hex> (<name>)
- Text: <hex>
- Text dim: <hex>
- Heading font: <font> (serif/sans-serif)
- Body font: <font> (sans-serif)
- Border radius: <N>px
- Additional colors: <name>: <hex> (for groups, statuses, categories, etc.)
# Layout (Desktop)
- Stage: 960x620px
- [Container hierarchy description]
- [Element positions with exact pixel coordinates]
- [Circular elements: center point (x,y), radius R]
- [Rectangular containers: origin (x,y), width, height]
- [Item sizing: WxH px]
# Layout (Mobile)
- Stage: 360x640px
- [Simplified container hierarchy — no sidebars, single-column]
- [Reduced element count: 8–12 elements max]
- [Element positions recalculated for smaller stage]
- [Larger relative element sizing: e.g., 36x36px avatars instead of 30x30px]
- [Elements or sections omitted from desktop version and why]
# Animation Plan
## Style: Before → Action → After
(or: ## Style: Carousel with N scenes)
### Before State
- [Element positions, visual state, text content]
- [For circular layouts: N items, angular spacing, starting angle]
### Action (feature-demo only)
- [User action: cursor movement, button click]
- [Intermediate states: loading, processing]
### After State
- [New positions, trigonometrically calculated for circles]
- [Visual changes: colors, borders, labels, badges]
- [Text content changes]
### Scene N (carousel only)
- [What's visible in this scene]
- [Entry animations for elements]
- [Duration and transition to next scene]
### Timing
- Total loop: <N>s
- [Phase-by-phase durations]
- Easing: cubic-bezier(0.34, 1.56, 0.64, 1) for spring motion
- Easing: ease-in-out for fades
先向用户展示简报,再生成 HTML:
"Does this brief capture the animation correctly?"
- Yes, generate the animation
- Needs adjustments (user specifies)
反复完善简报,直到用户批准,然后继续执行 3b。
3b:生成 HTML/CSS 动画
以简报为规范,生成一个独立的 HTML 文件。将文件保存为用户所选目录中的 <app>-<feature>.html。
文件结构
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><App> – <Feature> Animation</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=...');
/* ALL CSS here — no external stylesheets */
</style>
</head>
<body>
<div class="stage" id="stage">
</div>
<script>
// Minimal JS: setTimeout loop controller + class toggling ONLY
</script>
</body>
</html>
技术规则(必须遵守)
1. 圆形布局使用三角函数定位。
绝不要凭感觉估算圆上的位置。务必计算:
left = centerX + R * cos(angle_radians) - (elementWidth / 2)
top = centerY + R * sin(angle_radians) - (elementHeight / 2)
其中:
R= 容器的可见半径 + (元素尺寸 / 2),使元素的内边缘与容器周边相接- 对于均匀分布的 N 个项目:
angle_i = startAngle + i * (2 * PI / N),从-PI/2(顶部中心)开始 - 将角度转换为弧度:
radians = degrees * PI / 180
例如,在圆上放置 7 个项目,圆心为 (140, 160),R=95,项目尺寸为 30x30px:
Item 0: angle = -90° → left = 140 + 95*cos(-90°) - 15 = 125, top = 160 + 95*sin(-90°) - 15 = 50
Item 1: angle = -38.6° → left = 140 + 95*cos(-38.6°) - 15 = 199, top = 160 + 95*sin(-38.6°) - 15 = 86
...etc for all N items
2. 矩形边缘定位。
沿矩形边缘放置项目时,均匀分布:
- 上边缘/下边缘:以相等间隔改变 X,Y 为边缘 ± (元素高度 / 2)
- X 间距:
containerLeft + containerWidth * (i + 1) / (numItemsOnEdge + 1) - 左边缘/右边缘:采用相同逻辑,改变 Y
3. 独立 HTML。 除 Google Fonts @import 外,不使用外部依赖。所有 CSS 放在 <style> 中,所有 JS 放在 <script> 中。无需构建步骤。
4. 使用 CSS 过渡实现元素移动。
.element {
position: absolute;
transition: left 1.2s cubic-bezier(0.34, 1.56, 0.64, 1),
top 1.2s cubic-bezier(0.34, 1.56, 0.64, 1);
}
5. JS 仅用于控制循环和切换类。
重要:绝不要在 JS 重置/更新函数中使用内联样式(element.style.opacity = '1')。内联样式会覆盖 CSS 类规则,导致状态错误(例如,“隐藏”的元素因为内联样式优先于 CSS 类而仍然可见)。只能通过切换类来控制。
const stage = document.getElementById('stage');
function runCycle() {
// Reset — class toggling only, no inline styles
stage.classList.remove('clicking', 'processing', 'optimized', 'complete');
// Reset text content to before-state values
setTimeout(() => stage.classList.add('clicking'), 500);
setTimeout(() => {
stage.classList.remove('clicking');
stage.classList.add('processing');
}, 900);
setTimeout(() => {
stage.classList.remove('processing');
stage.classList.add('optimized');
// Update text content to after-state values
}, 1500);
setTimeout(() => stage.classList.add('complete'), 3000);
setTimeout(runCycle, 6000); // Loop
}
setTimeout(runCycle, 300);
默认使用较快的时间设置。 用户几乎总是希望动画比你最初设想的更快。请从轻快的默认值开始:
- 变换前状态停留:0.3–0.5s(刚好足以让人看清)
- 元素间的交错间隔:0.3–0.5s
- 变换后状态停留:2–3s
- 循环总时长:5–8s
- 时间设置会在阶段 4 中反复调整——先从快速开始,只有在用户要求时才放慢。
6. 非交互动画使用 CSS @keyframes ——例如光标移动、徽章进入、旋转器旋转。对相关元素使用 animation 属性。
7. 使用 transition-delay 错开过渡,让单个元素之间相隔 0.04–0.08s,以实现自然的连续移动效果。
8. 根据目标设置舞台尺寸。
- 桌面端: 960×620px,
border-radius: 12px - 移动端: 360×640px,
border-radius: 16px(纵向) - 始终与应用的设计语言(深色/浅色主题、颜色)保持一致。根据应用在该视口下的实际布局调整比例。
9. 隐藏元素必须同时使用 visibility: hidden 和 opacity: 0。 在深色背景上,JPEG 截图压缩会让 opacity: 0 的元素产生可见伪影——看起来像淡淡的残影。务必同时使用:
.element-hidden {
opacity: 0;
visibility: hidden;
transition: opacity 0.5s ease-out, visibility 0s 0.5s; /* visibility delays on hide */
}
.element-hidden.visible {
opacity: 1;
visibility: visible;
transition: opacity 0.5s ease-out, visibility 0s 0s; /* visibility instant on show */
}
对于隐藏时应完全退出布局流的元素(例如占位文本),请通过父级类切换使用 display: none:
.stage.active .placeholder { display: none; }
10. 验证内容是否适合舞台。 生成后,在进入审阅循环之前,注入 JS 检查所有内容是否都在舞台边界内:
var content = document.querySelector('.content');
var stage = document.getElementById('stage');
JSON.stringify({ stageH: stage.offsetHeight, contentH: content.scrollHeight, fits: content.scrollHeight <= stage.offsetHeight - content.offsetTop })
如果内容溢出,应压缩间距(减小内边距、外边距和字号)或增加舞台高度,然后再继续审阅。不要把审阅轮次浪费在溢出问题上。
轮播动画专属规则
- 每个场景使用
opacity关键帧来显示/隐藏(淡入 → 停留 → 淡出) - 每个场景中的子元素使用
animation-delay错开入场 - 循环总时长 = 所有场景的时长之和 + 过渡间隔
- 使用带百分比时间的
@keyframes控制场景可见性 - 每个场景都是一个容器
div,设置position: absolute; inset: 0;
功能演示动画专属规则
- 默认 CSS 为所有元素定义“之前”位置
- 转换后的状态位置放在
.stage.optimized .element { left: ...; top: ...; }下 - JS 类切换(
stage.classList.add('optimized'))触发 CSS 过渡 - 包含:动画光标(CSS 关键帧)、点击闪光效果、处理旋转指示器叠加层
- 包含:转换后动画显示的完成徽章
- 包含:通过
setTimeout链中的 JS 更新文本内容(计数器、标签)
移动端专属规则
生成移动端动画(360×640px 舞台)时:
- 大幅简化。 展示功能的核心,而不是每个 UI 元素。桌面动画可能会展示完整工具栏 + 侧边栏 + 画布;移动端版本只展示核心交互。
- 最多 8–12 个元素。 小尺寸舞台很快就会显得杂乱。先删减装饰元素,再删减次要 UI。
- 不使用动画光标。 移动端使用触控——在点击位置用短暂的圆形脉冲替代光标动画。
- 相对尺寸更大。 元素相对于舞台的比例应更大。如果桌面端在 960px 舞台上使用 30×30px 头像(3.1%),移动端在 360px 舞台上应使用 36×36px 头像(10%)。
- 采用单列布局。 不使用侧边栏。垂直堆叠内容。
- 操作锚定在底部。 按钮和 CTA 放在舞台底部,符合移动应用的惯例。
- 空间不足时跳过导航栏。 动画不必重现完整应用界面——专注于功能区域。
从单个简介生成两个变体时:
- 首先生成桌面版(
<app>-<feature>.html) - 然后将移动版(
<app>-<feature>-mobile.html)生成为单独文件 - 移动版是针对较小舞台专门重新设计的版本,而非缩小后的副本
- 两个文件使用相同的设计语言(颜色、字体),但布局相互独立
- 在第 4 阶段分别审核每个变体
第 4 阶段:审核循环
这是核心质量保障机制。生成动画 HTML 后,进入迭代审核循环,直到用户批准。
步骤 1:在本地提供动画
- 检查是否已有 Python HTTP 服务在运行:
lsof -i :8765 - 如果没有运行,则在输出目录中启动服务:
python3 -m http.server 8765 --directory <output-directory> & - 使用第 1 阶段中的 Chrome 标签页(或新建一个)
- 如果审核的是移动端动画: 使用
resize_window将浏览器调整为移动端视口(390×844px),然后再导航。这可确保按预期比例查看动画,而不是将其拉伸到桌面窗口大小。 - 导航至:
http://localhost:8765/<filename>.html?v=<timestamp>
每次编辑后,都必须附加 ?v=<Date.now()> 以清除缓存。
审核两个变体时: 先在完整浏览器窗口大小下审核桌面动画,再调整为移动端大小并审核移动端变体。分开审核——不要混合两个变体的反馈。
步骤 2:冻结并检查每个关键状态
注入 JavaScript 以停止动画并设置指定状态:
// Stop ALL pending timers
var id = window.setTimeout(function(){}, 0);
while (id--) { window.clearTimeout(id); }
// Reset stage
var stage = document.getElementById('stage');
stage.classList.remove('clicking', 'processing', 'optimized', 'complete');
// Hide cursor
var cursor = document.querySelector('.cursor');
if (cursor) { cursor.style.animation = 'none'; cursor.style.opacity = '0'; }
// Hide badges/overlays
var badge = document.querySelector('.optimized-badge');
if (badge) { badge.style.display = 'none'; }
然后设置目标状态:
- 之前状态:移除所有类(应用默认 CSS 位置)
- 之后状态:
stage.classList.add('optimized');并更新文本内容 - 完成状态:
stage.classList.add('optimized', 'complete');并显示徽章
设置每个状态后都要截图,并展示给用户。
需要检查的关键状态
功能演示:
- 前置状态——所有元素是否都可见?是否正确位于容器周边?颜色是否与应用一致?
- 后置状态——元素是否位于周边?分组是否正确?标签和徽章的位置是否正确?
- 徽章/叠加层——完成徽章是否遮挡了重要元素?
轮播:
- 每个场景——布局是否与应用一致?元素样式是否恰当?文本内容是否正确?
第 3 步:收集反馈
对于每个检查过的状态,使用 AskUserQuestion:
"How does the [BEFORE / AFTER / Scene N] state look?"
Options:
- Looks good
- Element positions are off (not on perimeters, wrong placement)
- Colors or styling need adjustment
- Layout or spacing needs changes
- Text content is wrong
- [Other]
如果可能存在多个问题,请启用 multiSelect: true。
第 4 步:修复并重新检查
用户报告问题时:
- 阅读当前 HTML,了解 CSS 结构
- 找出根本原因:
- 位置偏离周边 → 使用三角函数公式重新计算
- 颜色错误 → 更新 CSS 自定义属性
- 布局偏移 → 检查容器位置和绝对坐标
- 文本错误 → 更新 HTML 内容
- 徽章遮挡元素 → 调整徽章位置或 z-index
- 使用 Edit 工具应用修复
- 如果修复发现规格有误,更新简述
- 使用新的缓存破坏参数重新提供页面:
?v=<new-timestamp> - 使用相同的 JS 注入,在受影响的状态下重新冻结
- 重新截图,并再次询问用户
重复第 3–4 步,直到用户对每个状态都表示“看起来不错”。
第 5 步:完整播放并调整时长
所有冻结状态都分别获得批准后:
- 重新加载页面(使用缓存破坏参数),以重启动画循环
- 让用户观看完整动画——不要冻结动画
- 询问:
"How does the full animation look in motion?" Options: - Approved — looks great! - Timing needs adjustment - Transitions need work (easing feels wrong, stagger off) - Something else needs fixing - 如果是已批准 → 完成。告知用户文件保存位置(简述和 HTML)。
- 如果是需要调整时长 → 进入下方的时长调整循环。
- 如果有其他反馈 → 应用修改,重新提供页面,并再次询问。
时长调整循环
时长调整总是需要反复迭代。 预计需要 2–4 轮时长调整——这很正常,并不代表初次尝试不佳。目标是通过提出具体问题,快速收敛。
用户表示需要调整时长时,具体询问哪些阶段需要调整:
"What about the timing needs adjustment?"
Options (multiSelect: true):
- Initial state too long (before the action starts)
- Initial state too short (need more time to see the 'before')
- Action/stagger too slow (elements appear too slowly)
- Action/stagger too fast (can't follow what's happening)
- Final hold too long (loop feels sluggish)
- Final hold too short (not enough time to absorb the result)
应用修改,使用缓存破坏参数重新加载,然后再次询问:
"How does the updated timing feel?"
Options:
- Approved — looks great!
- Still needs adjustment
如果用户表示“仍需调整” → 再次询问具体阶段。重复此过程,直到获得批准。
时长调整提示:
- 以有意义的幅度调整(减半或加倍,不要只调整 50 毫秒)
- 如果用户只说“快一点”,先缩短前置状态和最终状态的停留时间——动作错开时长通常没有问题
- 总循环时长低于 6 秒会显得利落;超过 12 秒则会显得拖沓
- 前置状态通常不需要超过 0.5 秒——观看者能立即理解“空白”状态
审查循环原则
先检查静态状态,再评估动态效果。
在冻结画面中更容易发现定位和布局问题。时长和缓动问题只有在播放过程中才会显现。先修复视觉问题,再调整动态效果。
错误处理
- 应用要求登录: 停止操作,并让用户在 Chrome 标签页中手动登录。用户确认后再继续研究。
- Chrome 工具不可用: 告知用户第 1 阶段(研究)需要 Claude-in-Chrome。如果用户能口头描述应用,可提出跳过该阶段,直接进行访谈。
- HTTP 服务器端口已被占用: 尝试使用 8766、8767 等端口。使用
lsof -i :<port>检查。 - 浏览器缓存显示旧版本: 始终使用
?v=<timestamp>破坏缓存。如果仍显示旧版本,尝试打开新的 Chrome 标签页。 - 用户报告了你无法复现的问题: 请用户详细描述。使用
read_page或javascript_tool检查实时 DOM 和计算样式。 - 圆周定位看起来不正确: 仔细核对公式。常见错误:
- 忘记将角度转换为弧度
- 中心点错误(记住:中心 = 原点 + 半个尺寸)
- 半径错误(应为容器可见半径 + 元素尺寸的一半)
- 忘记从计算得出的位置中减去元素尺寸的一半
高质量动画的技巧
- 契合应用的个性。 深色主题应用使用深色动画。风格活泼的应用采用弹性缓动。企业级应用使用细腻的过渡效果。
- 少即是多。 14–20 个动效元素就足够了。不要试图还原真实应用的每个像素。
- 弹簧缓动效果更真实。
cubic-bezier(0.34, 1.56, 0.64, 1)能让元素显得有质感、充满活力。 - 让所有元素依次出现。 为元素依次设置
transition-delay(每个元素间隔 0.04–0.08s),效果远胜于同时移动。 - 展示结果要留时间,但别太久。 动画结束后,将最终状态保持 2–3 秒。时间再长,循环就会显得拖沓。观众吸收结果的速度比你想象的更快。
- 标签和徽章最后出现。 它们负责说明结果——先让视觉变化发生。
- 设计语言至关重要。 只要颜色、字体和圆角半径恰当,即使布局粗略,整体也仍会「像这个应用」。布局再完美,颜色不对也会显得格格不入。