在 PJSK(Project Sekai)同人社区里,跑团 Replay 已经是一种非常成熟的二次创作形态。你很可能刷到过类似《才不是喜欢你呢》这样的标题——它看起来像一场跑团直播的录像,又带着完整的剧情剪辑和角色演出,弹幕和评论区往往比正片还热闹。很多第一次接触这类视频的观众会问:这到底是一群人开了个语音在玩游戏,还是有人提前写好剧本请了 CV 配音?立绘为什么会动?骰子结果看起来那么真实,又是怎么做到的?
这篇文章不打算分析具体剧情和 CP 关系,而是从制作角度把“跑团 Replay 视频”整条工作流拆开讲清楚:从跑团过程的记录整理,到骰点数据处理,再到语音合成、立绘演出、字幕制作、剪辑合成和最终发布。读完你会知道,这类视频真正难在哪一步,以及如果你也想做一条 3 分钟的小样,需要准备哪些工具、避开哪些坑。
先给出一个明确判断:跑团 Replay 视频的复杂度不在剪辑本身,而在“前半程的数据整理”。一次跑团可能持续三四个小时,留下上万字对话和几十次骰点记录。如果没有在跑团过程中顺手把结构化信息记录下来,后期几乎等于从一堆录音里重新写一个剧本。所以这篇文章会花较大篇幅讲“如何把跑团过程变成可加工的数据”,再讲语音、立绘和剪辑,这个顺序也是你实际制作时的推荐顺序。
1. 跑团 Replay 是什么,为什么在 PJSK 同人圈流行
TRPG(Tabletop Role-Playing Game,桌上角色扮演游戏)的基本玩法是:一位主持人(GM 或 KP)负责描述场景、推进剧情和扮演 NPC,几位玩家扮演自己创建的角色,用对话和行动推动故事。某件事能否成功,通常由骰子决定,比如《克苏鲁的呼唤》里的 1D100 检定。这种形式本质上和游戏直播没有区别,但对观众来说,直接听几个人连续聊几个小时,既没有画面感,也缺少节奏。于是出现了 Replay 这种二次创作形态:把跑团过程中的对话、骰点、场景描述重新组织成类似动画剧集的观看体验。
PJSK 同人圈对 Replay 的接受度如此之高,有它独特的土壤。PJSK 角色本身拥有非常鲜明的性格和人际关系,粉丝很愿意看到角色脱离官方剧情、进入一个完全不同的世界观。比如“彰冬”(东云彰人×青柳冬弥)、“杏豆杏”这类 CP 向内容,在跑团剧本里可以让角色以另一种身份互动,同时保留原作的口癖和人物关系。这种“熟悉的角色 + 陌生的剧本”带来的反差和共鸣,是普通剧情向二创不容易做到的。
从制作角度看,跑团 Replay 还有一个天然优势:它不需要作者独立构思完整剧情,剧本来自跑团过程本身,作者更像一个纪录片导演而不是编剧。骰子带来的不确定性,会制造出许多写剧本时根本想不到的戏剧冲突,这让观众愿意追下去。也正因如此,Replay 视频的弹幕互动率通常高于普通剧情剪辑。
但反过来,Replay 并不好做。它是典型的“多工种叠加”:文本处理像做数据整理,语音部分像做音频节目,立绘演出像做动画,最后还要像做短视频一样考虑节奏和完播率。很多人第一次尝试就败在某个前置环节没有处理好,导致整集烂尾。接下来,我把完整链路铺开,你就能看到每个环节的位置和作用。
2. 制作一份 Replay,需要哪些核心环节
在进入具体工具之前,先看一张完整制作链路图。注意不要跳过任何一步,因为每一步的输出都是下一步的输入。
- 跑团实录:在线跑团时打开录音或文字记录,留下原始素材。
- 记录整理:把对话、动作、骰子结果从原始录音和文字中提取出来,按场景分段。
- 剧本化润色:保留跑团过程的大体走向,精简冗余对话,补全动作和环境描写。
- 数据录入:把角色名、台词、骰点、场景标签转成结构化数据(JSON 或表格)。
- 语音生产:用真人配音或音声合成得到每句台词对应的音频文件。
- 立绘演出:把角色立绘做成动态效果,配合表情切换和口型。
- 字幕制作:根据最终配音时长生成 SRT 或 ASS 字幕。
- 剪辑合成:将语音、立绘、背景、BGM、字幕合成一个成片。
- 审核发布:检查版权声明、分 P 规划、封面标题,再发布到平台。
很多新手会把第 1 步和第 2 步混在一起,以为录了音就万事大吉。实际上,录音只是原始素材,最终视频里不会直接使用大段现场录音,因为现场有大量停顿、规则讨论、跑题闲聊。你需要把原始素材“翻译”成一份干净可读的剧本。
在工程意义上,第 4 步是整个流程里最值得投入的一步。只要第 4 步输出的数据结构稳定,后面的语音合成、字幕生成甚至剪辑都可以部分自动化。反之,如果数据格式不规范,每一句台词都要手工处理,做一集的时间会成倍增加。从目前同人圈的常见实践看,多数人会先用云文档或表格记录,后期再转成脚本。但更推荐的做法是:在跑团结束当天,立刻用模板把记录整理成结构化数据,趁记忆还热,把语气、动作、氛围这些信息补齐。放几天再来整理,效率会明显下降。
3. 骰点与文本的结构化:最小脚本怎么做
3.1 骰点为什么需要单独处理
TRPG 的乐趣和麻烦都来自骰子。KP 一句“请进行一个幸运检定”,玩家掷出 1D100,结果直接决定剧情走向。Replay 视频里必须保留骰点,因为它是剧情合理性的来源。观众看到“骰点成功 / 失败”的过程,会更容易代入角色的紧张感。
但骰点不能只给一个最终数字,最好保留完整信息:掷了多少面骰子、修正值是多少、每颗骰子的点数、最终结果。这样在字幕上可以展示“2D6+3 → [5,1] → 合计 9”,观众一眼就能看出这波运气到底如何。
这里可以写一个极简 Python 脚本,处理xdy+k形式的骰点表达式:
""" 文件路径:dice.py 极简 TRPG 骰点解析器,支持 2d6+3 这类表达式 """ import random import re def roll(expr: str): expr = expr.replace(" ", "").lower() if not re.fullmatch(r"\d*d\d+([+-]\d+)?", expr): raise ValueError(f"无法解析骰点表达式: {expr}") m = re.fullmatch(r"(\d*)d(\d+)([+-]\d+)?", expr) count = int(m.group(1) or "1") faces = int(m.group(2)) mod = int(m.group(3) or "0") results = [random.randint(1, faces) for _ in range(count)] total = sum(results) + mod return results, total if __name__ == "__main__": expr = "2d6+3" results, total = roll(expr) print(f"{expr} -> {results} 合计 {total}")运行验证:
python dice.py # 示例输出:2d6+3 -> [5, 1] 合计 9这个脚本虽短,但它体现了工程化的关键思路:不要把骰点结果手动敲进字幕,要让程序替你生成。实际制作中,你可以把骰点结果直接写进跑团记录,再用下一节的整理脚本批量抽出来。
3.2 跑团记录的结构化
跑团过程中的文本可能是这样的:
# 第一章 放学后的教室 [彰人] 我才不是特意来看你的。 [冬弥] 嗯,我知道。 [KP] 那么请彰人过一个幸运检定。 (dice: 彰人 1d100 -> 42)要把这些文本转成后续能自动处理的 JSON,可以写一个简单的解析脚本。它把以#开头的行当作场景,把[角色]开头的行当作对话,把(dice:)标记解析为骰点:
""" 文件路径:log_to_json.py 把跑团日志行解析为结构化 JSON 输入格式: # 场景标题 [角色名] 台词内容 (dice:1d100) """ import json def parse_line(line: str): line = line.strip() if not line: return None if line.startswith("#"): return {"type": "scene", "content": line[1:].strip()} if line.startswith("["): speaker_end = line.find("]") speaker = line[1:speaker_end] rest = line[speaker_end + 1:].strip() dice_text = "" if "(dice:" in rest: start = rest.index("(dice:") end = rest.index(")", start) dice_text = rest[start + 6:end] rest = rest[:start].strip() return { "type": "dialog", "speaker": speaker, "content": rest, "dice": dice_text, } return {"type": "note", "content": line} if __name__ == "__main__": with open("run_log.txt", "r", encoding="utf-8") as f: lines = f.readlines() session = [] for line in lines: parsed = parse_line(line) if parsed: session.append(parsed) with open("session.json", "w", encoding="utf-8") as f: json.dump(session, f, ensure_ascii=False, indent=2) print(f"已解析 {len(session)} 条记录")这一步的核心价值,是把“跑团实录”变成“机器可读的数据”。有了这个 JSON,下一步合成语音时,可以直接遍历所有dialog节点,逐句调用音声合成接口,不需要手工复制台词。如果你在跑团过程中的台词还包含动作、心理描写、BGM 提示,可以在模板里继续扩展字段。
3.3 为什么要用 JSON 而不是 Excel
Excel 表格也可以记录角色、台词和骰点,而且对非程序员更友好。但后续自动化时,JSON 的优势很明显:它天然支持嵌套结构,一个场景下面可以挂多个对话节点;你还能给每个节点增加额外属性,比如情绪标签、语速标签、BGM 标签:
{ "type": "dialog", "speaker": "彰人", "content": "才不是喜欢你。", "emotion": "tsundere", "bgm": "school_theme.wav" }这些字段在 Excel 里也能加,但用 JSON 更容易交给代码读取。特别是当你有几十个角色、上百句台词时,写一个 Python 脚本批量处理 JSON,比手动操作 Excel 表格省事得多。后面所有自动化能力,都依赖这一步的数据规范程度。数据越规范,后期越轻松。
4. 语音合成:让角色“开口说话”的主流方案
Replay 视频的语音来源通常有三种:真人配音、音声合成、AI 语音克隆。三种方案各有优劣,并不是越贵越好。
真人配音的优点是有感情、有演技,适合追求品质的团队。缺点是成本高,需要组织多位愿意录制的朋友,录制周期长,后期修音工作量大。对个人制作者来说,真人配音的门槛往往不在技术,而在人员组织。
音声合成是目前个人制作 Replay 的主流选择。以 VOICEVOX 为例,它是一个本地运行的语音合成引擎,提供 HTTP API,支持多种音色。你传入一句文本,它就能生成一个 WAV 文件。好处是完全离线运行、费用可控、接口简单;缺点是音色不一定完全贴合角色性格,合成句子的语气可能偏平淡,需要一些后期处理。
AI 语音克隆是最近两年发展最快的方向,它可以把特定角色的声音建模,然后用文本生成语音。但这里必须提醒一句:声音和角色形象都涉及授权问题。使用官方角色的声音或真人声优的声音做克隆,需要仔细确认二次创作规则和商业使用边界。从稳妥角度出发,个人创作建议优先使用公开可商用的合成音色,而不是克隆原作声优。同人创作的前提是遵守规则,这比技术本身更重要。
下面给出 VOICEVOX 的调用示例。使用前,先下载并启动 VOICEVOX 客户端,默认会开启本地 HTTP 服务:
""" 文件路径:voice.py 调用 VOICEVOX 本地引擎合成语音 使用前:先启动 VOICEVOX 软件,默认监听 127.0.0.1:50021 """ import json import urllib.parse import urllib.request def synthesize(text: str, speaker_id: int = 1, output_wav: str = "out.wav"): host = "127.0.0.1" port = 50021 # 第一步:通过 audio_query 获取语音合成参数 query_url = ( f"http://{host}:{port}/audio_query" f"?text={urllib.parse.quote(text)}&speaker={speaker_id}" ) with urllib.request.urlopen(query_url) as resp: query = json.load(resp) # 第二步:调用 synthesis 接口,生成 wav 音频 synth_url = f"http://{host}:{port}/synthesis?speaker={speaker_id}" req = urllib.request.Request( synth_url, data=json.dumps(query).encode("utf-8"), headers={"Content-Type": "application/json"}, ) with urllib.request.urlopen(req) as resp: wav_data = resp.read() with open(output_wav, "wb") as f: f.write(wav_data) print(f"已生成 {output_wav}") if __name__ == "__main__": synthesize("才不是喜欢你呢,别误会了。", speaker_id=1, output_wav="line_001.wav")这段代码的关键在于两步请求:先用audio_query拿到说话速度、音高、停顿等参数,再用synthesis接口把参数变成音频。VOICEVOX 把“文本到参数”和“参数到音频”分开了,这就允许你在中间层修改语速和音量,方便批量调整。
实际制作中,不要为每一句台词单独启动一次 Python 程序。更合理的做法是遍历上一节生成的session.json,把里面所有dialog节点的content批量生成音频文件,并以台词编号命名。生成完音频后,还要做一遍听感检查。合成音色经常会读错人名、英文缩写或特殊语气词,最好在剪辑前把有问题的句子挑出来,手动调整断句,比如给文本加上“、”或“……”来改变节奏。
5. 立绘演出:静态图如何动起来
Replay 视频的视觉层,通常由角色立绘、背景图、字幕和特效组成。最简单的做法是让立绘固定在屏幕两侧,根据当前说话的人切换显示。但现在的观众已经被养得很挑剔,单纯的左右切换很快会让人觉得单调。更常见的做法是使用 Live2D,让立绘有呼吸感、眨眼、口型变化和小幅度动作。
Live2D 的核心思路不是做逐帧动画,而是把一个 PSD 分层文件变成可操纵的参数化模型。你拖动参数滑块,模型就会眨眼、转头、开口。制作流程大致是:先准备一张拆分好图层的角色立绘,再导入 Live2D 建模工具,为每个图层设置可动参数,最后导出 moc3 模型文件。之后在视频制作软件或动画引擎里,通过参数关键帧控制演出。
对 PJSK 同人 Replay 制作者来说,立绘素材通常来自官方立绘或社区二创立绘。这里要特别注意,官方素材的使用范围受二次创作规范约束,不一定能用于商业或直播场景。个人非商业 Replay 相对宽容,但搬运和二次分发时要看清各平台和官方的规则,不要想当然。
如果你没有 Live2D 建模经验,也可以退而求其次,使用“静态立绘 + 轻微动效”的方案:在剪辑软件里给立绘添加位置、旋转、缩放的关键帧,模拟角色微微晃动;说话时通过字幕高亮或立绘边框高亮来表示当前发声者。这个方案学习成本很低,但效果也不差,很多成熟的 Replay 早期版本都是这样做的。
如果想更接近动画质感,可以考虑用 MMD(MikuMikuDance)制作 3D 模型动画,但它的学习曲线和渲染时间都明显高于 Live2D。对多数做剧情向 Replay 的作者来说,Live2D 的性价比更高。真正重要的不是追求炫技,而是前期定好“演出规范”:什么时候眨眼、什么时候说话、什么时候换表情。如果没有规范,后期调整演出会越调越乱。
6. 字幕、时间轴与最终合流
6.1 字幕文件选 SRT 还是 ASS
SRT 是最基础的字幕格式,几乎所有播放器和剪辑软件都认。ASS(Advanced SubStation Alpha)功能更强,可以指定字体、颜色、位置、边框、阴影,甚至支持卡拉 OK 特效。Replay 视频里往往要区分角色名、旁白、骰点提示,所以更推荐 ASS。
一个简单的 SRT 示例:
1 00:00:01,000 --> 00:00:04,500 (彰人)才不是喜欢你呢。 2 00:00:05,000 --> 00:00:08,200 (冬弥)……嗯,我知道。ASS 文件比 SRT 复杂一些,但模板化之后,你只需要关注文本内容,格式可以复用。实际项目中更稳妥的做法是在剪辑软件里直接用字幕轨道,让字幕时间轴与画面完全同步,最后再导出或烧录,避免出现硬编码字幕与画面错位的问题。
6.2 用 ffmpeg 完成音频和字幕合成
很多新手以为剪完视频就是最后一步,其实还有音频轨合并、字幕烧录、转码压缩等收尾工作。ffmpeg 可以高效完成这些批量任务。
把角色语音合并到成片视频中:
ffmpeg -i final_video.mp4 -i voice.wav -map 0:v -map 1:a -c:v copy -c:a aac -b:a 192k output.mp4把 ASS 字幕烧录进视频:
ffmpeg -i output.mp4 -vf "subtitles=subtitle.ass" -c:a copy final.mp4注意,烧录字幕需要 ffmpeg 编译时启用了 libass。如果提示找不到滤镜,就需要更换带 libass 的 ffmpeg 版本。
但 ffmpeg 只是收尾工具,真正的剪辑仍然建议在剪辑软件里完成。Replay 视频需要频繁调整语音和画面之间的节奏,自动剪辑很难准确卡点。ffmpeg 的定位更多是批量处理素材,比如把几十个 WAV 批量转成统一采样率,或者把大量立绘图片压缩到合适尺寸。
7. 常见问题与排查方法
这里整理一份实践中的高频问题。每个问题基本都能对应到一个前期环节,如果后期才发现,返工成本会很高。
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 语音合成延迟高,一句要等几十秒 | 本地引擎未预热或 CPU 配置较低 | 查看任务管理器 CPU 占用 | 批量预生成音频,不要实时合成 |
| 同一角色前后音色不一致 | 切换了 speaker_id 或音色参数 | 检查 JSON 里的 speaker 字段 | 固定角色使用唯一 speaker_id 和配置 |
| 骰点结果与剧情对不上 | 原始日志漏记或后期手动改过 | 对照跑团录音回查 | 以主持人记录为准,及时补录 |
| 字幕与语音不同步 | 音频替换后时间轴未更新 | 检查剪辑软件时间轴 | 在剪辑软件里一次性对齐字幕轨 |
| 立绘口型不自然 | Live2D 口型参数未正确绑定 | 检查口型参数曲线 | 导出时重置口型参数并重新测试 |
| ffmpeg 烧字幕报错 | 缺少 libass 滤镜 | 输入ffmpeg -version查看配置 | 安装带 libass 的 ffmpeg 版本 |
| 视频编码后画质模糊 | 码率设置过低 | 检查导出参数 | 使用 CRF 18-20 或设置足够高的码率 |
8. 工程化建议与内容安全提醒
Replay 看起来是创意作品,但要做到多集连载,就必须当成工程来做。
8.1 命名规范
当涉及大量角色、场景和音频文件时,以时间或编号作为文件名前缀,避免使用“最终版”“真的最终版”这类文件名。推荐命名规范:集数_场景编号_台词编号_角色.扩展名,例如ep01_sc02_line014_akito.wav。这样即使几百个文件放在同一目录,也能快速定位,剪辑软件导入后的排序也更清晰。
8.2 不要等剪辑时再生成音频
语音是本类视频