关于 graphic-gif
用于制作动画 GIF 的技能,默认通过 CSS 动画生成,也可按明确要求使用 Kling 图像转视频流程。适合制作短篇视觉动效,并输出 HTML 源文件和 GIF。
主要功能
- 01通过 CSS 动画生成 GIF
- 02支持 Kling 图像转视频生成
- 03设置时长、帧率、风格和尺寸
- 04捕获动画帧并导出优化后的 GIF
适用场景
- 01制作社交媒体动画图形
- 02将动态文字或计数器制作为 GIF
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ varnan-tech/ opendirectory --skill graphic-gif安装后在 Claude Code 中输入/graphic-gif确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
README.mdevals/evals.jsonreferences/animation-library.mdstyle-presets.mdscripts/capture-and-encode.mjsexport-gif.sh详细介绍
graphic-gif
根据 CSS 动画或 AI 图像转视频 API 生成循环动画 GIF。输出:animation.gif。
与其他所有输出静态 PNG 或 PDF 的 graphic- 技能不同,此技能输出动画 .gif。使用 Playwright 和 Web Animations API 逐帧捕获 CSS @keyframes 动画(选项 A,默认),或通过 Kling 使用 AI 图像转视频工作流(选项 B)。
关键规则(每次生成前阅读)
- 默认使用 css-animated。 除非用户明确要求,否则绝不使用
ai-generated。 - 画布为 800×800px 正方形。 所有
clamp()值均按 800px 计算(1vw = 8px)。 - 使用单个独立 HTML 文件。 所有 CSS 都内联在
<style>中。唯一外部依赖是字体 CDN<link>。 - 绝不在聊天中贴出 HTML。 保存到文件,只展示摘要。
- 使用 Web Animations API 跳转时间点来捕获帧。 不使用
setTimeout循环,也不使用animation-delay技巧。 - 帧数必须精确:
Math.floor(duration_seconds * fps)帧。不得捕获t=duration_ms处的帧——它与t=0重复,会导致循环衔接处出现明显卡顿。 - 不要使用占位框。 仅使用 CSS 生成视觉效果。不要添加“图片放在这里”之类的元素。
- 调色板越简洁,文件越小。 使用:
clean-slate、terminal、electric-burst、brutalist。 - 不要用
animation-delay实现错开效果。 将错开时间写入@keyframes百分比中——逐帧跳转会处理时间。 - 编写 CSS 前先确定设计方向。 在写第一行代码前,确定基调、标志性元素、运动风格和令人难忘的细节。
第 1 步:收集需求
必需: prompt(内容描述和动态效果说明)
可选,使用默认值:
| 参数 | 默认值 | 选项 |
|---|---|---|
| animation_type | css-animated | css-animated / ai-generated |
| duration | 3.0 | 秒 |
| fps | 12 | 帧/秒 |
| loop | true | true / false |
| style | clean-slate | clean-slate / terminal / electric-burst / brutalist |
| dimensions | 800x800 | WxH,单位为像素 |
| optimization | balanced | quality / balanced / filesize |
如果缺少 prompt 或动态效果说明,请原样询问:
"GIF 应该展示什么?请描述内容和动态效果(例如:'数字递增:73% 的买家在购买前会阅读 3 篇以上的内容。打字机效果,每次显示一个字符。风格:terminal。3 秒,12fps。')
关键设置(均为可选,括号内为默认值):
- animation_type:css-animated(默认)或 ai-generated
- duration:3.0 秒
- fps:12
- loop:true
- style:clean-slate(选项:clean-slate / terminal / electric-burst / brutalist)
- dimensions:800x800
- optimization:balanced(选项:quality / balanced / filesize)"
如果必需信息齐全 → 直接跳到第 2 步。
步骤 2:内部架构(绝不向用户展示)
对于 css-animated:
- 从以下类型中选择动画类型:
fade-in、slide-in、typewriter、counter、pulse、loop-scroll - 阅读
references/animation-library.md— 查找所选类型的完整 HTML/CSS 规范 - 阅读
references/style-presets.md— 加载所选样式的 CSS token 块 - 计算帧数:
Math.floor(duration_seconds * fps)— 记下这个数字 - 确定设计方向:
| 决策 | 推导依据 |
|---|---|
| 基调 | 受众的情绪基调(机械 / 温暖 / 电感 / 专业) |
| 标志性元素 | 始终一致使用的一个视觉元素(光标闪烁、幽灵数字、扫描线叠层、强调色边框) |
| 动效风格 | 该类型的缓动曲线理念(弹簧 / 线性 / 步进 / 缓入缓出) |
| 难忘细节 | 观众会记住这个 GIF 的唯一亮点 |
对于 ai-generated:
- 生成基础静帧 HTML(适用于画布的海报式布局)
- 使用截图导出为 PNG
- 调用 Kling API:
POST https://api.klingai.com/v1/videos/image2video,传入image_url和描述动效的prompt - 轮询任务完成状态
- 下载视频 → 使用 ffmpeg 转换为 GIF:
# Two-pass palette for best color quality ffmpeg -i input.mp4 -vf "fps=12,scale=800:800:flags=lanczos,palettegen=stats_mode=diff" palette.png ffmpeg -i input.mp4 -i palette.png -vf "fps=12,scale=800:800:flags=lanczos,paletteuse=dither=bayer:bayer_scale=5" output.gif
步骤 3:HTML 生成(css-animated 路径)
生成前阅读 references/animation-library.md 和 references/style-presets.md。
画布基础样式 — 每个 GIF 都必须包含:
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
body {
width: 800px;
height: 800px;
overflow: hidden;
background: var(--bg);
font-family: var(--font-body);
}
.canvas {
width: 800px;
height: 800px;
position: relative;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
}
动画规则:
- 在所有动画元素上设置
animation-fill-mode: forwards(或both) - 按类型设置计时函数:
typewriter→steps(N, end),其中 N = 字符总数counter→linearfade-in→cubic-bezier(0.22, 1, 0.36, 1)(缓出)slide-in→cubic-bezier(0.34, 1.56, 0.64, 1)(弹簧式过冲)pulse→ease-in-out,并设置animation-iteration-count: infiniteloop-scroll→linear,并设置animation-iteration-count: infinite
- 对于单次动画(fade-in、slide-in、typewriter、counter):设置
animation-iteration-count: 1— 循环由 GIF 层级处理 - 不要使用
animation-delay— 通过@keyframes百分比实现错落效果
Typewriter 的 N 值计算: 统计每个字符,包括空格、标点和数字:
- "73% of buyers" = 14 个字符 →
steps(14, end) - "Hello, World!" = 13 个字符 →
steps(13, end)
Counter CSS @property(counter 类型必需):
@property --num {
syntax: '<integer>';
inherits: false;
initial-value: 0;
}
.counter {
animation: countUp var(--duration) linear forwards;
counter-reset: num var(--num);
}
.counter::after { content: counter(num); }
@keyframes countUp {
from { --num: 0; }
to { --num: var(--target); }
}
Loop-scroll:必须重复内容:
<div class="ticker-track" style="--item-count: 4;">
[item1][item2][item3][item4][item1][item2][item3][item4]
</div>
使用 translateX(0 → -50%),并设置 linear infinite。
设计质量规则(根据步骤 2 中确定的方向):
- 标注的标志性元素必须出现在 CSS/HTML 中(不能只写在描述里)
- 排版:展示文本与辅助文本之间的字重对比至少为 2:1(例如 700 与 400)
- 背景:深色样式不要使用纯白色
#fff— 使用预设中的确切--bg值 - 对于终端样式:使用
repeating-linear-gradient添加::after扫描线叠层,opacity: 0.03 - 对于粗野主义样式:在关键元素上添加粗边框
4px solid #000或4px solid var(--accent) - 难忘细节:如果需要额外元素,就现在添加
Step 4:自检(在 Step 5 前修复所有问题)
画布:
-
body和.canvas的尺寸均为 800×800px(或指定尺寸) -
body和.canvas均设置了overflow: hidden - 没有元素超出画布边界
动画:
- 任何地方都没有
animation-delay——交错效果通过@keyframes百分比实现 - 所有动画都从
t=0开始(Web Animations API 会从该位置开始定位) - 所有动画元素都设置了
animation-fill-mode: forwards或both - 单次动画:
animation-iteration-count: 1 - 无限动画(pulse、loop-scroll):
animation-iteration-count: infinite
类型专项检查:
- 打字机效果:
steps(N, end)中的 N = 文本字符串的准确字符数 - 计数器:使用
syntax: '<integer>'和initial-value: 0声明了@property --num - 计数器:设置了
counter-reset: num var(--num)和::after { content: counter(num) } - 循环滚动:HTML 中的内容恰好重复一次
设计:
- 没有占位框
- 已应用
references/style-presets.md中的样式预设令牌——没有未归属的十六进制颜色 - Step 2 中指定的标志性元素确实存在于 HTML/CSS 中
- Step 2 中指定的令人难忘的细节确实已实现
- 已为所选样式的字体添加 Font CDN
<link>
Step 5:导出
根据提示词确定 slug(kebab-case,≤30 个字符)。创建输出目录:
mkdir -p [slug]
保存 HTML:
[slug]/animation.html
在浏览器中打开并快速检查视觉效果:
open [slug]/animation.html
运行导出脚本(将 [skill-root] 替换为此技能的实际路径):
bash [skill-root]/scripts/export-gif.sh \
[slug]/animation.html \
[slug]/animation.gif \
--duration [duration] \
--fps [fps] \
[--no-loop if loop=false] \
--optimization [optimization] \
--width [W] \
--height [H]
该脚本会:
- 在临时目录中安装
gifenc、sharp(或jimp)和playwright - 如果 Chromium 尚未缓存,则下载 Chromium
- 运行
capture-and-encode.mjs——暂停动画、定位到每一帧、截屏并合成为 GIF - 如果
gifsicle可用,则运行优化流程 - 报告文件大小并打开结果
如果未找到导出脚本 [skill-root]/scripts/export-gif.sh,请检查技能安装时是否完整保留了 scripts/ 文件夹。
Step 6:输出摘要
成功导出后显示:
## GIF: [1-line description]
Date: [YYYY-MM-DD] | Style: [style] | Animation: [type] | [duration]s @ [fps]fps
Dimensions: [WxH] | Frames: [N] | Loop: [true/false]
Files
Source: [slug]/animation.html
Output: [slug]/animation.gif
Size: [X] KB
Checklist
- [ ] Preview loops cleanly at start/end point (no stutter)
- [ ] Text legible at intended display size
- [ ] File size appropriate: email <500KB / social <3MB
AI 生成路径(选项 B)
仅当明确指定 animation_type: ai-generated 时使用。
要求:
- 环境中配置了 Kling API 密钥:
KLING_API_KEY(每天 66 个免费点数,免费套餐无需信用卡) - 本地已安装
ffmpeg,用于将视频转换为 GIF
工作流:
- 生成与提示词相符的基础静帧 HTML(海报/图形风格,采用指定尺寸)
- 将静帧导出为 PNG:
# Quick screenshot via Playwright node -e " const { chromium } = require('playwright'); (async () => { const browser = await chromium.launch(); const page = await browser.newPage({ viewport: { width: W, height: H } }); await page.goto('file://[slug]/animation.html'); await page.screenshot({ path: '[slug]/base-frame.png' }); await browser.close(); })(); " - 上传到 Kling 图生视频端点
- 使用 ffmpeg 的两遍调色板转换将结果转为 GIF
- 使用 gifsicle 优化
**Kling 不可用时:**改用 css-animated,并告知用户:“AI 生成需要 Kling API 密钥(KLING_API_KEY)。正在改用 css-animated。设置该密钥即可启用 AI 生成。”
提示词建议(用户寻求指导时显示)
“描述动作,而不仅仅是内容。‘数据逐个递增’比‘显示数据’更好。”
“保持简单以减小文件体积。使用 1–3 个动画元素和纯色背景。”
“考虑循环效果。动画从结束到开始应无缝衔接。”
“明确指定动画类型。
typewriter和counter最适合社交媒体内容。”✅ 好:“创建一个动画 GIF,使用 css-animated 和打字机效果。文本:‘73% 的 B2B 买家在联系销售前会阅读 3 篇以上的内容。’逐个输入每个字符。样式:terminal。时长 3 秒,12fps,loop=true。”
❌ 不好:“制作一张关于营销技巧的动画 GIF”