mcpField
C
css-animation

css-animation

github.com/neonwatty设计与 UI18167 次安装1 周前更新
代码仓库

关于 css-animation

用于制作自包含 HTML/CSS 动画的技能,可复现应用功能,服务于产品演示、引导和营销。流程涵盖调研、访谈、生成与审核,并支持功能演示和轮播两种形式。

主要功能

  1. 01在 Chrome 中调研应用视觉
  2. 02功能演示与轮播形式
  3. 03桌面和移动端输出尺寸
  4. 04生成简报与 HTML 动画
  5. 05迭代审核与调整

适用场景

  1. 01演示应用功能的状态变化
  2. 02制作多屏产品演示
  3. 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 外,安装时一起下载的参考资料和脚本。

LICENSE
CNAME
README.md
index.html
docs/plans/
2026-02-26-css-animation-skill-design.md
2026-02-26-css-animation-skill-implementation.md
examples/
seatify-optimize-brief.md
seatify-rsvp-brief.md
seatify-rsvp.html
seatify-optimize.html
seatify-walkthrough.html

详细介绍

CSS 动画演示技能

你将创建精致、独立的 HTML/CSS 动画,模拟真实应用功能。这些动画用于功能演示、新手引导和营销。它们不是 GIF——不受分辨率限制、文件体积小,而且易于迭代。

两种动画风格

  1. 功能演示 — 操作前 → 执行操作 → 操作后。展示单个功能的变化(例如,点击“优化”,观察座位重新排列)。
  2. 轮播 — 多视图。通过交叉淡入淡出过渡,循环展示多个应用界面(例如,仪表板 → 嘉宾名单 → 画布 → RSVP)。

在访谈阶段确定用户需要哪种风格。

阶段

Phase 1: Research → Phase 2: Interview → Phase 3: Generate → Phase 4: Review Loop

阶段 1:调研

在生成任何内容之前,通过 Chrome 浏览目标应用,深入了解其视觉系统。

前提条件
  • 必须能够使用 Claude-in-Chrome MCP 工具
  • 必须能在浏览器中访问目标应用(本地运行或已部署)
步骤 1:设置 Chrome
  1. 调用 tabs_context_mcp 检查现有标签页
  2. 创建一个新的专用标签页:tabs_create_mcp
  3. 保存此标签页 ID——后续所有浏览器操作都专门使用此标签页
步骤 2:导航并探索
  1. 导航到目标应用 URL
  2. 如果需要身份验证,请让用户手动登录,然后继续
  3. 如果目标是移动端或同时面向移动端和桌面端: 在导航到相应功能前,使用 resize_window 将浏览器调整为移动视口(390×844px)。这样可以确保你调研的是应用实际的移动端布局,而不是被压缩的桌面版。如果目标是同时面向移动端和桌面端,先在全尺寸下调研桌面版,然后调整为移动视口并重新提取移动端布局。
  4. 导航到要制作动画的具体功能/页面
  5. 截取探索性屏幕截图,以了解布局
步骤 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:在本地提供动画
  1. 检查是否已有 Python HTTP 服务在运行:
    lsof -i :8765
    
  2. 如果没有运行,则在输出目录中启动服务:
    python3 -m http.server 8765 --directory <output-directory> &
    
  3. 使用第 1 阶段中的 Chrome 标签页(或新建一个)
  4. 如果审核的是移动端动画: 使用 resize_window 将浏览器调整为移动端视口(390×844px),然后再导航。这可确保按预期比例查看动画,而不是将其拉伸到桌面窗口大小。
  5. 导航至: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'); 并显示徽章

设置每个状态后都要截图,并展示给用户。

需要检查的关键状态

功能演示:

  1. 前置状态——所有元素是否都可见?是否正确位于容器周边?颜色是否与应用一致?
  2. 后置状态——元素是否位于周边?分组是否正确?标签和徽章的位置是否正确?
  3. 徽章/叠加层——完成徽章是否遮挡了重要元素?

轮播:

  1. 每个场景——布局是否与应用一致?元素样式是否恰当?文本内容是否正确?
第 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 步:修复并重新检查

用户报告问题时:

  1. 阅读当前 HTML,了解 CSS 结构
  2. 找出根本原因:
    • 位置偏离周边 → 使用三角函数公式重新计算
    • 颜色错误 → 更新 CSS 自定义属性
    • 布局偏移 → 检查容器位置和绝对坐标
    • 文本错误 → 更新 HTML 内容
    • 徽章遮挡元素 → 调整徽章位置或 z-index
  3. 使用 Edit 工具应用修复
  4. 如果修复发现规格有误,更新简述
  5. 使用新的缓存破坏参数重新提供页面:?v=<new-timestamp>
  6. 使用相同的 JS 注入,在受影响的状态下重新冻结
  7. 重新截图,并再次询问用户

重复第 3–4 步,直到用户对每个状态都表示“看起来不错”。

第 5 步:完整播放并调整时长

所有冻结状态都分别获得批准后:

  1. 重新加载页面(使用缓存破坏参数),以重启动画循环
  2. 让用户观看完整动画——不要冻结动画
  3. 询问:
    "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
    
  4. 如果是已批准 → 完成。告知用户文件保存位置(简述和 HTML)。
  5. 如果是需要调整时长 → 进入下方的时长调整循环。
  6. 如果有其他反馈 → 应用修改,重新提供页面,并再次询问。
时长调整循环

时长调整总是需要反复迭代。 预计需要 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 秒。时间再长,循环就会显得拖沓。观众吸收结果的速度比你想象的更快。
  • 标签和徽章最后出现。 它们负责说明结果——先让视觉变化发生。
  • 设计语言至关重要。 只要颜色、字体和圆角半径恰当,即使布局粗略,整体也仍会「像这个应用」。布局再完美,颜色不对也会显得格格不入。

评论

支持 Markdown