mcpField
M
meme-creator

meme-creator

github.com/daymade创意与媒体1.5k115 次安装今天更新
代码仓库

关于 meme-creator

meme-creator 是一项将图片叠加到视频移动对象上并导出 MP4 和 GIF 的技能。流程强调先确认素材身份,再检查跟踪结果并验证编码后的成品。

主要功能

  1. 01获取素材前核验身份
  2. 02逐帧跟踪对象
  3. 03静态画面或长镜头使用手动关键帧
  4. 04控制叠加层显示与淡入淡出
  5. 05导出并调整 MP4 和 GIF 大小

适用场景

  1. 01为移动对象添加标志或头像
  2. 02用手动位置制作单帧表情包
  3. 03检查场景切换时的叠加效果
  4. 04制作符合聊天大小限制的 GIF

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/daymade/claude-code-skills --skill meme-creator

安装后在 Claude Code 中输入/meme-creator确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
asset-binding.md
tracking-playbook.md
scripts/
encode_outputs.sh
make_sheets.py
render_overlay.py
track_boxes.py

详细介绍

表情包制作器

将视频片段制作成表情包:把图像(徽标、头像、贴纸)贴到运动物体上,让它们逐帧跟随运动,最终输出 MP4 + GIF。

导致成品毁于一旦的问题不是跟踪漂移,而是因为名称绑定到了第一个看起来合理的账号,结果把错误的人的头像贴到了屏幕上。因此,第 0 步是确认身份,而不是准备工具。

制作静态图像表情包时,可完全跳过跟踪:在叠加层配置中,为每个目标添加一条 manual_keys 条目([[1, [x, y, w, h]]]),然后只渲染该帧——如果所有位置都来自键帧,--tracks 可以省略。

要求

  • ffmpeg 位于 PATH 中
  • uv — 所有随附的 Python 脚本都带有内联依赖;使用 uv run <script> 运行,依赖会自动解析
  • 仅在下载时需要 yt-dlp(uv run --with yt-dlp yt-dlp ...)
  • 仅在栅格化 SVG 徽标时需要 Chrome/Chromium(asset-binding.md)
  • 下文中的脚本路径写作 scripts/…,相对于此技能的包目录。解析一次包路径(SKILL_DIR=<path to this skill>),并运行 "$SKILL_DIR"/scripts/make_sheets.py …——你的工作目录应是临时目录,而不是包目录。

工作流

在临时目录(/tmp/<meme-name>/ 或类似位置)中操作,只交付最终的 MP4 + GIF。

0. 获取素材前先确认身份

当用户指定屏幕上要出现的人物或对象(“Codex、Claude 和 Tibo 的头像”)时,每个有歧义的名称都必须通过 references/asset-binding.md 中的消歧流程——使用不含账号名的搜索列出候选项,根据请求上下文进行区分(并列提到的同类实体是最强信号);若上下文无法判断,则询问用户。该文件还介绍了徽标和头像的来源、使用无头 Chrome 将 SVG 转为带真实透明通道的 PNG,以及徽章样式。合成之前,先获取并检查每张图像。

1. 获取源文件

本地文件:直接使用。URL:yt-dlp 可处理 bilibili(包括 b23.tv 短链接)、YouTube 和大多数网站:

uv run --with yt-dlp yt-dlp -f "bv*+ba/b" --merge-output-format mp4 -o "source.%(ext)s" "<url>"

检查时长:ffprobe -v error -show_entries format=duration -of csv=p=0 source.mp4

2. 定位片段

绝不要跟踪“整段视频”。先用 1–2 fps 联系表找到准确场景,再扩大范围:

ffmpeg -v error -ss <start_s> -t 40 -i source.mp4 -vf "fps=1,scale=240:-1,tile=5x8" -frames:v 1 contact.png

查看联系表,选出节拍边界(入场 → 动作 → 离场),并在最终片段两端各留 ±1 秒余量。按原生 fps 提取帧序列:

