sweety-handdraw-video:让 Agent 按旁白作画的手绘视频 Skill——预算制分镜、拟人运笔与 21 种画风

对 threerocks/sweety-handdraw-video 的深度拆解:一周 715 star 的手绘讲解视频制作 Skill。它不调用图生视频模型,而是让 Agent 当导演、本地 Python 引擎当画手:先按真实旁白时间戳算分镜预算再生图,用 420px/s 运笔、4 倍速 lapse、右手偏好的抬笔位移还原拟人绘制,GB2312 汉字按标准笔顺书写,六种导演密度模式各有硬性契约,158 项回归与分层检查(工程/观感/听感分开记录)兜底。本文拆它的五步流水线、storyboard_lint 的预算公式、line_drawing 的物理常数、六款手臂与 21 种画风、四类配音后端与语义分段门禁、50MB 离线包与 SHA-256 镜像修复,以及它自己写进文档的边界。

先给结论:sweety-handdraw-video 不是"AI 视频生成"项目,它是一条「模型导演 + 本地引擎」的混合流水线——把创作判断交给 Agent,把渲染确定性交给 Python 脚本。 市面上的图生视频方案(Sora、可灵一类)走的是「文本提示 → 扩散模型整段生成」,笔触不可控、内容不可核对、中文字写不出笔顺、画面时间轴对不上旁白。这个项目换了一条路:Agent 负责理解内容、写口播、设计分镜、生成插画;本地引擎负责逐笔描线、按笔顺手写、配音对齐和导出,每一笔的位置和时刻都是算出来的,不是抽出来的。

图:《那条死于愤怒的蛇》样片封面,v1.2 流程制作,49 秒淡彩叙事插画

目录

  1. 它是什么:一周 715 star 的手绘视频 Skill
  2. 它解决的问题:手绘视频为什么难
  3. 五步流水线:从主题到成片
  4. 预算制分镜:先算画得完,再生图
  5. 六种导演密度模式
  6. 像人一样画:运笔的物理常数
  7. 渲染引擎与字幕硬门槛
  8. 配音:旁白先行与语义分段门禁
  9. 21 种画风与六款手臂
  10. 工程细节:50MB 离线包与镜像修复
  11. 诚实的边界:它自己写下的限制
  12. 成熟度评估
  13. 结语

一、它是什么:一周 715 star 的手绘视频 Skill

一句话:一个安装在 Claude Code / Codex 里的 Agent Skill,输入一个主题、一篇文章或一个完整故事,输出边画边讲的有声 MP4——Agent 当导演,本地 Python 引擎当画手。

数据快照(2026-10-20 通过 GitHub API 与仓库源码核实):

维度数据
仓库threerocks/sweety-handdraw-video
定位手绘口播视频制作 Skill(白板动画 / 文章转讲解)
Stars / Forks715 / 136
Open Issues2
创建时间2026-10-12(至今 8 天)
累计提交76
最新 Releasev1.4.1(2026-10-19);包内 VERSION 文件为 1.4.1
许可MIT(主项目;内置依赖保留各自许可)
文件总数1,009(其中 skills/ 占 981,即内置依赖与素材)
安装包体积843 个文件 / 49.4 MB(v1.3 实测核验)
宿主与平台Claude Code、Codex;macOS 与 Linux(Windows 暂不承诺)
技术栈Python 3.9+(Pillow / NumPy / SciPy / fontTools)+ FFmpeg
作者leo_xiaolei(X:@leo_xiaolei)

几个数字值得单独说:

8 天 715 star、76 次提交。这个star 增速在工具类项目里属爆发级别,且迭代极快——10-12 建仓库,10-13 就连发 v1.2.1/v1.2.2/v1.2.3 三个封板,10-17 发 v1.3,10-19 发 v1.4.1。版本号里能看到功能演进:v1.2 封板包含整篇连续旁白和原片参考导入,v1.3 加了声音门禁和素材随包,v1.4 转向原生选项、9:16 竖屏默认和导演密度契约。

1,009 个文件里 981 个在 skills/ 目录——这不是冗余,是它把五个上游项目以固定快照内置了:

内置依赖职责
sweety-image-art-direction主体、接触关系、构图、比例与观看主次
hand-drawn-styles风格配方、参考锚点与预览
omniailab-ai-director导演规划、叙事、声画关系与终审方法
huashu-art-motion适用题材下的艺术动效方法
sweety-image-privacy图像隐私元数据清理与审计

