anim-slides(动画幻灯片)
用于幻灯片的自动画 SVG 插图,可从现有幻灯片或文档制作。
输出始终是一个片段:一个包含 <style> 和一个 <svg> 的 HTML 文件,无脚本、无外部文件,通过 CSS 变量设置主题,可直接嵌入任何幻灯片。
references/fragment-contract.md 是契约。在构建任何内容前请先阅读它。
何时使用
- 某张幻灯片包含一行文本卡片、项目符号列表或截图,其内容涉及流程、流、依赖结构、时间线、比较、架构或时间序列。
- 某份文档(Markdown、Confluence 导出文件、README、Mermaid 块)描述了一个流程或依赖关系,用户希望将其以动画形式显示在幻灯片或页面上。
- 宿主是一个 HTML 幻灯片(frontend-slides、reveal.js、impress.js、Slidev、手写)或一个普通网页。
.pptx或 Markdown 源文件会先由幻灯片技能(步骤 0)转换为设计好的 HTML 幻灯片;然后由本技能添加插图。
工作流程
下方的 <skill-dir> 是包含此 SKILL.md 的文件夹(Claude Code 将其暴露为 $CLAUDE_SKILL_DIR;在其他框架中,请使用您加载此文件的路径)。脚本需要 Python 3.9+ 以及用于渲染的 Chrome 或 Chromium 二进制文件。anim/<name>/ 是用户幻灯片旁边的文件夹。
0. 输入
首先获取一个 HTML 幻灯片。 anim-slides 为 HTML 幻灯片添加图形;它不设计幻灯片。
- 源文件已经是 HTML 幻灯片(reveal.js、impress.js、任何
<section>或.slide幻灯片):继续。 - 源文件是
.pptx、Markdown、remark、文档或任何非 HTML 幻灯片的内容:由幻灯片技能首先构建 HTML 幻灯片,而不是 anim-slides。优先顺序如下: (a) 用户已安装的或其所在组织的幻灯片技能; (b)frontend-slides(如果已安装,它将 pptx 和 Markdown 转换为设计好的 HTML 幻灯片;当它提供美观预览时,选择最接近源幻灯片品牌的样式,除非用户想要新外观); (c) 仅当没有安装任何幻灯片技能时,使用scripts/md_to_deck.py作为后备(请参阅下方的后备子弹点),并在一句话中告知用户其输出是一个普通宿主,不是设计好的幻灯片,在由幻灯片技能或设计师设计样式之前,读起来会像文档。在情况 (a) 和 (b) 中,原始.pptx仍作为extract_slides.py和render_deck.py分类(图表、图形、备注)的源文件,但集成目标指向该技能生成的幻灯片,并且匹配外观来自该幻灯片的调色板(通过host_theme.py)。要求幻灯片技能(或在其之后立即执行)将每个候选幻灯片的主体包裹在一个固定大小的插槽<div id="sN-slot">中,位于<!-- sN-body -->和<!-- /sN-body -->之间(md_to_deck.py使用的 id 和标记名称,不过在那种情况下插槽是主体的空兄弟元素):然后measure_slot.py --selector '#sN-slot'是精确的,并且integrate_fragment.py --anchor/--replace-until以这些标记为目标。幻灯片技能自己的字体链接(Google Fonts、Fontshare)是该幻灯片的加载内容,而不是 anim-slides 添加的;保留它,并在移交时使用bundle_deck.py --fetch将其内联。
然后决定适用哪个入口点:
- 现有幻灯片:运行
python3 <skill-dir>/scripts/extract_slides.py deck.pptx|deck.html|doc.md -o anim/outline.json和python3 <skill-dir>/scripts/render_deck.py deck -o anim/render,然后查看sheet-NN.png联系表(每张 12 张编号幻灯片),不要逐页查看(当一张幻灯片的outline.json中的图片数量与其渲染中的图片数量不同时,查看幻灯片布局上的图片:布局上的封面照片很容易被忽略);然后使用references/input-stage.md进行分类,并将表格写入anim/triage.md:每张幻灯片一个决定和理由,不能静默跳过(每 30 张幻灯片中大约有 3 到 8 个插图是正常的;在短幻灯片中,每个流程、结构、时间线、比较或数据幻灯片都会有一个)。然后为整个幻灯片确定一次外观:匹配(片段采用宿主的调色板和字体,这是品牌或公司幻灯片的默认设置)或精简(片段在深色背景上保留精简调色板,适用于演讲和推介)。python3 <skill-dir>/scripts/host_theme.py deck.html --mode match -o anim/host-theme.css从幻灯片的 CSS 中推导出匹配粘合剂(--mode lean写入精简粘合剂);将推导出的块与幻灯片自己的变量(浅色文本颜色、次要背景)比较一次,并在推导选择计算混合时手动纠正;用两种方式渲染第一个片段(render-phases.sh --theme anim/host-theme.css ...)并在构建其余内容之前显示两个静止帧,除非用户已经指定了外观。两种方式之间只有颜色和字体发生变化:references/style.md的形状规则在两者中均适用。 控制对于整个幻灯片来说是once,除非用户要求点击式:每张幻灯片的图形在幻灯片出现时播放一遍平静的通过,然后停止。不要主动推荐step。只有当outline.json报告builds大于 0 时(源文件已通过点击构建:reveal.js 片段、PowerPoint 点击动画、impress.js 子步骤、幻灯片自己的构建步骤),才用一行提及:“您的幻灯片是通过点击构建的;图形可以做同样的事情(step),如果您想要,请告知”。在step模式下,进入时绘制,每次点击进入下一个阶段;阶段是简报中叙述的阶段(每张幻灯片 3 到 5 个),片段文件相同,点击依赖于幻灯片自己的导航。Step 模式只监听按键,因此 step 幻灯片使用键盘或翻页器进行演示(同时通过滚轮或滑动导航的幻灯片,如 frontend-slides,会跳过滚动时的阶段)。在anim/triage.md的标题中写入外观和控制。 - 后备,没有安装幻灯片技能(Markdown、remark 或从 pptx 提取到 Markdown):
python3 <skill-dir>/scripts/md_to_deck.py deck.md -o deck.html制作一个普通的、自包含的宿主用于集成(每个幻灯片一个<section>、.visible门控、打印布局、围绕每个幻灯片主体的<!-- sN-body -->标记)。它不是设计好的幻灯片:用一句话告诉用户。首先获取 Markdown 引用的图像(相对路径)到同一文件夹中,否则幻灯片会显示占位符;然后从原始源文件(如果有.pptx)或 Markdown 中提取。 - 文档:阅读源文件,使用
references/archetypes.md中的表格选择原型,提取规格(步骤 1)。 - 单张幻灯片请求:直接转到该幻灯片的步骤 1。 仅当源文件在顺序、方向或分组方面不明确时,才询问用户。否则,在简报中指出假设并继续。
1. 规格
按照 references/spec-format.md 编写 anim/<name>/spec.yaml:名称、原型、节点、边、组、带秒标记的阶段、循环(通过长度)、控制(在输入中从幻灯片选择的:once,幻灯片变为当前幻灯片时播放一遍平静的通过,持续 4 到 10 秒,结束于休息帧;step,相同的通过,但在阶段标记处切割,以便每次点击进入下一个阶段;loop,仅当用户要求连续循环时)。once 和 step 下的片段文件相同;阶段标记变为 data-anim-phases。重用源文件自己的词语作为标签。将规格保持在约 12 个节点以下;否则进行拆分。
1b. 检查池
读取 <skill-dir>/pool/index.yaml,然后如果设置了 $ANIM_POOL 变量,则读取 $ANIM_POOL/index.yaml(或列出 $ANIM_POOL/*/),查找具有相同原型和相似故事或标签的条目。
- 接近匹配:将文件夹复制到
anim/<name>/,将片段和所有前缀重命名为<name>,然后在步骤 3 中调整标签、数据、时序和 viewBox 以匹配规格,而不是从头搭建。如果存在,其spec.yaml是您规格的起点。 - 仅相同原型:照常搭建,并将池片段打开作为密度、运动和休息帧的质量标准。
- 没有匹配的:根据规格构建;最接近的池条目仍然值得一看。 切勿将池片段未经修改地复制到幻灯片中:其故事只是一个示例,而不是用户的。
2. 插槽和简报
测量幻灯片上的空闲框:python3 <skill-dir>/scripts/measure_slot.py deck.html --slide N [--selector SEL] [--ignore .body] 以舞台像素打印框、匹配的 viewBox 和检查器标志(references/layouts.md 解释了手动方式)。在绝对定位的布局上,不使用 --selector 进行测量会返回垃圾数据;测量插槽 div(--selector '#sN-slot',步骤 0)。选择具有相同宽高比的 viewBox,并根据 references/brief-template.md 填写 anim/<name>/brief.md。简报固定 viewBox 和渲染大小、构图、阶段、休息帧、主题令牌和最小文本大小,并指明片段替换幻灯片上的哪个内容(药丸、框图、项目符号列)。片段的质量取决于简报的质量。
3. 构建
python3 <skill-dir>/scripts/scaffold_from_spec.py anim/<name>/spec.yaml -o anim/<name>/<name>.html --rendered-width <px> 验证规格并写入符合契约的骨架(布局、阶段、分组、注释、休息帧;字体大小根据渲染宽度提高到下限),然后对其运行检查器。输出顶部的注释列出了需要手动优化的内容。使用 references/archetypes.md 确定构图和运动,使用 references/motion-rules.md 确定时序和缓动,使用 references/style.md 确定外观(精简易模式:圆环和细线、无框、一个发光强调色、单色子标签、普通标题),将其优化为简报描述的插图。对于多个插图,从共享简报一次构建一个片段,或者如果框架支持,每个片段使用一个并行子 Agent;集成始终在主线程中进行。
4. 通过目视检查验证
python3 <skill-dir>/scripts/check_fragment.py anim/<name>/<name>.html --name <name> --rendered-width <px> --stage-width <deck stage width>必须通过(前缀、令牌、门控、文本大小、禁止内容)。--stage-width设置文本下限(1920 下为 18 px,1280 下为 12 px);outline.json报告舞台。<skill-dir>/scripts/render-phases.sh anim/<name> <W> <H> 1.5 4 7 10 rest使用暂停加负延迟方法将阶段 PNG 和联系表渲染到它打印的临时文件夹中(传递--out DIR以选择目录)。集成后,render-phases.sh --page deck.html 1920 1080 rest检查宿主页面的休息帧;在多幻灯片页面上添加--slide N(或#hash,或 CSS 选择器)。对于定时标记或阶段帧,当页面自己的脚本切换门控类时,使用--no-script,但切勿用于rest:在 frontend-slides 幻灯片中,.visible既是门控也是显示幻灯片的类,rest 渲染会剥离它,并且幻灯片之所以保持显示,仅仅是因为幻灯片的脚本也设置了.active;没有脚本时,rest 帧是空白的。使用您的图像查看工具打开每个 PNG。修复裁剪、重叠、不可读文本、空白面板。至少迭代一次。- 休息帧必须看起来像一个完整的静止画面(PDF 导出只显示这个)。
python3 <skill-dir>/scripts/verify_facts.py anim/<name>/<name>.html --source anim/outline.json --slide <N>(或--source doc.md)必须通过:片段中的每个数字都来自源文件或被标记为示意性;阅读每个 WARN 并将无法追踪的措辞替换为源文件自己的词语或删除它。规则在references/accuracy.md中。在通过此项检查之前,图形不算完成。 切勿依赖--virtual-time-budget,也切勿依赖阅读源文件而非 PNG。
5. 集成
python3 <skill-dir>/scripts/integrate_fragment.py deck.html anim/<name>/<name>.html --name <name> --anchor '<slide 中的唯一字符串>' [--replace-until '<string>'] [--gate 'section.present'] [--control once|step] --backup 将样式提升到 <head> 中,在 <!-- anim:<name>:start --> 和 <!-- anim:<name>:end --> 标记之间插入片段(样式位于 anim-style 标记之间;重新运行会替换两个副本),为宿主幻灯片重写门控,并前缀任何漏掉的类。对于普通页面,将 <skill-dir>/scripts/snippets/observer.html 复制到页面中。--control 在包装器上设置幻灯片的控制;--control step 还会将 scripts/snippets/step-host.html(一个小型普通脚本,无库)放入头部一次,并从 --gate 设置其门控。控制是集成时的幻灯片范围开关:使用另一个值重新运行以更改它,片段保持不变。锚点和 until 字符串保持不变;两者之间的内容被替换。门控是宿主的“当前幻灯片”标记:reveal.js 使用 section.present,普通页面使用 .visible(scripts/snippets/observer.html),以及来自 md_to_deck.py 的幻灯片。在 md_to_deck.py 幻灯片以及步骤 0 中带有插槽标记的幻灯片技能幻灯片中,片段替换主体:--anchor '<!-- sN-body -->' --replace-until '<!-- /sN-body -->'。检查幻灯片的标题和正文文本在没有幻灯片脚本的情况下以及在打印中是否显示。幻灯片技能的进入动画通常仅基于当前幻灯片类(frontend-slides 仅在 .slide.visible 下显示 .reveal 元素),因此 rest 渲染和 PDF 会显示空白幻灯片;将这些揭示也基于幻灯片的活跃类(.slide.active),并添加一个显示它们的打印规则。(类名 .reveal 也会在 host_theme.py 的幻灯片选择器中匹配 reveal.js 检测;到目前为止无害,但请检查它找到了哪些幻灯片。)
它还会添加一个打印保护,以便 PDF 导出(reveal 的 ?print-pdf 标记每张幻灯片为 present)显示休息帧。
保持工作幻灯片精简:片段是小的 SVG 文本,通过标记进入,但在工作时不要内联字体、图像、库或样式表,切勿将整个幻灯片读入上下文;读取锚点周围的切片(grep -n、sed -n)并让脚本编辑它。然后在真实浏览器中打开幻灯片并观察。
(文档在此被截断)