mkdir -p seq && ffmpeg -v error -ss <seg_start> -i source.mp4 -t <seg_dur> seq/f_%04d.png
ffprobe -v error -select_streams v:0 -show_entries stream=r_frame_rate -of csv=p=0 source.mp4
3. 准备叠加素材

每个目标准备一张带 alpha 通道的 PNG 图像。将不同类型的素材(应用图标 + 徽标图案 + 照片头像)统一制作成 circle-white 徽章——关于原因和头像圆形蒙版的处理方法,请参阅 asset-binding.md。

4. 跟踪目标

完整流程和故障分类: references/tracking-playbook.md。简要步骤:

  1. 网格化一帧所有目标都完整可见的画面: uv run scripts/make_sheets.py grid --frames 'seq/f_%04d.png' --index 30 --out grid.png 并从网格中读取每个目标的 [x, y, w, h] 边界框。
  2. 编写跟踪配置(目标 + 初始帧),然后运行: uv run scripts/track_boxes.py --frames 'seq/f_%04d.png' --config track.json --out tracks.json --last <N>
  3. 验证:uv run scripts/make_sheets.py tile --frames 'seq/f_%04d.png' --tracks tracks.json --start 1 --end <N> --step-frames 15 --out verify.png 并检查每个切片。
  4. 根据切片显示的情况修正:为后续片段重新锚定(镜头切换、尺寸骤变、漂移),或使用 manual_keys 接管平稳的长镜头。预计需要 2–3 轮。然后为每个离场、入场和空白片段标记 visible/fade_in/fade_out——徽标停留在空画面上,是最明显的错误。
5. 渲染
uv run scripts/render_overlay.py --frames 'seq/f_%04d.png' --tracks tracks.json \
  --overlays overlays.json --out 'out/o_%04d.png' --last <N>

编码前,抽查渲染后的联系表(对 out/ 运行 make_sheets.py tile)——这比重新编码便宜得多。

6. 编码与大小预算
scripts/encode_outputs.sh --frames 'out/o_%04d.png' --fps <native_fps> \
  --source source.mp4 --ss <seg_start> --t <seg_dur> --mp4 meme.mp4 \
  --gif meme.gif --gif-width 400 --gif-fps 10 --gif-colors 96

GIF 的文件大小取决于帧数 × 抖动噪声,而不是调色板大小。要符合约 10 MB 的聊天应用预算,请按以下顺序调低参数:先调低 --gif-fps(15→12→10),然后调低 --gif-width(480→400),最后调低 --gif-colors(128→96)。

7. 检查编码后的交付文件,然后交付

从最终 MP4 和最终 GIF 中提取帧(ffmpeg -ss <t> -frames:v 1)并查看——前面的检查验证的是中间产物;这一步验证的才是接收者实际会看到的内容。交付这两个文件,并使用它们的准确路径。

故障排查

症状原因修复方法
在国内网站上 yt-dlp 报错:Tunnel connection failed 503本地 HTTP 代理拦截添加 --proxy ""
cairosvg/svglib 崩溃:no library called cairo缺少系统 cairo通过无头 Chrome 栅格化 SVG(asset-binding.md)
跟踪器恰好在镜头切换时失效CSRT 无法跨越剪辑点在新镜头的第一帧添加新的 segments 条目
框在约 1 分钟内缓慢偏离目标模板污染使用跟踪器自身上一次的有效框重新锚定,或使用 manual_keys
主体离开后,Logo 停在画面中间缺少可见性时间段在主体离开前设置 fade_out,之后不要设置 visible 范围
GIF 大幅超出大小预算抖动噪声 × 帧数先调低 --gif-fps,然后依次调低宽度和颜色数
Logo 在 PNG 中看起来正常,但在 GIF 中不对只检查了中间产物始终检查编码文件中的帧(第 7 步)
编码失败:Failed to set value '1:a' for option 'map'源片段没有音频流捆绑脚本会映射 1:a?(可选);如果手动运行 ffmpeg,也要这样做,或者去掉 --source

参考资料

评论

支持 Markdown