「内置而不安装」是个明确的工程取舍:运行时不自动追踪上游更新,用快照换可复现。README 把来源、许可和固定快照写进了 THIRD_PARTY_NOTICES.md。

三条精选样片(均为 1920×1080、30fps,Release 下载):

样片时长风格配置
《那条死于愤怒的蛇》49 秒淡彩叙事插画、毛笔手部、无底板字幕
《快乐囚禁你的方式》1 分 52 秒冷色棱角插画、女性手部、连续女声旁白
《墨菲定律》约 2 分 05 秒淡彩速写、碎钻长甲手、笔杆文字;8 个画面、24 段口播

图:《快乐囚禁你的方式》封面图:《墨菲定律》封面,v1.0.0 历史样片

二、它解决的问题:手绘视频为什么难

要理解这个项目的设计选择,先得看清「让 AI 做手绘讲解视频」这件事难在哪。三条路线各有各的坑:

路线问题
图生视频模型(Sora / 可灵类)笔触是"抽"出来的,不可控、不可核对;画面时间轴对不上旁白;中文按笔顺书写基本无解
通用动画软件 + 手动 K 帧一条两分钟视频要 K 几百个关键帧,改一句话全部重来
开源白板动画工具(VideoScribe 类)模板化、素材库封闭,做不了内容驱动的定制插画

这个项目的答案是把流水线切成两半:

关键在于分工边界:模型负责"画什么、讲多久、用什么风",脚本负责"画得完画不完、运笔像不像人、字幕压没压图"。SKILL.md 里有一句话把这份分工写得很直白:

主体内容由模型设计;脚本只执行已确定的素材与时间线,并用客观指标拦截错误。

翻译成工程语言:模型是创作者,脚本是护栏。护栏不创作,只拦截——旁白没锁不给渲染、分镜没算预算不给生图、线稿门槛不过不给编排、检查记录过期不给交付。这套边界感是后面所有机制的前提。

三、五步流水线:从主题到成片

完整流程在 SKILL.md 里固化为六步,我按数据流重新画了一遍:

两个反直觉的顺序值得注意:

声音先于画面。 不是先出图再配音,而是先写完整口播稿、逐段合成、拼成母带、生成 alignment.json 逐句时间戳——然后用时间戳反推每幅画能画几秒。这解决了手绘视频最经典的死局:画面画完了,旁白没说这么长。

生图前先算账。 分镜按旁白算出每个 visual 的绘制窗口和笔数上限,图按预算设计。约 3 倍人速画得完就停,笔忙占比受模式约束且不超过 70%。画不完的图不是渲染时压缩时间轴(那会变成"快进糊弄"),而是上游简化图片或把窗口跨句延长——storyboard_lint.py 里对"引擎超预算"是直接判 error 的:

if asset.get('time_compression', 1) > 1.001 or ... speed_over_cap or ... fill_over_cap:
    errors.append(f'{label}: the engine exceeded its drawing budget; simplify the image or extend its window across beats instead of compressing its strokes')

四、预算制分镜:先算画得完,再生图

这是整个项目里我最欣赏的部分,也是它与"AI 生成视频"拉开本质差距的地方。核心问题一句话:给定一段真实时长的旁白,每幅图能画几秒、能画几笔? storyboard_lint.py(479 行)把这个问题做成了可执行的门禁。

4.1 绘制节奏的标定常数

STROKES_PER_SECOND = 3.5  # measured draw-v2 pace at the cap: contour strokes, pen lifts and marker color included
MAX_DRAWING_SHARE = .7    # the pen is busy at most this share of the narration

3.5 笔/秒不是拍的脑袋——注释写明是 draw-v2 引擎实测节奏,且轮廓笔、抬笔移动、马克笔上色都算笔数。70% 是笔忙占比上限:剩下的 30% 必须留给观众看完成图。这两个数决定了后面所有的分档和窗口计算。

4.2 按秒数分档的复杂度契约

