- 用VoxCPM2生成128条v2语音(林夏回应+NPC反应+Round3对话) - story.js全部切换到VoxCPM2音频路径 - engine.js: BGM音量减半(0.2→0.1)、MSG-14前导语支持、结局E用周南新语音 - 林夏.md完整重写:6手势交互、主角有声音、VoxCPM2本地TTS方案 - batch_tts_voxcpm.py: 新增linxia角色、修复self_3y音色、添加全部v2台词 - 新增voice/linxia/参考音色 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
786 lines
35 KiB
Markdown
786 lines
35 KiB
Markdown
# 林夏
|
||
|
||
> **类型**:情感 / 叙事 / 轻悬疑 · 纯音频交互游戏
|
||
> **目标用户**:20–25 岁年轻女性(大学生 / 初入职场 / 一线城市独居)
|
||
> **时长**:约 30–45 分钟
|
||
> **核心隐喻**:所有人都给你发语音,没有人发文字。今晚你必须一条一条听完,才能决定明天的自己长什么样。
|
||
> **核心原则**:每次选择都必须产生玩家能听到的、不同的后果。
|
||
|
||
---
|
||
|
||
## 0. 一句话概述
|
||
|
||
24 岁的林夏,被分手、被裁员、被妈妈催婚,全发生在同一个周五。她把手机调成静音、躲进合租屋,关上灯。屏幕坏了——只剩耳机能听、手指能摸。今晚 16 个人会发来电话和语音。她接谁、不接谁、怎么回——每一个回应都会被对方听到,每一段对话都会走向不同的结局。
|
||
|
||
---
|
||
|
||
## 1. 玩家与角色
|
||
|
||
### 1.1 玩家是谁
|
||
- **林夏**,24 岁,西部小城来的姑娘,北漂第 3 年。
|
||
- 国贸某外企新媒体专员,今天上午刚被裁员(合同到期不续签)。
|
||
- 与男友"阿哲"恋爱 2 年 4 个月,今天下午刚被分手("我们性格真的不合")。
|
||
- 与一位大学闺蜜"小美"合租,但小美今晚去了酒吧。
|
||
- 老家妈妈让她"五一回来相亲"。
|
||
- 微信未读:99+。
|
||
- 屏幕:今天上午地铁挤碎了的那块屏,现在显示一片黑——但触控、震动、声音都还在。
|
||
|
||
### 1.2 林夏不是"听者"——她会说话
|
||
|
||
与传统音频叙事游戏不同,**林夏有自己的声音**。玩家的每次选择都会触发林夏的一句语音回应,对方会听到并做出反应。这构成了完整的对话:
|
||
|
||
```
|
||
NPC 说话 → 玩家选择方向 → 林夏说出回应 → NPC 对林夏的回应做出反应
|
||
```
|
||
|
||
林夏的声音设计:**疲惫但清醒、克制但有温度、年轻但不幼稚。**
|
||
|
||
---
|
||
|
||
## 2. 核心玩法
|
||
|
||
### 2.1 六种手势——零视觉依赖
|
||
|
||
| 手势 | 全局含义 | 情感色彩 | 触觉反馈 | 音效 |
|
||
|------|---------|---------|---------|------|
|
||
| **单击** | 接受 / 回应 / 继续 | 中性应答 | 轻触感 | 清脆短音 880Hz |
|
||
| **双击** | 跳过 / 忽略 | 不耐烦 / 赶时间 | 短促双震 | 下行滑音 587→392Hz |
|
||
| **右滑** | 温暖 / 靠近 | 接纳、关心 | 流畅长震 | 上行音 440→659Hz |
|
||
| **左滑** | 冷淡 / 推开 | 疏离、敷衍 | 干脆短震 | 下行音 523→349Hz |
|
||
| **上滑** | 好奇 / 追问 | 想了解更多 | 快速上弹震 | 快速上行 523→784Hz |
|
||
| **下滑** | 沉默 / 退缩 | 说不出口 | 极轻慢震 | 极轻低音 330Hz |
|
||
|
||
> **不需要记位置**。每个方向有固定的情感含义,贯穿全游戏。右滑永远是温暖,左滑永远是冷淡。
|
||
|
||
### 2.2 对话流程(多轮交互)
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────┐
|
||
│ [提示音 + 震动] │
|
||
│ 消息到达 │
|
||
│ → 单击播放 / 双击跳过 │
|
||
└──────────┬──────────────────────────────────────┘
|
||
▼
|
||
┌─────────────────────────────────────────────────┐
|
||
│ NPC 语音播放(Round 1) │
|
||
│ "你被甩了我都听说了,明天陪你喝酒" │
|
||
└──────────┬──────────────────────────────────────┘
|
||
▼
|
||
┌─────────────────────────────────────────────────┐
|
||
│ [三音上行提示音 · 等待选择] │
|
||
│ 玩家操作:右滑 / 左滑 / 上滑 / 下滑 / 单击 │
|
||
└──────────┬──────────────────────────────────────┘
|
||
▼
|
||
┌─────────────────────────────────────────────────┐
|
||
│ [打字音效 ~0.8s → 发送音效] │
|
||
│ 林夏的语音播放 │
|
||
│ 右滑 → "好啊,明天不见不散。" │
|
||
│ 左滑 → "再说吧。" │
|
||
│ 上滑 → "你怎么知道的啊?" │
|
||
│ 下滑 → [一秒沉默] │
|
||
│ 单击 → "嗯。" │
|
||
└──────────┬──────────────────────────────────────┘
|
||
▼
|
||
┌─────────────────────────────────────────────────┐
|
||
│ NPC 反应播放(Round 2)—— 因选择而异 │
|
||
│ │
|
||
│ 右滑: "行!那我叫上安安!老地方见!" │
|
||
│ 左滑: "……好吧,你休息。" │
|
||
│ 上滑: "还不是阿哲那个大嘴巴告诉我的……" │
|
||
│ 下滑: "??你还活着吗哈哈。算了不打扰你了" │
|
||
│ 单击: "嗯是什么意思啊哈哈!行吧你休息" │
|
||
└──────────┬──────────────────────────────────────┘
|
||
▼
|
||
┌─────────────────────────────────────────────────┐
|
||
│ [可选] Round 3: 继续对话(仅部分路径触发) │
|
||
│ NPC 追问 → 再次选择 → 林夏回应 → 对话结束 │
|
||
└──────────┬──────────────────────────────────────┘
|
||
▼
|
||
┌─────────────────────────────────────────────────┐
|
||
│ → 等待 → 下一条消息到达 │
|
||
└─────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 2.3 关键设计
|
||
|
||
| 方面 | 说明 |
|
||
|------|------|
|
||
| **林夏的声音** | 每次选择后都有语音回应(或有感知的沉默) |
|
||
| **NPC 反应** | 根据选择播放完全不同的反应语音 |
|
||
| **选择的感受** | 五个方向各自导向不同的音频内容 |
|
||
| **对话长度** | 温暖/追问路径更长、信息更多;冷淡/沉默路径更短 |
|
||
| **独家信息** | 追问路径可获得其他路径听不到的剧情细节 |
|
||
| **玩家驱动** | 没有时间限制,消息不会自动推进,完全由玩家操作控制节奏 |
|
||
| **双击跳过** | 在林夏回应或 NPC 反应播放中,双击可跳过当前语音,加速流程 |
|
||
|
||
### 2.4 关键机制:「正在输入…」
|
||
|
||
当林夏回应前,耳机里会播放微弱的**键盘敲击声** → 发送音效 → 然后才播放林夏的语音。这 ~1 秒的"打字等待"让选择感觉真实——你不是在"选菜单",你是在"发语音"。
|
||
|
||
---
|
||
|
||
## 3. 消息全列表(16 条)
|
||
|
||
| # | 来源 | 形式 | 关键内容 | 有无选择 |
|
||
|---|------|------|---------|---------|
|
||
| 01 | 妈妈 | 电话 | "今晚煮了你爱吃的排骨" | 接听 → 无选择(自动回应) |
|
||
| 02 | 闺蜜小美 | 语音 ×3 | "你被甩了我都听说了,明天陪你喝酒" | 5 方向 + 追问 Round 3 |
|
||
| 03 | 外卖小哥 | 电话 | "你的麻辣烫到了" | 接听 → 无选择(自动回应) |
|
||
| 04 | 前任阿哲 | 语音 | "我的 AirPods 落你那了" | 5 方向 + 温暖/追问各有 Round 3 |
|
||
| 05 | HR 王姐 | 语音 | "离职流程周三前办完就行" | 5 方向 |
|
||
| 06 | 室友安安 | 语音 | "我在 Helens!快来!" | 5 方向 |
|
||
| 07 | 寝室群 | 语音 ×5 | 室友 A 升职,@林夏 | 5 方向 + 温暖 Round 3 |
|
||
| 08 | 未知号码 | 电话 | 呼吸声 6 秒后挂断 | 无选择(悬疑钩子) |
|
||
| 09 | 小美(醉)| 语音 ×4 | "阿哲大三追过我" | 5 方向 + 追问 Round 3 |
|
||
| 10 | 妈妈 | 文字 | "睡了吗?" | 5 方向 + 温暖/追问各有 Round 3 |
|
||
| 11 | 阿哲 | 电话 | "我能过去拿吗?就 5 分钟" | 5 方向(关键分支锚点) |
|
||
| 12 | 周南 | 语音 | "初三坐你后桌那个" | 5 方向 |
|
||
| 13 | 周南 | 语音 ×4 | "今天我生日" | 5 方向 + 温暖 Round 3 |
|
||
| 14 | 妈妈 | 电话 | "你不接电话我有点担心" | 接听 → 自动回应,条件分支 |
|
||
| 15 | 自己 | 系统通知 | 3 年前录的备忘录 | 单击播放 / 双击跳过 |
|
||
| 16 | 妈妈 | 长语音 ×8 | 妈妈 24 岁那年的故事 | 无选择(结局前奏) |
|
||
|
||
---
|
||
|
||
## 4. 16 条消息详细设计
|
||
|
||
### MSG-01 妈妈 · 电话
|
||
|
||
**类型**:来电(铃声 + 长震动)
|
||
**Round 1**(接听后):妈妈说"今晚煮了你爱吃的排骨,你什么时候回来呀。"
|
||
**接听后自动**:林夏轻轻说"嗯……好。"(无选择)
|
||
**不接** → 直接跳到下一条。
|
||
|
||
**状态**:接听 → MOM_LINK = true
|
||
|
||
---
|
||
|
||
### MSG-02 小美 · 语音 ×3(教学关)
|
||
|
||
**Round 1**:小美连发三条语音:
|
||
- "林夏!你还活着吗!"
|
||
- "你被甩了我都听说了——别难过啊"
|
||
- "明天陪你喝酒,去不去"
|
||
|
||
**选择 + Round 2**:
|
||
|
||
| 方向 | 林夏说 | 小美反应 | profile |
|
||
|------|--------|---------|---------|
|
||
| 右滑 | "好啊,明天不见不散。" | "行!那我叫上安安!老地方见!别放鸽子啊!" | engagement+2 |
|
||
| 左滑 | "再说吧。" | "……好吧。你要是改主意了随时说。" | avoidance+1 |
|
||
| 上滑 | "你怎么知道的啊?" | "还不是阿哲自己发朋友圈!你不知道吗?他发了又秒删……" | engagement+1,**独家信息** |
|
||
| 下滑 | [沉默 2s] | "??你还活着吗哈哈。好了不烦你了,有事找我。" | avoidance+2 |
|
||
| 单击 | "嗯。" | "嗯是什么意思啊哈哈!行吧你休息。" | — |
|
||
|
||
**追问 Round 3**(上滑后,小美说完"他发了又秒删"):
|
||
- 右滑 → 林夏:"他……发了什么?" → 小美:"就发了一张你们以前的照片,配了一句'值得'。两分钟就删了" → **独家信息**
|
||
- 其他 → 对话结束
|
||
|
||
---
|
||
|
||
### MSG-03 外卖小哥 · 电话
|
||
|
||
**类型**:来电
|
||
**Round 1**:外卖小哥:"你好,你的麻辣烫到了,在楼下。"
|
||
**接听后自动**:林夏说"好,我下来拿。"(无选择)
|
||
**不接** → 漏接。
|
||
|
||
---
|
||
|
||
### MSG-04 阿哲 · 语音
|
||
|
||
**Round 1**:阿哲说"那个……我的 AirPods 好像落你那了,方便帮我寄一下吗?"
|
||
|
||
| 方向 | 林夏说 | 阿哲反应 | 效果 |
|
||
|------|--------|---------|------|
|
||
| 右滑 | "你那边……还好吗。" | "我……挺好的。" [停顿] "你呢?" | engagement+2 |
|
||
| 左滑 | "知道了。明天寄。" | "嗯……谢了。" | HE_BACK=false, avoidance+1 |
|
||
| 上滑 | "你怎么不自己来拿。" | "我……不太方便过去。" [欲言又止] | engagement+2 |
|
||
| 下滑 | [沉默 3s] | [等 5 秒] "那……我晚点再说吧。" → 阿哲撤回消息 | HE_BACK=null, avoidance+2 |
|
||
| 单击 | "好。" | "谢谢。" | HE_BACK=false, engagement+1 |
|
||
|
||
**右滑 Round 3**(阿哲问"你呢?"后):
|
||
- 右滑 → 林夏:"不太好。" → 阿哲:"……对不起。" [沉默]
|
||
- 左滑 → 林夏:"挺好的。" → 阿哲:"那就好。"
|
||
- 下滑 → [沉默] → 阿哲:"……那,晚安。"
|
||
|
||
**上滑 Round 3**(阿哲说"不太方便"后):
|
||
- 上滑 → 林夏:"为什么。" → 阿哲:"我……" [长停顿] "没什么。你寄吧。" → HE_BACK=false
|
||
- 右滑 → 林夏:"算了,不问了。" → 对话结束
|
||
|
||
---
|
||
|
||
### MSG-05 HR 王姐 · 语音
|
||
|
||
**Round 1**:王姐说"小夏,离职流程周三前办完就行。别有压力。"
|
||
|
||
| 方向 | 林夏说 | 王姐反应 | profile |
|
||
|------|--------|---------|---------|
|
||
| 右滑 | "谢谢王姐。" | "别客气。你还年轻,出去看看也好。这行业你知道的。" | engagement+1 |
|
||
| 左滑 | "好的,知道了。" | [无反应,对话结束] | — |
|
||
| 上滑 | "王姐……有什么建议吗?" | "你想听真话?别在这行耗了。你有本事,去试试别的。" → **独家** | engagement+2 |
|
||
| 下滑 | [沉默] | [无反应,对话结束] | avoidance+1 |
|
||
| 单击 | "好。" | [无反应,对话结束] | — |
|
||
|
||
---
|
||
|
||
### MSG-06 安安 · 语音
|
||
|
||
**Round 1**:安安在酒吧里大喊:"我在 Helens!快来!今天 happy hour!"(背景很吵)
|
||
|
||
| 方向 | 林夏说 | 安安反应 | profile |
|
||
|------|--------|---------|---------|
|
||
| 右滑 | "在哪儿啊?我看看吧。" | "对面那个!我给你留了位置!赶紧赶紧!" | engagement+2 |
|
||
| 左滑 | "不了,你们玩好。" | "好吧!那我给你寄一杯!" [大笑] | — |
|
||
| 上滑 | "你喝了多少了?" | "才两杯!我清醒得很!……好吧三杯。快来!" | engagement+1 |
|
||
| 下滑 | [沉默] | "喂?信号不好吗?好吧以后再约!" | avoidance+1 |
|
||
| 单击 | "嗯。" | "嗯是来还是不来啊!算了回头聊!" | — |
|
||
|
||
---
|
||
|
||
### MSG-07 寝室群 · 语音 ×5
|
||
|
||
**Round 1**:群消息连续播放:
|
||
- 室友 A:"我升主管了!!!"
|
||
- 室友 A:"请你们吃饭!!"
|
||
- 室友 B:"我的天!恭喜!!"
|
||
- 室友 B:"必须喝一个!"
|
||
- 室友 C:"@林夏 你也来吧"
|
||
|
||
| 方向 | 林夏说 | 群里反应 | 效果 |
|
||
|------|--------|---------|------|
|
||
| 右滑 | "恭喜恭喜!太厉害了!" | 室友 A:"哈哈谢谢!我请客!你最近怎么样啊?" | GROUP_REPLY, engagement+2 |
|
||
| 左滑 | "恭喜。" | [群里继续聊别的,没人注意到你的冷淡] | avoidance+1 |
|
||
| 上滑 | "怎么升的啊?讲讲!" | 室友 A:"说来话长!我们老板走了我就顶上了哈哈" → **独家** | GROUP_REPLY, engagement+2 |
|
||
| 下滑 | [沉默,不回群] | [群里继续热闹,但渐渐没人 @ 你了] | avoidance+2 |
|
||
| 单击 | [发一个表情] | 室友 B:"林夏发表情了哈哈" | GROUP_REPLY |
|
||
|
||
**右滑 Round 3**(室友 A 问"你最近怎么样"后):
|
||
- 右滑 → 林夏:"挺好的~你请客我去!" → 室友们欢呼
|
||
- 左滑 → 林夏:"还行。" → 室友 B:"你是不是有事啊?没事可以跟我们说"
|
||
- 下滑 → [沉默] → 对话自然结束
|
||
|
||
---
|
||
|
||
### MSG-08 未知号码 · 电话(悬疑)
|
||
|
||
**类型**:来电
|
||
**接听后**:只有呼吸声,6 秒后自动挂断。然后心跳音效。
|
||
**无选择**——悬疑钩子。
|
||
**不接** → 未接来电。
|
||
|
||
---
|
||
|
||
### MSG-09 小美(醉)· 语音 ×4
|
||
|
||
**BGM 切换为悬疑风格**
|
||
|
||
**Round 1**(四段醉酒语音):
|
||
- "林夏……我跟你说个事"
|
||
- "阿哲那个人……大三的时候追过我"
|
||
- "但我没答应他……因为我知道你喜欢他"
|
||
- "我到现在都没跟你说……对不起"
|
||
|
||
| 方向 | 林夏说 | 小美反应 | profile |
|
||
|------|--------|---------|---------|
|
||
| 右滑 | "小美……你没事吧。" | "我没事……我就是喝多了想告诉你……你别怪我。" [哭] | engagement+2 |
|
||
| 左滑 | "我知道了。" | [沉默 3 秒] → 小美撤回了刚才的语音 | avoidance+1 |
|
||
| 上滑 | "你……为什么现在才说。" | "因为你今天……我怕你以后恨我……" | engagement+2 |
|
||
| 下滑 | [沉默] | [10 秒后] 小美撤回了刚才的语音 | avoidance+2, nostalgia+1 |
|
||
| 单击 | "嗯。" | "你不生气吗?" [等 3 秒] "算了……当我没说" | nostalgia+1 |
|
||
|
||
**上滑 Round 3**(小美说"怕你恨我"后):
|
||
- 右滑 → 林夏:"我不恨你。" → 小美 [大哭]:"谢谢你……谢谢你林夏"
|
||
- 左滑 → 林夏:"我得想想。" → 小美:"好……对不起" → 对话结束
|
||
- 下滑 → [沉默] → 小美:"你还在吗?" → [长沉默] → 小美撤回
|
||
|
||
---
|
||
|
||
### MSG-10 妈妈 · 文字消息
|
||
|
||
**Round 1**:消息到达提示音。TTS 朗读三个字——"睡了吗?"
|
||
|
||
| 方向 | 林夏说 | 妈妈反应 | 效果 |
|
||
|------|--------|---------|------|
|
||
| 右滑 | "没有,怎么了?" | 妈妈发语音:"没事,就是想起来问一下。今天怎么样?" | MOM_LINK, engagement+2 |
|
||
| 左滑 | "嗯,要睡了。" | 妈妈发文字:"好,早点睡。" | MOM_LINK, avoidance+1 |
|
||
| 上滑 | "妈……你能打电话给我吗?" | [电话铃响] 妈妈打来了!接听后:"怎么了夏夏?" | MOM_LINK, engagement+3 |
|
||
| 下滑 | [不回复] | [30 秒后] 妈妈发文字:"看到了回一下。" | avoidance+2 |
|
||
| 单击 | "嗯。" | 妈妈发文字:"嗯就是睡了?晚安。" | MOM_LINK |
|
||
|
||
**上滑路径**(妈妈打来电话后,说"怎么了夏夏?你声音不对。"):
|
||
- 右滑 → 林夏:"没什么……就是有点累。" → 妈妈:"累了就回家歇几天。妈煮了排骨。"
|
||
- 上滑 → 林夏:"妈,我辞职了。" → 妈妈 [沉默 2 秒]:"辞了就辞了。回来再说。"
|
||
- 下滑 → [沉默,只有呼吸] → 妈妈:"不想说就不说。妈在这呢。"
|
||
|
||
**右滑路径**(妈妈问"今天怎么样"后):
|
||
- 右滑 → 林夏:"还好。" → 妈妈:"那就好。别太晚了。"
|
||
- 上滑 → 林夏:"不太好。" → 妈妈:"怎么了?" → [可继续展开]
|
||
|
||
---
|
||
|
||
### MSG-11 阿哲 · 电话(关键分支)
|
||
|
||
**类型**:来电
|
||
**Round 1**(接听后):阿哲说"那个……AirPods 的事,我能过去拿吗?就 5 分钟。"
|
||
|
||
| 方向 | 林夏说 | 阿哲反应 | 效果 |
|
||
|------|--------|---------|------|
|
||
| 右滑 | "可以。但只有 5 分钟。" | "好,我马上过来。谢谢。" → [挂断] | HE_BACK=true |
|
||
| 左滑 | "不方便。我明天寄给你。" | "好吧……那谢了。" → [挂断] | HE_BACK=false |
|
||
| 上滑 | "为什么非要今天来?" | "我……明天要出差。" [停顿] "就 5 分钟。" | 继续选择 |
|
||
| 下滑 | [沉默 → 挂断音] | [电话断了] | HE_BACK=false |
|
||
| 单击 | "不了。" | "好。" → [挂断] | HE_BACK=false |
|
||
|
||
**如果 HE_BACK=true** → 消息 12 之前插入门铃声 + 敲门声场景。
|
||
|
||
---
|
||
|
||
### MSG-12 周南 · 语音
|
||
|
||
**Round 1**:周南说"林夏,是我,周南。初三坐你后桌那个。好久没联系了,今天突然想到你。"
|
||
|
||
| 方向 | 林夏说 | 周南反应 | 效果 |
|
||
|------|--------|---------|------|
|
||
| 右滑 | "周南!你还记得我啊!" | "当然记得。你是我们班最安静的那个。" [轻笑] | ZHOUNAN_DEPTH+1, engagement+2 |
|
||
| 左滑 | "嗯,你好。" | "嗯……好久不见。你现在在哪呢?" | ZHOUNAN_DEPTH+1, nostalgia+1 |
|
||
| 上滑 | "你怎么有我微信的?" | "你忘了吗?毕业那天你加的我。不过你可能早忘了哈哈。" | ZHOUNAN_DEPTH+1, nostalgia+2 |
|
||
| 下滑 | [沉默] | "你是不是不记得我了?没关系的。就是突然想说声嗨。" | nostalgia+1 |
|
||
| 单击 | "嗯……好久不见。" | "是啊,好久不见。" | ZHOUNAN_DEPTH+1 |
|
||
|
||
---
|
||
|
||
### MSG-13 周南 · 长语音 ×4
|
||
|
||
**BGM 切换为周南主题(温暖吉他)**
|
||
|
||
**Round 1**(四段语音):
|
||
- "高考那年我没考好,去复读了"
|
||
- "后来上了个二本,学了个不喜欢的专业"
|
||
- "毕业回了老家,在我爸店里帮忙"
|
||
- "今年刚来北京出差……今天是我生日"
|
||
|
||
| 方向 | 林夏说 | 周南反应 | 效果 |
|
||
|------|--------|---------|------|
|
||
| 右滑 | "一个人在北京,还好吗?" | "还行吧。习惯了。你呢?你在北京过得好吗?" | ZHOUNAN_DEPTH+1, engagement+2 |
|
||
| 左滑 | "你讲了好多。" | "是吗?不好意思,话太多了。" [轻笑] | ZHOUNAN_DEPTH+1, nostalgia+1 |
|
||
| 上滑 | "……生日快乐。" | [沉默 2 秒] "谢谢你。你是今天第一个跟我说的。" | ZHOUNAN_DEPTH+1, ZHOUNAN_SHARE, nostalgia+2 |
|
||
| 下滑 | [沉默] | "不好意思突然说这么多……那,晚安。" | avoidance+1 |
|
||
| 单击 | "嗯,我都听到了。" | "嗯。谢谢你听我说。" | ZHOUNAN_DEPTH+1 |
|
||
|
||
**右滑 Round 3**(周南问"你在北京过得好吗"后):
|
||
- 右滑 → 林夏:"不太好。今天也是我的坏日子。" → 周南:"那我们算是难兄难妹了。" [轻笑] → **ZHOUNAN_SHARE**
|
||
- 左滑 → 林夏:"还行吧。" → 周南:"那就好。"
|
||
- 上滑 → 林夏:"你为什么突然联系我?" → 周南:"因为……今天生日嘛,想起以前的事。想起你。"
|
||
|
||
---
|
||
|
||
### MSG-14 妈妈 · 第二次电话
|
||
|
||
**类型**:来电
|
||
**Round 1**:妈妈说"夏夏,你不接电话我有点担心。你还好吗?"
|
||
|
||
接听后 → 林夏自动说"嗯,我没事。"
|
||
妈妈:"真的没事?"
|
||
- 如果 MOM_LINK=true:"好。那早点睡。妈爱你。"
|
||
- 如果 MOM_LINK=false:"你今天怎么都不理妈妈?出什么事了吗?" → 可选择回应
|
||
|
||
**状态**:接听 → MOM_LINK=true
|
||
|
||
---
|
||
|
||
### MSG-15 时光胶囊 · 系统通知
|
||
|
||
**特殊消息**:系统提示音 + "3 年前的今晚,你给自己录过一段备忘录。"
|
||
- 单击播放 → 根据玩家画像播放不同版本(avoidance / engagement / nostalgia) → SELF_RECORD=true
|
||
- 双击跳过 → avoidance+2
|
||
|
||
*无选择交互。这条消息是独白时刻。*
|
||
|
||
---
|
||
|
||
### MSG-16 妈妈 · 长语音 ×8(结局前奏)
|
||
|
||
**条件**:MOM_LINK=true 时播放
|
||
|
||
妈妈讲她 24 岁那年的故事:
|
||
1. "夏夏。妈妈知道你今天电话不接。妈妈不催你,就是想跟你说一件事。"
|
||
2. "你 24 了对吧。妈妈 24 那年——你应该没听我说过——"
|
||
3. "那时候妈妈在广州,给一个香港老板做秘书,1995 年。那年我也被分手过。也被开除过。"
|
||
4. "那年我哭得特别难看。后来呢?后来就没什么后来了。我回了老家,认识了你爸,生了你。"
|
||
5. "我想跟你说,那年夏天我没死,是因为我外婆每天晚上都给我打一个电话。"
|
||
6. "她不说什么,就问我今天吃饭了没。"
|
||
7. "我现在打给你,你不接也没事。妈妈给你发个语音,你什么时候想听就听。你不用回我。"
|
||
8. "你今天接了好多电话吧。妈妈不打扰你了。晚安。"
|
||
|
||
*无选择交互。让玩家安静听完。播放结束 → 触发结局判定。*
|
||
|
||
---
|
||
|
||
## 5. 分支判定变量
|
||
|
||
| 变量 | 触发条件 | 影响 |
|
||
|------|---------|------|
|
||
| **MOM_LINK** | 是否接妈妈两次电话中的至少一次 / 是否回复"睡了吗?" | 决定 MSG-16 是否播放 |
|
||
| **HE_BACK** | 是否答应阿哲过来拿耳机(MSG-11 右滑) | 决定 MSG-12 前是否插入门铃场景 |
|
||
| **GROUP_REPLY** | 是否在寝室群里回复过(MSG-07 非沉默) | 决定彩蛋消息 |
|
||
| **ZHOUNAN_DEPTH** | 给周南的回应深度(累计) | 决定结局字幕 + self-3y 版本 |
|
||
| **ZHOUNAN_SHARE** | 是否在周南对话中选择"分享自己"(MSG-13 上滑/右滑 R3 右滑) | 决定隐藏结局 |
|
||
| **SELF_RECORD** | 是否听完 3 年前备忘录(MSG-15) | 决定结局类型 |
|
||
| **PROFILE** | 全场行为聚合画像:avoidance / engagement / nostalgia | 决定 self-3y 版本 + 环境音 |
|
||
|
||
### PROFILE 计分细则
|
||
|
||
| 行为 | avoidance | engagement | nostalgia |
|
||
|------|-----------|------------|-----------|
|
||
| 漏接电话(不动) | +2 | 0 | 0 |
|
||
| 双击跳过消息 | +2 | 0 | 0 |
|
||
| 单击回"嗯" | +1 | 0 | 0 |
|
||
| 左滑冷淡回应 | +1 | 0 | 0 |
|
||
| 下滑沉默 | +2 | 0 | +1 |
|
||
| 右滑温暖回应 | 0 | +2 | 0 |
|
||
| 上滑追问 | 0 | +2 | 0 |
|
||
| Round 3 中选择"分享自己" | 0 | +1 | +1 |
|
||
|
||
最终取分数最高项作为 PROFILE 标签。
|
||
|
||
---
|
||
|
||
## 6. 结局系统(5 种)
|
||
|
||
### 结局 A · "明天就明天吧"
|
||
**触发**:MOM_LINK=true + SELF_RECORD=true + 至少回了周南或群里 1 条
|
||
- 妈妈语音播完。林夏起身,环境声:走到厨房、烧水、坐在小板凳上。
|
||
- 字幕:"明天再说。"
|
||
- 烧水壶滴的一声 → 游戏结束。
|
||
|
||
### 结局 B · "AirPods 我寄给你"
|
||
**触发**:HE_BACK=false + 回过周南至少 1 条
|
||
- 林夏给阿哲发了文字"我寄给你,地址发我"。
|
||
- 字幕:"寄出。"
|
||
- 一个"清醒地走"的结局。
|
||
|
||
### 结局 C · "全部已读"
|
||
**触发**:未读数=0 且回复≤2 条
|
||
- TTS:"今晚共 16 条新消息,已读 16,未回复 14。"
|
||
- 长沉默。字幕:"今晚就这样。"
|
||
|
||
### 结局 D · "明天再开机"
|
||
**触发**:未读数≥8
|
||
- 系统提示电量 1%。触感震动 + 白噪 → 彻底黑。
|
||
- 第二天清晨鸟叫。字幕:"早上好。"
|
||
|
||
### 结局 E · 隐藏 · "周南,我也记得你"
|
||
**触发**:ZHOUNAN_DEPTH≥2 + ZHOUNAN_SHARE + PROFILE=engagement 或 nostalgia
|
||
- 周南秒回:"那我下次出差来北京,请你吃饭好不好。"
|
||
- 系统播放林夏的轻笑——这是全游戏唯一一次林夏主动笑出声。
|
||
- 字幕:"好。"
|
||
|
||
---
|
||
|
||
## 7. 音频设计
|
||
|
||
### 7.1 音频资产分类
|
||
|
||
| 类别 | 说明 | 数量 | 制作方案 |
|
||
|------|------|------|---------|
|
||
| **林夏语音** | 主角对话回应(通用 + 专属) | ~55 条, ~100s | VoxCPM2 声音克隆 |
|
||
| **NPC Round 1 语音** | 各角色主要台词 | ~30 条, ~300s | VoxCPM2 声音克隆 |
|
||
| **NPC Round 2/3 反应** | 对话分支反应 | ~54 条, ~205s | VoxCPM2 声音克隆 |
|
||
| **self-3y 三版** | 时光胶囊备忘录 ×3 | 3 条, ~150s | VoxCPM2(linxia 音色) |
|
||
| **UI 短音效** | 提示音、选择反馈、打字/发送 | ~12 种 | Web Audio 合成(无需文件) |
|
||
| **BGM** | 4 段主题音乐 | 4 段 | Suno / Udio 生成 |
|
||
| **环境音** | 卧室夜噪、酒吧、街声 | 4-5 段 | Freesound (CC0/CC-BY) |
|
||
| **角色铃声** | 来电铃声 | 3-4 段 | 简单合成或 Suno 短旋律 |
|
||
|
||
### 7.2 TTS 方案:VoxCPM2 本地声音克隆
|
||
|
||
所有角色语音使用 **VoxCPM2**(本地部署,无需外部 API),通过声音克隆实现一致的角色音色。
|
||
|
||
**服务启动**:
|
||
```bash
|
||
bash /home/xsl/AutoVideo/start-voxcpm.sh
|
||
# uvicorn 服务: http://127.0.0.1:8000
|
||
```
|
||
|
||
**API 接口**:
|
||
- `POST /v1/voices` — 注册参考音频(wav_base64)→ 返回 voice_id
|
||
- `POST /v1/speech` — 合成语音(text + voice_id)→ 返回 WAV
|
||
- 输出格式:48kHz 16-bit PCM WAV
|
||
- 参数:cfg_value(默认 2.0)、inference_timesteps(默认 10)
|
||
|
||
**声音克隆流程**:
|
||
```
|
||
参考音频 (voice/{角色}/*.wav)
|
||
→ 转换为 16kHz mono WAV
|
||
→ POST /v1/voices 注册 → voice_id
|
||
→ POST /v1/speech 合成台词 → WAV
|
||
→ ffmpeg atempo 调速 → 最终音频
|
||
```
|
||
|
||
### 7.3 角色音色配置
|
||
|
||
| 角色 | 参考音频目录 | 语速 | 音色描述 |
|
||
|------|-------------|------|---------|
|
||
| **林夏** | `voice/linxia/` | 1.00 | 24 岁女生,疲惫但清醒,克制但有温度 |
|
||
| 妈妈 | `voice/mom/` | 0.92 | 50 上下,温柔不黏腻,西部口音轻微 |
|
||
| 阿哲 | `voice/azhe/` | 1.05 | 27 岁,城市男生,理性偏冷 |
|
||
| 小美 | `voice/xiaomei/` | 1.10 | 24 岁,活泼,语速快 |
|
||
| 小美(醉) | `voice/xiaomei/` | 0.95 | 同音色,降速模拟醉态 |
|
||
| 周南 | `voice/zhounan/` | 0.95 | 26 岁,温和略拘谨 |
|
||
| HR 王姐 | `voice/hr/` | 1.00 | 38 岁,职场化,疲惫的善意 |
|
||
| 安安 | `voice/anan/` | 1.15 | 23 岁,活泼,比小美更嗲 |
|
||
| 室友 A | `voice/dorm_a/` | 1.10 | 年轻女声,兴奋 |
|
||
| 室友 B | `voice/dorm_b/` | 1.00 | 年轻女声,随和 |
|
||
| 室友 C | `voice/dorm_c/` | 0.95 | 年轻女声,温柔 |
|
||
| 外卖小哥 | `voice/delivery/` | 1.20 | 30 岁,麻利 |
|
||
| self-3y | `voice/linxia/` | 1.15 | 3 年前的林夏,更明朗(同一音色,不同语速) |
|
||
|
||
### 7.4 批量合成脚本
|
||
|
||
```bash
|
||
# 启动 VoxCPM2 服务
|
||
bash /home/xsl/AutoVideo/start-voxcpm.sh
|
||
|
||
# 使用 WAV 参考音色,批量合成所有台词
|
||
python audio/batch_tts_voxcpm.py --source voice
|
||
|
||
# 只合成特定角色
|
||
python audio/batch_tts_voxcpm.py --source voice --role linxia
|
||
|
||
# 干跑查看任务列表
|
||
python audio/batch_tts_voxcpm.py --source voice --dry-run
|
||
```
|
||
|
||
### 7.5 UI 音效(Web Audio 合成,无需文件)
|
||
|
||
所有 UI 音效通过 `SFX_UI` 对象在浏览器端实时合成:
|
||
|
||
| 音效 | 用途 | 实现方式 |
|
||
|------|------|---------|
|
||
| `tap` | 单击确认 | 880Hz, 45ms |
|
||
| `swipe` | 滑动确认 | 660Hz, 60ms |
|
||
| `error` | 无效操作 | 200Hz square, 100ms |
|
||
| `notify` | 新消息到达 | 523Hz + 659Hz 双音 |
|
||
| `choiceReady` | 进入选择 | 440→523→659 三音上行 |
|
||
| `choiceWarm` | 右滑温暖 | 440→659Hz 上行 |
|
||
| `choiceCold` | 左滑冷淡 | 523→349Hz 下行 |
|
||
| `choiceCurious` | 上滑追问 | 523→784Hz 快速上行 |
|
||
| `choiceSilent` | 下滑沉默 | 330Hz 极轻 |
|
||
| `typing` | 打字中 | 6 次随机频率短脉冲 |
|
||
| `send` | 发送 | 400→900Hz 上扫 |
|
||
| `ending` | 结局 | 三音渐弱 |
|
||
|
||
### 7.6 BGM 与环境音
|
||
|
||
| 曲目 | 用途 | 描述 |
|
||
|------|------|------|
|
||
| M1 | 全程低氛围 Loop | lo-fi midnight bedroom, soft piano, light vinyl noise |
|
||
| M2 | MSG-08/09 悬疑 | subtle ambient suspense, low drone |
|
||
| M3 | MSG-13 周南段落 | gentle indie folk, fingerpicked guitar |
|
||
| M4 | MSG-16 结尾 | warm cinematic piano, single melody line |
|
||
|
||
环境音根据 PROFILE 累计分数动态调整:
|
||
- engagement 倾向:柔和雨声、远处隐约的音乐
|
||
- avoidance 倾向:安静、时钟滴答、远处车声
|
||
- nostalgia 倾向:梦幻混响、远处风铃
|
||
|
||
---
|
||
|
||
## 8. 技术实现
|
||
|
||
### 8.1 技术栈
|
||
|
||
纯前端 Web 应用(单 HTML + JS),无需后端服务器:
|
||
- **手势识别**:`gestures.js` — 6 种手势(单击、双击、四方向滑动)
|
||
- **音频管理**:`audio.js` — Web Audio API 合成 + HTML5 Audio 播放
|
||
- **触觉反馈**:`haptics.js` — Vibration API
|
||
- **剧情数据**:`story.js` — 16 条消息的完整对话树
|
||
- **游戏引擎**:`engine.js` — 状态机 + 异步对话流程
|
||
- **行为画像**:`profile.js` — PROFILE 计分 + 状态变量
|
||
|
||
### 8.2 状态机
|
||
|
||
```
|
||
idle → notification/ringing → playing → choosing → responding → reacting → [choosing | idle] → ending
|
||
```
|
||
|
||
| 状态 | 说明 | 可用手势 |
|
||
|------|------|---------|
|
||
| idle | 等待消息 | — |
|
||
| notification | 消息到达提示中 | 单击(播放)、双击(跳过) |
|
||
| ringing | 来电铃声中 | 单击(接听)、左滑(拒接) |
|
||
| playing | NPC 语音播放中 | 双击(跳过语音) |
|
||
| choosing | 等待玩家选择 | 右滑、左滑、上滑、下滑、单击 |
|
||
| responding | 林夏语音播放中 | 双击(跳过) |
|
||
| reacting | NPC 反应播放中 | 双击(跳过) |
|
||
| ending | 结局播放中 | — |
|
||
|
||
### 8.3 异步对话流程
|
||
|
||
```javascript
|
||
async _handleChoice(dir) {
|
||
const choice = currentMsg.choices[dir];
|
||
|
||
// 1. 情感音效
|
||
SFX_UI[emotionSfx[dir]]();
|
||
|
||
// 2. 打字 → 发送
|
||
state = 'responding';
|
||
SFX_UI.typing();
|
||
await sleep(800);
|
||
SFX_UI.send();
|
||
await sleep(300);
|
||
|
||
// 3. 林夏的回应
|
||
if (choice.linxia) {
|
||
await playVoiceAsync([choice.linxia]);
|
||
} else {
|
||
await sleep(1500); // 沉默
|
||
}
|
||
|
||
// 4. NPC 反应
|
||
if (choice.npcReact) {
|
||
state = 'reacting';
|
||
await playVoiceAsync(choice.npcReact);
|
||
}
|
||
|
||
// 5. 后续对话(Round 3)
|
||
if (choice.followUp) {
|
||
state = 'playing';
|
||
await playVoiceAsync(choice.followUp.audio);
|
||
if (choice.followUp.choices) {
|
||
enterChoosing(choice.followUp.choices);
|
||
return;
|
||
}
|
||
}
|
||
|
||
// 6. 推进到下一条
|
||
proceedToNext();
|
||
}
|
||
```
|
||
|
||
### 8.4 跳过机制
|
||
|
||
在 `responding` 或 `reacting` 状态中双击:
|
||
- 设置 `_skipRequested = true`
|
||
- 中断当前语音播放
|
||
- 异步函数在每个步骤检查 skip 标志,快速跳到下一阶段
|
||
|
||
### 8.5 隐私承诺
|
||
|
||
本作**不申请任何敏感权限**:
|
||
- ❌ 不要麦克风、摄像头、位置、通讯录
|
||
- ❌ 不需要联网(全程离线可玩)
|
||
- ✅ 仅使用:触觉震动 + 触控输入 + 系统音量
|
||
- 玩家行为数据只在本地存储,从不上传。
|
||
|
||
---
|
||
|
||
## 9. 音频资产清单
|
||
|
||
### 林夏语音
|
||
|
||
| 类别 | 数量 | 平均时长 | 总时长 |
|
||
|------|------|---------|-------|
|
||
| 通用短句(嗯、好、知道了等) | ~10 条 | 1s | ~10s |
|
||
| 消息专属台词 | ~45 条 | 2s | ~90s |
|
||
| **合计** | **~55 条** | | **~100s** |
|
||
|
||
### NPC 语音(Round 1 主台词 + Round 2/3 反应)
|
||
|
||
| 角色 | Round 1 | Round 2/3 | 总条数 | 总时长 |
|
||
|------|---------|-----------|-------|-------|
|
||
| 妈妈 | 11 段 | 10 条 | ~21 条 | ~340s |
|
||
| 小美 | 7 段 | 10 条 | ~17 条 | ~120s |
|
||
| 阿哲 | 2 段 | 8 条 | ~10 条 | ~50s |
|
||
| 周南 | 5 段 | 10 条 | ~15 条 | ~80s |
|
||
| HR 王姐 | 1 段 | 3 条 | ~4 条 | ~20s |
|
||
| 安安 | 1 段 | 5 条 | ~6 条 | ~20s |
|
||
| 寝室群 | 5 段 | 8 条 | ~13 条 | ~50s |
|
||
| 外卖小哥 | 1 段 | 0 | ~1 条 | ~5s |
|
||
| self-3y | 3 版 | 0 | ~3 条 | ~150s |
|
||
| **合计** | | | **~90 条** | **~835s** |
|
||
|
||
### 总计
|
||
|
||
- 林夏 ~55 条,~100 秒
|
||
- NPC ~90 条,~835 秒
|
||
- **总语音约 145 条,约 15.5 分钟**
|
||
- UI 音效:12 种,全部 Web Audio 合成
|
||
- BGM:4 段
|
||
- 环境音:4-5 段
|
||
|
||
---
|
||
|
||
## 10. 项目文件结构
|
||
|
||
```
|
||
blind/
|
||
├── game/
|
||
│ ├── index.html # 入口
|
||
│ └── js/
|
||
│ ├── main.js # 启动 + 事件绑定
|
||
│ ├── gestures.js # 6 种手势识别
|
||
│ ├── haptics.js # 触觉反馈
|
||
│ ├── audio.js # 音频管理 + UI 合成音效
|
||
│ ├── story.js # 16 条消息剧情数据
|
||
│ ├── engine.js # 游戏引擎(状态机 + 对话流程)
|
||
│ ├── profile.js # 行为画像 + 状态变量
|
||
│ └── utils.js # 工具函数(sleep, dbg 等)
|
||
├── audio/
|
||
│ ├── mp3/
|
||
│ │ ├── linxia/ # 林夏语音(当前 edge-tts 版本)
|
||
│ │ └── react/ # NPC 反应语音(当前 edge-tts 版本)
|
||
│ ├── 00_raw/tts/ # VoxCPM2 生成原始 WAV
|
||
│ └── batch_tts_voxcpm.py # VoxCPM2 批量合成脚本
|
||
├── voice/ # VoxCPM2 参考音色(WAV)
|
||
│ ├── linxia/ # 林夏
|
||
│ ├── mom/ # 妈妈
|
||
│ ├── azhe/ # 阿哲
|
||
│ ├── xiaomei/ # 小美
|
||
│ ├── zhounan/ # 周南
|
||
│ ├── hr/ # HR 王姐
|
||
│ ├── anan/ # 安安
|
||
│ ├── dorm_a/ # 室友 A
|
||
│ ├── dorm_b/ # 室友 B
|
||
│ ├── dorm_c/ # 室友 C
|
||
│ └── delivery/ # 外卖小哥
|
||
├── gdd/
|
||
│ └── redesign_v2.md # v2 重构设计文档
|
||
└── 林夏.md # 本文档(总设计纲要)
|
||
```
|
||
|
||
---
|
||
|
||
## 11. 风险与对策
|
||
|
||
| 风险 | 对策 |
|
||
|------|------|
|
||
| VoxCPM2 长情绪戏(妈妈 4 分钟)质感不够 | 分段录制 + 后期拼接,预留调参时间 |
|
||
| 声音克隆音色不够区分 | 每角色选择差异大的参考音频 + 调速区分 |
|
||
| 60+ 分支语音管理复杂 | batch_tts_voxcpm.py 统一管理,命名规范 |
|
||
| 手势误判导致选错 | 滑动阈值 30px + 40°范围;双击间隔 250ms 内 |
|
||
| 玩家不理解手势含义 | MSG-02(小美教学关)强引导,每步正向反馈 |
|
||
| 女性玩家代入感 | 编剧组需有 24 岁左右女性参与 |
|
||
| 题材敏感 | 开场加心理预警 + 提供试玩版 |
|
||
|
||
---
|
||
|
||
## 12. 制作流程
|
||
|
||
| 阶段 | 关键交付 |
|
||
|------|---------|
|
||
| **剧本定稿** | 16 条全脚本 + 5 结局完整对白 + 所有分支台词 |
|
||
| **参考音色准备** | voice/ 下 12 个角色参考音频确认 |
|
||
| **VoxCPM2 批量合成** | ~145 条语音 + 语速调整 + 质检 |
|
||
| **BGM + 环境音** | 4 段 BGM + 环境采样 |
|
||
| **程序集成** | story.js 对接最终音频路径 + 全流程调试 |
|
||
| **测试** | 全 5 结局通关测试 + 分支覆盖 |
|
||
|
||
---
|
||
|
||
## 附录 · 一句话给主创
|
||
|
||
> "这不是一个让女孩们更难过的游戏。这是一个让她们在难过的时候,知道有人也曾这样难过、并且活下来的游戏。"
|