ワンクリックで
elisp-explainer-video
用 HyperFrames 制作 Emacs Lisp 教学视频的完整工作流——从文档提取概念→设计可视化(画数据结构+算法流程)→编写 HTML/SVG/GSAP 时间线→渲染 MP4。
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
用 HyperFrames 制作 Emacs Lisp 教学视频的完整工作流——从文档提取概念→设计可视化(画数据结构+算法流程)→编写 HTML/SVG/GSAP 时间线→渲染 MP4。
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
Diagnose and fix the dual-channel memory problem in Hermes Agent — when `memory.provider: holographic` (or any external provider) is configured but the agent keeps writing only to `memories/MEMORY.md`, bypassing it. Covers why agents default to the markdown file, the four root causes of routing failure, and three remediation options (SOUL.md rules / disable MEMORY.md / mirror via code). Triggers on 'memory 不生效', 'holographic 没在用', 'agent 都写到 MEMORY.md', '双 memory 系统', 'memory tool vs fact_store', 'on_memory_write', 'memory drift', 'Mirrors 不到', or any 'why is my agent ignoring the configured memory provider' question.
Use when the user works inside ~/Projects/Config/Guix-configs and mentions '改 dotfiles', 'blue home', 'guix system reconfigure', 'shepherd service', 'stow 死链', 'blue stow', 'AGENTS.md 翻新', 'fcitx', 'IME 没输入法', 'Electron 没输入法', 'wireplumber', '二轨 dotfiles', '恢复被删除的 dotfiles', or related. Ten sub-protocols — dotfiles deploy verification, worker delegation, multi-line edit safety, Guix service debugging, GNU Stow mutable config, restoring deleted dotfiles, ISO 移植, 需求澄清, 模块归属陷阱.
跨 agent KB 健康度维护。**触发信号**:每周/长会话后例行维护 / 卡片 >50 张 / 检索质量明显下降 / 用户触发 `/agenote-curate` / 发现重复卡片或矛盾结论 / 新增了对话抽取源。**当上述任一信号出现时立即调用本 skill** 做健康检查+去重+归档+权重重分配+reconcile 多源 memory。基础用法见 `agenote-base`;会话中单次经验记录见 `agenote-review`。
Maintain the personal Guix channel at ~/Projects/Config/jeans (Just Enough AI-geNerated Slops). Use when the user asks to "fix the CI build failure issue", "升级 X 包", "add a package", "check upstream updates", "跑 maak upgrade", "修复 auto-update 流水线的 issue
How to author a Hermes Agent skill the right way. Covers the two non-negotiable structural principles every skill must follow — **self-contained** (all runnable artifacts ship inside the skill directory so backup = usable) and **progressive disclosure** (SKILL.md is a thin router; details live under `references/`, `templates/`, `scripts/`) — the directory layout, file-type rules, decision trees for what goes in SKILL.md vs. a support file, **which of the 12 existing categories a new skill belongs to (never top-level `<skill-name>/`)**, and a checklist before declaring a skill done. Trigger when: writing a new skill, refactoring an existing skill's structure, wondering 'should this go in SKILL.md or references()' / 'which category directory should this skill live into', preparing a skill for backup/share, noticing a self-contained violation, or auditing existing skills. Also trigger when the user complains something is 'too verbose' or 'in the wrong place' — those are progressive-disclosure violations.
When the user says '校对文档 / 检查文档是否还有效 / sync doc with code / 扩写 README / 改写文档 / 把这个 PLAN/plan/任务书做成文档 / 文档并入主文档', or when a `refs/*.md` document may be drifting from the tool/CLI/源码 it describes, or when a PLAN file needs to become a user-facing reference doc. Covers three entry points — check, rewrite, plan-to-doc — backed by a `scripts/doc-check.py` checker that catches silent drift between a doc and its source-of-truth (CLI flags, MCP tool names, file paths). Trigger when the user names a doc path and asks whether it's still accurate, when adding a new CLI/MCP/API surface that old docs don't mention, or when a PLAN/任务书/thread needs to graduate into a stable reference.
| name | elisp-explainer-video |
| description | 用 HyperFrames 制作 Emacs Lisp 教学视频的完整工作流——从文档提取概念→设计可视化(画数据结构+算法流程)→编写 HTML/SVG/GSAP 时间线→渲染 MP4。 |
| category | video |
把一份 Emacs Lisp 教程文档变成 13-16 分钟的教学视频,让概念本身被画出来而不是只贴文字。
references/svg-state-machine-and-graph-patterns.md — SVG 状态机/网络图布局(Evil 7 状态、Org Roam 9 节点)references/voiceover-and-captions.md — TTS 配音 + 字幕工作流,含 MiniMax t2a_v2 完整对接(2026-06 实测) + 章边界对齐 + 语速预算 + 稿件详细度三档references/tts-intent-disambiguation.md — 用户说"minimax"时的三种指代 + 三步判别法scripts/minimax-tts.py — MiniMax 同步语音合成批量脚本(从 hermes .env 加载 key,hex 解码,可选 --dry-run)scripts/synthesize_narration.py — 解说稿 md → 7 章 mp3 批量合成(温柔学姐 / speech-2.8-hd)scripts/align_and_merge.py — 章边界对齐拼接 + 烧录到视频(裁切溢出,补静音)scripts/probe_chapter_starts.py — ffmpeg 抽帧 + vision 探测章扉页真实视觉起点(解决 GSAP 入场延迟导致的 data-start 偏差)templates/narration-script.md — 解说稿 md 模板(7 段结构 + 停顿标签 + 三原则 + 反模式)教学视频常见的陷阱是把文档的段落"搬"到屏幕上——4 行定义就 4 张卡片,两段说明就两段文字。这不是可视化,这是幻灯片。真正的讲解视频应该让观众亲眼看到代码背后发生了什么。
| 概念 | 错误做法 | 正确可视化 |
|---|---|---|
| S-表达式求值 | 4 个步骤说明文字 | 求值树:根节点 + 从源代码飞出,边生长后叶子 1 2 降入树,脉冲粒子沿边流动,结果 3 落回结果框 |
| 数据类型 | 类型名称 + 例子文字 | 内存布局:整数=单格单元格、字符串=6 个字符格子排成行、布尔=t vs nil 双框、符号=指针→interned 入口 |
| 变量定义 | 4 张代码卡片 | 变量表:左 4 行代码 + 右 obarray 风格表,setq 写入闪烁,defvar 灰化跳过,defconst 加锁,defcustom 齿轮旋转 |
| cons cell | 文字说明"链表的每个节点" | 真 SVG 链表:双格矩形(数据域+指针域)+ 紫色箭头 → nil |
| 宏展开 | "宏在编译时展开"一行字 | 源代码→↓ macroexpand-1→展开后的 (progn (set ...) (set ...)) 代码块 |
在看文档前先问:每个概念在"具象世界"里长什么样?
用 beat-direction 的思路给每章定节奏: build-HOLD-SLAM-build-hold-CTA,每章 30-50 秒。
npx hyperframes init <project-name> --non-interactive --skip-skills --example=blank
关键 meta:
data-duration 为最终总时长(秒)class="clip",加 data-start/data-duration/data-track-indexwindow.__timelines["<composition-id>"] = tl原则":Layout Before Animation——先写静态 CSS 布局再补 GSAP。
每章的技术选型:
| 场景类型 | 实现方式 | 示例 |
|---|---|---|
| 树/图 | SVG <rect>/<circle>/<line> + GSAP strokeDash | 求值树、决策菱形、cons cell 链表 |
| 卡片网格 | CSS Grid + GSAP stagger | 4 数据类型卡片 |
| 流水线 | flex + GSAP fromTo | dolist 管道、mapcar 流水线 |
| 时间轴 | flex + GSAP set/to 光标移动 | save-excursion、with-eval-after-load |
| 状态表 | CSS Grid + classList 切换 | 变量表、features chip |
CSS 设计模式:
#0d1117 + 网格纹理(repeating-linear-gradient 1px)background: #161b22; border: 1px solid #30363d; border-radius: 12px;每章的 GSAP 写法则:
tl.set(id,{opacity:1}) + stagger 元素入场动画动词选择:
| 效果 | 动词 | 参数 |
|---|---|---|
| 树节点飞入 | fromTo({opacity:0,scale:0,...},{scale:1,opacity:1}) | ease:"back.out(1.7)" |
| 边生长 | fromTo({strokeDasharray:220,strokeDashoffset:220},{strokeDashoffset:0}) | duration:0.6 |
| 脉冲高亮 | fromTo({},{scale:1.15,duration:0.25,yoyo:true,repeat:1}) | ease:"power2.inOut" |
| 列表节点延迟出现 | forEach + stagger | i*0.25 |
| 类打字机 | fromTo({opacity:0},{opacity:1,stagger:0.08}) | span 级别的 stagger |
| 颜色过渡 | to({color:"#7ee787",duration:0.3}) | 配合 CSS transition |
textContent: 写入含 <b>,请用 innerHTML:from({opacity:0}) 要求 CSS 里没有 opacity:0(否则永远看不到)querySelector(`#${id}`) 会被 lint 拒绝 → 用字符串拼接 '#' + id<circle> 必须有显式 cx/cy/r,即使你打算用 GSAP attr:{cx:...} 改它。npx hyperframes validate 用 headless Chrome 解析 SVG,缺 cx/cy 直接报 "Unexpected end of attribute" → 整段渲染失败。Particle/ring 元素也照此办理。tl.to(...) 紧跟 tl.fromTo(...) 同一元素同一时间点同一通道(tl.to({opacity:1}) + tl.fromTo({opacity:0},{opacity:1}) 在 t=0.4)→ lint 报 overlapping_gsap_tweens,删掉冗余那个。fromTo(opacity:0.95) 后再 to(opacity:0) 也会触发 overlap warning。两者都是合法连续动画,加 overwrite:'auto' 即可。font-family 出现在 CSS 但没有 @font-face → validate 报 font_family_without_font_face(error 不是 warning!)。HyperFrames 自动解析的字体只覆盖: Inter / Segoe UI / JetBrains Mono / DejaVu Sans Mono / Consolas / monospace / sans-serif。不要写 "PingFang SC" / "Microsoft YaHei" / "Noto Sans CJK SC" / "Noto Sans Mono CJK SC" / "Consolas"——后两个我刚踩过,等本地有 .woff2 再说。data-start + data-duration 不能跟任何 clip 边界相切——lint 把"315+30=345"跟"345+0=345"视为 overlap。永远错开 1 秒,或者把后面的 data-start 设为前一个 + duration + 0.1(更安全:+ duration)。height / scale / x 显现元素,不要把它也写进 opacity:0 的 prime 列表,否则 GSAP 改了 height 它们还是 opacity:0(柱状图、扇形进度条、放大缩入的 logo 都是高发区)。只 prime 你打算用 opacity 显现的元素。data-duration 必须 ≥ 最后一个 clip 的 data-start + data-duration,改完子 clip 边界要顺手更新根。否则最后一段会被无声裁切。npx hyperframes info 会显示 root duration,改前看一眼。t2a_v2 同步语音 API,不是切对话/视觉模型。判别三步法(看上下文 / 看动词 / 看"那个"指向)见 references/tts-intent-disambiguation.md。这条踩过一次(2026-06),二次 clarify 才到位,代价是 1-2 轮会话。min(实测时长, 下章扉页起点 - 本章扉页起点),溢出用 ffmpeg -t 裁切。否则音轨溢出到下章扉页,画面已经切到下章但声音还在讲上一章尾巴——很难受。完整拼接范式见 references/voiceover-and-captions.md 坑 5 + scripts/align_and_merge.py。references/voiceover-and-captions.md 坑 6。data-start(2026-06-23 实测踩过,经过两轮修正才得到真值)。data-start 是 clip 起点,GSAP 入场动画(fromTo({opacity:0, ...}) 等)会让扉页大标题真正出现在画面上的时间比 data-start 晚约 1 秒(不是之前估的 3-6s)。配 TTS 旁白时,如果按 data-start 拼音轨,会出现"声音讲下一章,画面还在上一章"的错位。绝对不要信 data-start,必须用 ffmpeg 抽帧 + vision 看实际帧定边界。实测 7 个章扉页:data-start=[25,175,305,405,555,740,800] → 视觉 [26,176,306,406,556,741,801](全章一律 +1s)。脚本范式见 scripts/probe_chapter_starts.py。scripts/probe_chapter_starts.py 的 1fps 分支就是这个范式。带圆圈 + 标签的状态机,标签很容易掉进圆内触发 inspect 的 content_overlap warning;Org Roam 风格的双向链接图也有自己的节点+边+脉冲环范式。完整 SVG 模板、圆/标签坐标避让规则、5 类节点配色、GSAP 进场顺序见 references/svg-state-machine-and-graph-patterns.md。
hyperframes lint # 0 errors required
hyperframes validate # 0 errors required; 对比度 warning 可选
hyperframes inspect # 0 layout issues
hyperframes render --output renders/video.mp4
lint 的 gsap_from_opacity_noop 非常常见——CSS opacity:0 + gsap.from opacity:0 = 永远不可见template_literal_selector 解决:不用 ${} 写 querySelectornpx hyperframes doctor视频没有配音等于幻灯片。完整 TTS / 字幕 / 引擎降级 / ffmpeg 拼轨写在 references/voiceover-and-captions.md,关键四点先记在脑子里:
hyperframes-media skill,不要直接用 npx hyperframes tts。npx hyperframes tts 是 Kokoro-only 本地降级版本,HeyGen/ElevenLabs 即使 env 有 key 也会被它静默吞掉。统一入口是 skills/hyperframes-media/scripts/audio.mjs。espeak-ng 系统库,否则 Kokoro 在 phonemizer 阶段会报 language "zh" is not supported by the espeak backend → TTS 失败。pip install kokoro-onnx 不带 espeak-ng,得 apt-get install espeak-ng / brew install espeak-ng / guix 用户 profile guix install espeak-ng。装完重启 shell 让 PATH 生效。data-start..data-duration 的 clip,语速 4-5 字/秒中文,英文术语保留不翻(M-x / use-package / vertico),开头带过渡词接上段。逐段生成 wav 后用 ffmpeg 按时间戳拼回 880s 主轨,mux 进 mp4。t2a_v2(端点 + 鉴权 + 完整请求 schema 见 references/voiceover-and-captions.md 坑 3 节)。Key 在 ~/.local/share/hermes/.env 的 MINIMAX_CN_API_KEY,可复用脚本在 scripts/minimax-tts.py。别凭印象编 endpoint(这一条以前的 skill 自己写过反话,被实测打脸了)。references/voiceover-and-captions.md 里有 25 段 Elisp 教程的真实配音稿范本(可直接套用)、踩过的坑(Kokoro 中文走 espeak 失败 / hyperframes CLI 吞云端 key / MiniMax 厂商 vs 模型意图混淆 / execute_code 子进程不继承 env),以及 4 个实测中文男声音色试听路径。
如果用户用"minimax"一词模糊,先看 references/tts-intent-disambiguation.md 三步法再动手。
<div class="title"><span class="emacs">Emacs</span> <span class="lisp">Lisp</span></div>
<div class="subtitle">求值 · 变量 · 函数</div>
<div class="chapter">
<div class="chapter-num">Chapter 01</div>
<div class="chapter-title stamp">标题</div>
<div class="chapter-en">副标题</div>
<div class="chapter-bar"></div>
</div>
<polygon points="280,200 360,270 280,340 200,270" fill="#1c2128" stroke="#d2a8ff" stroke-width="3"/>
<text x="280" y="265" text-anchor="middle" font-family="JetBrains Mono" font-size="20" fill="#d2a8ff">COND</text>
<div class="code-block" style="background:#161b22; border:1px solid #30363d; border-radius:12px; padding:20px 28px; font-family:JetBrains Mono; font-size:22px;">
<span class="k">(defun</span> <span style="color:#7ee787">my/greet</span> ...
</div>
| 内容量 | 总时长 | 场景数 | 每场景时长 |
|---|---|---|---|
| 15-20 章 | 13 分钟 | ~35 个 | ~22 秒 |
| 8-10 章 | 6 分钟 | ~18 个 | ~20 秒 |
| 3 章(试水) | 2:40 | 11 个 | ~14 秒 |
每章 = 扉页(5s) + 1-3 个内容场景(30-50s)