def tier(seconds, hold):
    strokes = max(3, int(seconds * STROKES_PER_SECOND))
    if seconds < 3:
        return f'label or tiny icon: at most ~{strokes} strokes'
    if seconds < 6:
        return f'simple icon/silhouette: at most ~{strokes} strokes, flat fills'
    if seconds <= hold:
        return f'one subject: at most ~{strokes} strokes, flat fills, no texture lines'
    return (f'at most ~{strokes} strokes: a scene with background ... or split into two visuals')

一幅图能画几秒,就只允许几笔——不到 3 秒的窗口只配画个小图标或标签,超过单镜停留上限的要么画带背景的场景(靠部位分节拍撑时间),要么拆成两幅。复杂度不是美术喜好,是时间预算的函数。

4.3 窗口与视觉数量:两条硬公式

每个 visual 的绘制窗口这样算:

cursor = start + LEAD                                              # LEAD = 0.54
window = times[shot['beats'][-1]]['end'] - HOLD - cursor - GAP * max(0, len(visuals) - 1)   # HOLD = 0.6, GAP = 0.08
seconds = window * weight / sum(weights)

即:镜头内首 beat 起点 + 0.54 秒起笔,末 beat 终点前留 0.6 秒收尾,多个 visual 之间留 0.08 秒抬笔间隔,剩余时间按权重分配。窗口不足 0.5 秒直接报错:「only Xs to draw; give the shot more beats or fewer visuals」。

全片视觉数量也有下限:

required = max(1, math.ceil(narration / hold * rules['cadence_factor']))

旁白总时长除以单镜停留上限再乘模式系数——信息密度不够会被拦,而且报错信息直接告诉你该往哪加:

3 planned visuals for 92.0s of narration; at least 12 are needed (a new visual every 8s).
Add visuals to the sparsest shots: shot_07 (14.2s per visual), shot_03 (12.8s per visual) ...

插画占比也有要求:图片数少于 0.8 × required 且没写 text_only_reason 时判错;纯文字镜头超过 20% 时长同样拦。宿主没有生图能力时必须停下告诉用户,不允许静默降级成"文字滚动视频"——这条写在了错误信息里。

4.4 成片后的三项节奏复核

预算检查只是"计划",渲染完还有"实测"三件套:

指标门槛含义
pen_busy_share≤ 70%(模式可更严)笔在画的时间占比,含抬笔;超了说明完成图留不出阅读时间
finished_picture_hold_share≥ 30%完成图的静态阅读时间占比;不含片头空白和结尾静音
最长静止段≤ max_hold_seconds超过 hold 秒"什么都没画"直接报错,要求拆镜或加视觉

还有一条防偷懒的:同一张主图连续占超过 2 个 beat 会被拦,除非该镜标注了 callback 并写明理由。完成图停留时间的中位数低于模式要求会警告,单幅低于 1 秒也警告——注释里给了标定基准:「the first Codex film held only 0.56s on average, validated films hold 1.1-1.7s」。

4.5 镜头类型不是随便填的

七种 shot type 各有结构化真值条件,编剧意图要过代码校验:

SHOT_TYPES = {
    'scene_with_background': (lambda visuals: any(v.get('kind')=='illustration' and v.get('background') for v in visuals)),
    'comparison': (lambda visuals: sum(v.get('kind') in PICTURES for v in visuals) >= 2),
    'character_action': (lambda visuals: any(v.get('kind')=='illustration' and v.get('characters') for v in visuals)),
    ...
}

声明了 comparison 却只放了一幅图、声明了 character_action 却没有登记角色——都会被拦。角色必须绑定锁定参考图 + SHA-256,且绘制计划里要引用该参考图,防止跨画面角色漂移。

五、六种导演密度模式

v1.4 引入了 presentation.mode——这不是用户选项,是导演根据受众和内容推断的密度契约,写在 design.json 和 storyboard.json 里,由 storyboard_lint.py 强制执行。六种模式的参数差异很大:

模式密度单镜停留上限视觉节拍系数每镜图片上限每镜标签上限板复用笔忙占比完成图中位停留
picture_book稀疏10s1.3512否55%≥ 2.0s
focus_diagram(默认)中8s1.025否70%≥ 1.2s
dense_infographic密集7s0.9412是70%≥ 0.9s
accumulating_board密集12s0.55616是70%≥ 0.8s
step_sequence中8s1.0513否60%≥ 1.3s
narrative_comic中8s1.134否60%≥ 1.4s

几个设计细节:

accumulating_board(黑板报模式)的 cadence_factor 只有 0.55——同一块板跨 beat 累积,不需要每句重画整页,所以"每 hold 秒一幅新图"的要求减半。它还要求整页先规划 boards 的区域位置,同一块板在一张物理页面上按阅读顺序逐项补齐,不每句话清场。这是从"白板动画"向"课堂板书"的关键扩展。

模式必须带 reason。validate_presentation() 强制要求解释为什么这个模式适合受众和内容,density 字段还必须与模式内置值一致——想手动把 picture_book 标成 dense 会被拒。

模式是推断出来的,不是问出来的。infer_hints() 给模型的先验很直白:儿童叙事走绘本、单概念深挖走焦点图、清单对比走信息图、连续板书走黑板报、操作流程走步骤序列。用户不选,模型按内容定。

六、像人一样画:运笔的物理常数

如果说预算制分镜保证了"画得完",line_drawing.py(306 行)保证的就是"像人在画"。它的做法是把拟人感拆成一组可标定的物理常数:

常数值含义
LINE_SPEED420 px/s1080p 下人类描一条自信轮廓的笔速
SPEED_FACTOR4倍速标定:4–8 倍速的快手视频仍读作人类,前提顺序连贯
VIDEO_LAPSE3.0约 3 倍人速画完就停,绝不慢放填充窗口
FRAME_PX80 px描线笔尖单帧最大位移,超过就不像连续运动
TRAVEL_PX120 px抬笔移动的单帧峰值,防"瞬移"
DETAIL_BOOST1.6细节和短标记允许比主笔快 1.6 倍
PART_PAUSE0.18 s语义部位之间的思考停顿(随倍速缩放)
REVERSE_COST250 px右手偏好:宁可多绕 250 px,也不向左/向上画

这组常数撑起了几个具体的拟人机制:

转弯自动减速。 弧长计算不是欧氏长度,而是按曲率加权——steps * (1 + 1.5 * clip(turn / (π/8), 0, 1)),转弯处弧长膨胀,笔尖在曲线和拐角自然放慢。转角用 ±6 px 窗口测量,防止骨架像素抖动被误判为弯曲。

右手方向偏好。 REVERSE_COST = 250 的注释写得很直白:「px of extra travel a right-hander accepts rather than draw a line upward or leftward」。路径规划时,向左或向上画一笔要计入 250 px 的额外代价——于是笔画方向整体呈现出右手绘制的顺手感。倍速顶上还有个 HURRIED = REVERSE_COST / SPEED_FACTOR = 62.5:手快到顶上时,方向偏好让步于速度。

两种速度剖面。 stroke_profile() 按笔画长度和人速倍率切换:长笔画在倍速模式下用 plateau(两端缓入缓出、中间巡航),短笔画用 min-jerk。lift_seconds() 算抬笔时间——人类节奏 80–150 ms,随墨迹同步倍速,2 帧保底,且要满足抬笔移动的帧内位移不超 TRAVEL_PX。

部位分级与停顿。 笔画按 SILHOUETTE / KEY / STRUCTURE / DETAIL / TEXTURE 五档归类(KEY_PART 正则认 head/face/eye/mouth/nose/hand/finger/paw 这些关键部位),每个语义部分先轮廓后细节,部分之间停 0.18 秒——像人画完一个部分停下来想下一步。注释里给这部分的总纲是:

Order, time and render whole line strokes like a right-handed person: per part the silhouette first, then long interior structure, then details and short marks.

图:《那条死于愤怒的蛇》实际绘制过程节选(无声动图,v1.2)

七、渲染引擎与字幕硬门槛

video_renderer.py(529 行)负责把时间线渲染成帧:手部合成、路径文字、马克笔运动、水印。几个细节见功力:

手腕倾角上限 7 度(MAX_TILT = 7)——手臂跟随时加一点手腕转动,但不许过,过了就是"橡皮手"。阴影方向统一为向右下(SHADOW_DIRECTION = (0.555, 0.832),光源在左上),连笔杆阴影都按笔尖起算、随 barrel 距离漂移(PEN_SHADOW_SLOPE = 0.2)。手臂进出场 0.45/0.5 秒、镜头停留 1 秒——短于 1 秒的抬笔间隔会让手"留在画面里抢戏"。

