Communitygithub.com

furkanisikay/meme-reels

将知名的土耳其表情包片段与土耳其语TTS配音、逐词字幕及数据驱动的动画场景相结合,生成1080×1920竖屏Instagram Reels/TikTok/YouTube Shorts视频(MP4格式)。

meme-reels 是什么?

该技能专为在热门短格式竖屏平台上轻松创建引人入胜的土耳其语解说视频而设计。它通过将熟悉的土耳其影视表情包片段与基于数据的动画解说场景完美融合,以幽默且易于理解的方式解释某个概念、产品或故事。整个过程高度自动化,使用Chromium逐帧渲染HTML场景,并通过NumPy合成和混音音频,最终生成符合最高媒体平台标准的专业级MP4文件。该技能提供了一个确定性的工作流程,包括事实收集、脚本编写、表情包选择、场景构建、音频配音、预览、渲染和修正迭代。它支持DAILYMOTION上的表情包搜索、本地文件或URL导入,并利用免费的Edge TTS服务进行配音,同时允许用户录制自己的声音以获得更真实的效果。用户只需描述他们想要创建的视频主题,如“reels”、“tiktok”、“meme'li video”或“dikey video”,该技能即可自动处理所有技术细节,生成一个完整的、可立即发布的视频文件。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/furkanisikay/meme-reels/tree/HEAD/skills/meme-reel

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

Meme reel

此技能将一个主题转化为即使是最不了解情况的观众也能理解的竖屏视频。观众会因每个人都能认出的土耳其电视剧/电影片段而发笑,同时通过中间的动画场景和配音了解主题。引擎是确定性的:HTML场景在Chromium中逐帧渲染,音频通过NumPy合成并混音。

现成示例:examples/ardupilot-mcp/(36秒,4个表情包,6个解说场景)。开始制作新Reel之前,请先阅读其中的plan.json、fx.js和scenes/文件;你可以在那里看到所有功能的实际运作。

限制

  • 不要发布任何内容。 将视频作为文件提供给用户。即使要存入缓冲区或其他平台的草稿箱,也只有在用户当时明确同意的情况下才能进行。发布步骤在buffer-sosyal-icerik技能中。
  • 屏幕上的每个数字和主张都必须经过验证。 请注明日志、测量结果、工具输出或用户提供的来源。不要将你无法验证的主张(如“1分钟解决”)放入视频。
  • 不要添加注释行。 即使你使用了模拟或演示数据,也不要向视频和描述中添加“注意:”或诚实声明行;只有用户明确要求时才添加。不要在第一个画面上写像“模拟器中的一次试验”这样的钩子。
  • 版权: 电视剧/电影片段受版权保护。如果用户未接受风险,请先询问。不要删除来源标志(例如 TRT 1);裁剪掉第三方广告水印(如博彩网站)。
  • TTS 许可证: edge-tts 使用免费的 Edge 语音朗读服务;其商业用途处于灰色地带。对于商业发布,同样的语音可通过 Azure Speech 获得许可,或使用用户自己的声音。

发布文本

如果用户需要说明文字:

  • 不要重复视频中的句子。说明应讲述视频未讲述的内容:产品是什么、对谁有益、在哪里可以找到。
  • 就像一个人给朋友发信息一样,用日常土耳其语书写。最后以一个邀请评论的问题结束。
  • 不要添加“注意:”或诚实声明行。 模拟、演示数据、AI 使用等说明不应出现在说明文字中。如果需要 AI 标签,则通过平台自己的设置进行标记。
  • Instagram 说明中的链接不可点击。如果视频和文字中说“链接在个人资料中”,请让用户确认个人资料中确实存在链接;没有任何 API 可以更改个人简介。对于 YouTube 说明,请直接写入链接本身。

安装

bash scripts/setup.sh        # pip: edge-tts faster-whisper numpy scipy yt-dlp; ffmpeg ve Playwright kontrolü

与运行环境相关的已知问题(代理/TLS、YouTube 机器人检测、Chromium 缺少 H.264、Whisper 和 PyAV)及其解决方案在 references/pitfalls.md 中。卡住时可以查看那里。