每个像素都有语义归属。 质量门禁要求每个插画像素归到具体部位,所有轮廓结束后才填色,且两个阶段按同一部位顺序。部位审查还要处理遮挡关系——「发丝间露出的伞面属于伞,手持物不属于手臂,包与腿相交处按实际前后关系分配」。程序只能验证给定归属的执行顺序,不能证明模型分区语义正确——这句自我认知也写进了文档。

字幕唯一性是交付硬门槛。 同一句旁白同一时刻只允许一份字幕:画面烘焙、字幕事件、MP4 内嵌轨、网页 <track>、播放器自动加载,五条路都不许叠加。build 时就检查字幕避让——插画像素不得压进字幕区(含边距),不等渲染后才发现。编辑用字幕只能放 outputs/editing/。交付时检查成片无额外字幕轨、同目录无 SRT/ASS/VTT,并实际看解码画面的长句、换句和片尾。

检查记录分三层,不许互相顶替。 review.json 里工程检查(verify)、观感检查(visual / motion / content)、连续播放和实际听音分别记录。continuous_playback 和 listening 只能是 pass 或 not_done(写原因),做了 ASR 不等于听过——文档原话:「若只检查了 ASR,不能写’已经完整听过’」。抽帧能验证字形和版面,不能单独证明全片运动流畅。用户拒绝成片有专门命令:handdraw_video.py reject JOB --reason "用户原话",回执改为"用户已拒绝,需要返工",这一版不能再 finalize。

八、配音:旁白先行与语义分段门禁

声音在这条流水线里是时间轴的主锚,所有画面节奏都由它倒推。管线设计:

几个关键决策:

按语义分段,每段不超过约 100 字,只在句末切。 不按标点硬切、不跨句合并——保证每段的韵律完整,重读某句时只重新生成变化的语义段落。

每段过噪声门禁才保留。 嗡声、底噪、削波三项,不通过就换种子重试。这不是矫情——样片《那条死于愤怒的蛇》原版旁白带 235 Hz 嗡声,v1.3 门禁会直接拦截。拼接母带时用实测停顿,禁止"一律删静音、缩短所有停顿或全片交叉淡化"来掩盖错误,真实换气和语义停顿要保留。

四类配音后端,音色与后端分离:

路径说明
VoxCPM2 本地适配器Apple Silicon + MLX;项目用 VoxCPM2-8bit,权重约 3.23 GB
VoiceStudio 本机服务默认 http://127.0.0.1:3900,已对接 Qwen3-TTS-12Hz-1.7B-Base-bf16
现成整篇旁白离线编排渲染,不重新合成
火山豆包 / Gemini TTS用户自带密钥,非默认路径(只做过模拟 HTTP 测试)

六款声音里四款随包合成(磁性解说男声为默认、儒雅青年、温柔知性女声、悬疑故事解说),逼真男声/女声沿用原片参考、需用户自行导入。随包合成声音由本机 VoxCPM2 仅凭文字描述设计,未使用真人/主播/平台音色作参考;用户导入声音要声明授权(consent: self / consent: authorized),不克隆公众人物音色。作者本机环境是 M3 Max / 36GB——这是跑 3.23 GB 模型的家底,换个 8GB 的机器这条路直接不用考虑。

改一句话不必全部重做。 只改字幕/笔杆/水印/布局可复用图和声音;改口播正文只重新生成变化的语义段落。但改旁白后必须重算画面和字幕——「不能让视频页面成为声音切口」。

九、21 种画风与六款手臂

画风库是 20 个编号风格 + 一个稳定变体,按绘制方式分两类:

逐笔绘制(先描线后上色):编号 1、4、5、17、19、20——清晰墨线轮廓 + 平涂,这也是没有指定画风时模型默认挑选的范围。 揭示模式(笔带宽软笔刷按部位扫出成图):其余画风——只能由用户明确接受(reveal_accepted),因为"刷出来"和"画出来"是两种观感,不能替用户决定。纯黑白的 1 号要写明理由才用。

图:四种画风预览(4 小豆人涂鸦信息图 / 8 水墨写意 / 17 墨线绘本 / 19 圆头红线极简童画)

选择方式有四种:直接看预览选编号、库内自动匹配、模型独立设计(线条/颜色/明暗/材质/背景全自定义)、用户描述方向。风格选择器直接读包内预览,不访问网络——这是 v1.3 把 21 张预览图随包分发的原因。