流程

  1. 收集事实。 从来源中提取视频的主张:工具输出、日志、测量结果。将数字和时间记录下来;场景将使用这些值。如果屏幕上有安装命令,请验证该包在仓库(PyPI, npm)中确实存在,并写下受众熟悉的命令:pip install paket, npm i paket。像 uvx 这样的工具是针对 MCP 配置文件的;对普通观众来说比较陌生。
  2. 编写脚本(参见下面的模板)。每个解说语句持续 2-7 秒,每个表情包持续 1-3 秒。
  3. 选择表情包。 首先查看 references/tr-memes.md 目录(已验证台词和时间戳的片段)。对于新片段,使用 python3 scripts/reel.py search "erdal bakkal" 在 Dailymotion 上搜索,下载后使用 reel.py stt 找到台词的确切秒数。使用 reel.py still KAYNAK SANİYE 命令输出的网格图像测量脸部位置(cropx)。
  4. 设置项目: 创建 plan.json, style.css, fx.js,如果需要则创建 data.js 和 scenes/*.html。复制并修改示例是最快的方法。
  5. 裁剪并验证片段: reel.py clips PROJE。系统会将每个片段的 Whisper 识别文本与 quote 并排打印出来。如果不匹配,请调整时间。
  6. 配音: reel.py tts PROJE --verify。如果 Whisper 听错了一个词,那么 TTS 也会读错它;请将 say 文本按发音拼写(例如 ArduPilot em si pi'ye),同时确保正确的文本通过 show 显示在屏幕上。
  7. 编辑和预览: 先运行 reel.py build PROJE,然后运行 reel.py preview PROJE。build/sheet.png 会显示每个场景的 3 帧。打开这张缩略图检查以下内容:溢出或重叠的元素、进入安全区的文字、空白屏幕、无法阅读的字幕。修复后,重复此步骤。
  8. 渲染: reel.py render PROJE --verify → PROJE/out/<title>.mp4。输出会显示时长、集成音频(应接近 -14 LUFS)和峰值;--verify 会让 Whisper 处理整个视频。如果所有解说和表情包对话都能被正确听清,则说明音乐没有压制语音。
  9. 将视频发送给用户。简要说明你使用了哪些片段、来自哪个来源、它们带来的风险(版权、TTS 许可证、低分辨率来源)以及你反对的编辑决定。
  10. 修正轮次。 如果用户要求更改某个场景的文字或图像,请在不解说词和场景持续时间的情况下进行修改,然后运行 build + preview --at 查看该帧,接着运行 reel.py render PROJE --from <sahnenin başlangıç saniyesi>。之前的帧会被保留,仅从该点之后开始重新渲染。如果解说词发生了变化,持续时间会偏移;此时需要进行完整渲染。
  11. 发布。 如果用户说“分享吧”,则切换到 buffer-sosyal-icerik 技能:视频通过其中的托管步骤上传,Reel、Shorts 和 Story 使用同一个文件。Story 中的链接贴纸不会自动发布;请查看该技能中的 Story 部分。

脚本模板

钩子规则及其理由在 references/hooks.md 中。简要形式如下:

节拍时长发生什么
钩子0-3 秒从事件中间切入(坠落的无人机,红色错误)。第一帧上应已显示一个 4-7 个词的句子;即使静音观众也能理解。
反应表情包1-2 秒惊讶(“怎么了?”)。紧接在钩子之后。
问题3-6 秒用一个具体的数字展示问题的严重性(1,558,457 行)。
反应表情包2-5 秒对问题的荒谬之处用一到两个表情包来回应。顶部文字(cap)将表情包与主题联系起来。
解决方案3-4 秒使用产品的时刻;真实的界面或高度逼真的仿制品。
回答4-7 秒主要的发现,带有数据驱动的动画。最长且最具“教育意义”的场景。
价值2-3 秒免费、开源、安装命令等。
催促表情包1-2 秒向观众喊话的表情包(“还在等什么,Behzat?”)。
收尾3-5 秒应该做什么 + 读出“链接在个人资料中”。

总时长 25-36 秒。如果超过 30 秒,建议缩短最长的解说词句子。

plan.json

{
  "title": "<Konu> - Reels <ad>",            // 输出文件名
  "voice": "tr-TR-EmelNeural", "rate": "+6%", // tr-TR-AhmetNeural 在此服务中无法返回声音
  "clips": {                                   // 表情包来源
    "neoldu": {"dm": "x587xuk", "start": 37.80, "dur": 1.06, "cropx": 135, "quote": "— Ne oldu?"}
    // 来源: "dm" (Dailymotion id) | "url" (yt-dlp) | "file" (本地). 模式: "face" (4:5 脸部裁剪,默认) | "fit" (广角)
  },
  "lines": {                                   // 解说词;"show" 为屏幕上显示的文本(可选)
    "n1": {"say": "Dronum yirmi metreden düştü.", "show": "Drone'um 20 metreden düştü."}
  },
  "scenes": [                                  // 按顺序播放;时长根据音频计算
    {"id": "a", "line": "n1", "html": "scenes/crash.html", "pad": 0.25, "cap": "可选顶部文字"},
    {"id": "m1", "clip": "neoldu", "cap": "可选顶部文字"}
  ],
  "music": {"style": "phonk", "bpm": 120, "level": 0.42, "mute": [["a@düştü+0.05", "b"]], "light": []},
  "sfx": [{"fx": "boom", "at": "a@düştü+0.1", "gain": 1.0}]
}

如果 show 的单词数与 say 相同,则每个单词占据自己的时间;否则,单词将匀速分布在整个解说时长内。表情包场景的时长就是片段的时长;解说场景的时长则是音频时长 + 0.08 秒 + pad。

编写场景

每个解说场景包含一个 HTML 片段(scenes/<ad>.html)和一个在 fx.js 中的 FX.<id> 函数。场景被放置在一个 <section id="<id>" class="k-<ad>"> 容器内。引擎会自动处理剪辑、推进式缩放、cap 动画、表情包帧替换和卡拉 OK 字幕;FX 仅绘制该场景特有的动态效果。

FX.d = ({ s, el, t, lt, d, punch, word }) => {
  // lt: 场景内秒数,d: 场景持续时间,t: 视频时间(秒)
  // word('motor', 0.5): 单词"motor"被说出的场景内秒数(如果找不到则返回0.5)
  pop($('mhead'), lt, word('motor'), 0.3);           // 弹入出现
  stamp($('tag2'), lt, word('yetme'), 'translateX(-50%)'); // 溢出放大
  type($('cmd'), 'pip install ardupilot-mcp', lt, 0.1, 0.8); // 打字机效果
};

辅助函数:seg, clamp, lerp, easeOut, easeInOut, back, interp(series, t), pop, stamp, type。 规则:帧应仅依赖于 t。不要使用 setTimeout、Date、CSS 过渡和随机性;由于帧是逐帧捕获的,这些会导致闪烁和跳跃。

布局(1080x1920): 顶部 220 像素、底部 400 像素和右侧 150 像素会被 Instagram 界面遮挡。主要内容应位于 y 230-1300 之间。字幕在 y 1350 处,cap 在 y 230 处。将场景铺满整个屏幕;小卡片在中间留下空白会在手机端显得廉价。文本至少 40 像素,关键数字 100 像素及以上。

视觉风格(参考示例): 深蓝色背景 #0A0F1C,青色 #38BDF8 表示正常状态,红色 #F43F5E 表示故障,绿色 #34D399 表示解决方案,琥珀色 #FBBF24 表示注意/行为召唤。图标使用 Tabler(内联 SVG)。

音频

  • 解说词 -17 dBFS RMS,表情包音频归一化至 -16。音乐在解说词下方衰减至约 ~72%,在表情包下方衰减至约 ~88%。最终视频会归一化至 -14 LUFS。
  • 音乐免版税,由代码生成(120 BPM phonk:底鼓、808、拍手、Hi-hat、牛铃)。在 mute 窗口期间音乐静音;碰撞后的静默是最有力的节拍。
  • 效果音:whoosh(场景过渡;"at": "cuts" 会添加至所有过渡),fall, boom, hit, click(打字机、计数器),beep, tone, ding, riser, sparkle。参数在 scripts/synth.py 中。
  • 时间锚点:数字(绝对秒数)| "b"(场景开始)| "b.end" | "d@yetme"(该场景中以 "yetme" 开头的单词),均可添加 +0.1 / -0.4。对于重复,可使用 every + count 或 until;对于像 fall 和 whoosh 这样的扫频效果,仅提供 until 会将声音延长到那个时间点。

不要让人感觉像 AI 生成的

一个完全合成的视频(TTS 语音、完美无缺的矢量场景、所有效果精确对齐到单词)会给人一种“AI 做的”感觉。向用户提出以下建议,并根据情况应用:

  • 真实屏幕录制: 不要模仿产品界面,而是将真实的使用过程录制成场景(在 clips 中使用 "file" + "mode": "fit")。哪怕只有一个真实画面也能为整个视频增添可信度。
  • 人声: 如果用户用自己的手机录制对白,可以使用 reel.py voice PROJE n1 kayit.m4a 将该录音替代 TTS,它会裁剪开头和结尾的静音,并通过 Whisper 提取单词的时间。TTS 最容易暴露其非人本质的部分是语调。
  • 口语化语言: 脚本不要写得像公司文案,而要像一个人向朋友解释:“我打开了日志”,“还不够”。
  • 瑕疵与节奏: 不要使每个场景长度相同。将某些效果与单词错开 1-2 帧,在某个场景中完全切断音乐。避免完全对称的布局。
  • 熟悉的形式: 一个带有自己面孔或声音的开场(1 秒“看发生了什么”)比表情包系列更显得有人情味。

从之前的 Reel 中得到的教训

  • 效果好的做法:全屏竖屏表情包片段,配以片段自己的音频;中间穿插简短的解说场景;逐词字幕。
  • 用户仍然觉得“像 AI 做的”。在下一个视频中,至少提供上述建议中的一项(真实屏幕录制或用户自己的声音)。
  • 用户不希望收尾和描述中加入注释、警告或“此为模拟”字样。
  • 开始制作新的 Reel 时,查看同一账号的最后一个 Reel,不要重复使用相同的表情包和相同的顺序。

文件

  • scripts/reel.py: 所有流程(search, stt, still, clips, tts, voice, build, preview, mix, render [--from], all)
  • scripts/engine.js, scripts/base.css: 帧引擎和通用样式
  • scripts/synth.py: 音乐和效果生成器
  • scripts/capture.js: 使用 Playwright 进行帧捕获
  • references/tr-memes.md: 已验证的土耳其表情包片段(id, 秒数, 台词, 裁剪参数)
  • references/hooks.md: 钩子和节奏规则,来源
  • references/pitfalls.md: 环境问题及解决方案
  • examples/ardupilot-mcp/: 完整的工作示例项目

相关技能