六款手臂预设按笔尖到手腕校准,裁切边留在画外:

图:六款手臂预设总览

预设标识笔
深蓝袖马克笔navy马克笔
女性柔粉碎钻长甲diamond-woman同上笔型女性手
儿童彩铅child-pencil彩铅
上官婉儿灵感毛笔waner-brush毛笔
白衬衫中性笔teacher-pen中性笔
针织袖钢笔cardigan-fountain钢笔
仅画笔(无手臂)pen-onlynavy 同款笔去掉手臂

笔杆文字最多 16 个 Unicode 字符、水印最多 180 字符可换行——默认都不加。这两个选项本质是给做号的人留的商业化口子,作者没有默认塞广告。

十、工程细节:50MB 离线包与镜像修复

这个项目的工程质量不止在渲染管线,也在分发和资产完整性上。几个机制值得单独看:

10.1 安装体积的硬预算

validate_package.py 把「二进制文件禁令」换成了更实用的预算制:安装包总量 ≤ 50 MB、单文件 ≤ 10 MB,且包内预设必须与清单记录的哈希一致。v1.3 实测 843 个文件 / 49.4 MB 通过——贴着上限走,说明作者在主动管理体积。

同时按 omitted_showcase_media 机制移除了 omniailab 导演依赖里的 examples/motion 和 examples/images 宣传示例(533 个文件),方法文档和运行代码保留。README 特意说明:减小代码包不等于清理 Git 历史,没有改写历史提交。

10.2 资产修复:四级回退与哈希校验

手部、画风预览、试听共 30 个文件(约 8.8 MB)随包分发,hosted-manifest.json 为每个文件记录字节数、SHA-256 和有序镜像地址(jsDelivr CDN → Fastly → GitHub Release)。读取顺序:

三个细节:只有大小和哈希都一致的内容才写入缓存,不会"退回另一张图或另一种声音";HANDDRAW_OFFLINE=1 跳过联网直接说明缺失文件;HANDDRAW_MIRROR 支持 file:// 前缀——内网/Gitee 镜像可以顶上去。

10.3 一次真实的图床迁移

README 记录了一次值得写进教科书的资产运维事故:内置画风库的参考图原托管在 Netlify,额度耗尽停用,75 个链接变死链。修复方案是把链接整体迁到 jsDelivr 并固定到上游含图提交 cdfd004c89164096c861ad06ebab2aa1527d1710,Release 附件作最后回退。还有个更细的处理:五张运行参考锚点里三张清理了来源与模拟相机字段(逐像素一致),jsDelivr 返回上游原字节时校验不符,会自动转用 Release 清理版——清单保留上游字节校验值以便追溯。这种"清理过隐私的资产和上游原字节不一致"的边界情况,大多数项目到死都不会遇到。

10.4 纯 Python 隐私清理

图片隐私清理(clean_image.py)从原来的 Bun + ExifTool 改成纯 Python 实现——少两个外部依赖,setup.sh 也少两样要装的东西。所有生成图都要过这一步,元数据与来源属性分别报告,且文档明确:隐私处理不等于 AI 检测保证。

10.5 测试与验证

v1.3 记录:158 项回归通过(1 项平台用例跳过)、离线冒烟短片通过、安装包 843 文件 49.4 MB 通过核验。scripts/ 下 71 个文件里 test_*.py 有 30 个——对一个 Skill 项目来说测试密度相当高,且 smoke_test.py 可以离线跑通整条渲染链。

十一、诚实的边界:它自己写下的限制

这个项目的文档质量里最难得的,是把边界写在明面上:

边界原文口径
平台macOS 与 Linux;Windows 暂不承诺;宿主限 Codex 与 Claude Code
生图能力宿主无法生成图片时必须停下说明,不能交付只有文字的视频
稳定性不承诺任意主题一次稳定生成
笔顺范围GB2312 范围内汉字按标准笔顺,其余字符按字形描线
耗时与费用作者自述两分半样片"差不多 10 分钟"、200 美元订阅环境"不到 1%"——特定账号自述,非统一计量
橡皮擦转场无交付证据,不列为现成功能
AIGC 标识MP4 已写入隐式标识,发布时仍须按平台规则声明"AI 生成"
声音验收ASR 正确 ≠ 听感好;无听音工具时必须在交付说明里保留"主观听感未验收"
系列批量可固定画风配方和角色锚点,但仍可能漂移,每条都要检查

还有一条容易被忽略的:脚本不能替代观看。文档反复强调「最终实际画面仍须检查,不能以程序检查替代观看」「工程能约束检查是否完成和证据是否对应当前图,不能自动理解’切断’」。叙事事实甚至要做进图里——《蛇》样片的"身体切断"必须在 drawing-plan 里列为 narrative_requirements,要求两处可见空隙与断开的蛇段,看图时按相同 id 记录证据。把"剧情真实性"做成可勾验的契约,这是我对这个项目印象最深的细节之一。

十二、成熟度评估

维度评价依据
概念完整度高主题/文章/故事/定稿四类输入都有明确处理规则,修订可分层复用
工程严谨度高预算制分镜、拟人运笔常数、哈希资产校验、版本封板记录,都是踩过坑的正解
文档质量很高SKILL.md + 14 份 references,限制和代价写在明面上,不营销
测试覆盖中高158 项回归 + 冒烟短片 + 打包核验;但完整制作实测仅来自 macOS + Codex
平台覆盖中明确不支持 Windows;Claude Code 侧"整片流程待实测"
社区活跃度高8 天 715 star / 136 fork / 76 提交,作者在 X 持续更新
API 稳定性中自我标注 dev;本地 1.3/1.4/1.4.1 曾为未公开迭代号,公开标签后置对齐
主观质量保证无观感、听感、学习效果明确不承诺,检查记录分层留痕

一句话:这是一个"作者自己天天在做片"的项目。判断依据不是 star 数,而是那些只有真正做过片才会加的机制——3.5 笔/秒的标定(被画不完的图坑过)、235 Hz 嗡声门禁(被样片杂音坑过)、Netlify 死链迁移(被图床坑过)、字幕唯一性硬门槛(被双字幕坑过)、“做了 ASR 不等于听过”(被自己的验收记录坑过)。每一条都对应一次具体的翻车。

十三、结语

回到开头那个判断:它把"AI 做视频"从生成问题重构成了约束满足问题。

图生视频模型的范式是"生成然后祈祷"——抽一笔、看结果、不对再抽。这个项目的范式是"先算账再动手"——旁白时长决定绘制窗口,窗口决定笔数上限,笔数决定图片复杂度,复杂度决定生图提示词。渲染引擎只执行已验证可画的计划,预算不够就在上游改分镜,绝不靠压缩时间轴糊弄。确定性不是从模型里榨出来的,是从流水线的结构里长出来的。

但它真正值得学的地方,是那份贯穿所有文档的分工自觉:模型该做的(理解、创作、判断)和脚本该做的(标定、拦截、核验)划得很清,而且双方都不越界——脚本不假装能审美,模型不假装能保证。放到更大的语境里,这其实是所有 Agent 产品都要回答的问题:当执行者是不可靠的智能体时,工程系统的价值就在于把"不可靠"约束在可验收的边界内。

对普通读者,它的实用价值也很直接:有一条两分钟的知识讲解/寓言故事/产品原理要做口播视频,又不想出镜、不想 K 帧、不想学动画软件——装个 Skill,把文章丢给 Agent,喝杯咖啡回来审片。macOS 用户现在就能试;Windows 用户(比如我)只能等,或者去催作者。

承认自己做不到什么,比宣称自己什么都能做,更能建立信任。 这条在工程上和在别处一样成立。

免责声明:本文基于 2026-10-20 的仓库快照(main 分支、Release v1.4.1)与公开源码、SKILL.md、references 文档及 GitHub API 数据撰写,所有代码片段与常数均可在仓库 skills/sweety-handdraw-video/scripts/ 核对。文中「实测」指作者记录的 v1.3 验证结果(158 项回归、843 文件 49.4 MB 安装包等),非本文在本机复跑;本文未在 macOS 环境实际制作视频。项目仍在高速迭代,接口、默认值、支持平台均可能变化,使用前请以仓库最新 README 与 SKILL.md 为准。文中引样的星标、提交数等动态数据随时间变化。本项目涉及本地运行第三方 TTS 模型与声音素材,声音授权与平台 AIGC 声明规则请自行确认遵守。