This commit is contained in:
2026-05-13 03:10:55 +08:00
154 changed files with 16812 additions and 708 deletions

View File

@@ -0,0 +1,99 @@
# 宝贝识物寓教于乐模板 PRD 2026-05-11
## 1. 目标
新增寓教于乐内容线的创作模板:
```text
宝贝识物
```
创作者必须通过该模板创作并发布作品后,用户才能在寓教于乐板块体验对应关卡。
本模板只服务儿童动作 Demo 内容线,不把普通教育题材作品自动归入寓教于乐。
## 2. 创作输入
创作者必须填写两个物品名称:
1. 物品 A 名称;
2. 物品 B 名称。
两个名称都必须去除首尾空白后非空。当前阶段不新增题材、难度、计时、失败次数、分数、体力或递增规则。
## 3. 生成规则
提交后生成一份宝贝识物草稿,草稿包含:
1. 模板 ID`baby-object-match`
2. 模板名称:`宝贝识物`
3. 两个物品;
4. 两个物品图;
5. 作品标签。
物品图使用 VectorEngine `gpt-image-2-all` / image-2 生成。图片生成只能走后端或后续后端预留接口,前端不得泄露 `VECTOR_ENGINE_API_KEY`
本地 Demo 阶段若真实生图接口未接入完成,允许前端 service 返回明确标记为 `placeholder` 的占位图形,用于打通创作到结果页的交互链路;该占位结果不得伪装成正式 image-2 资产。
## 4. 标签规则
发布作品必须携带精确标签:
```text
寓教于乐
```
标签识别只接受精确等于 `寓教于乐`。不接受 `儿童教育``动作教育``寓教于乐 ` 等近似标签。
宝贝识物草稿与发布 payload 中都必须保留该标签。发布后的公开展示、搜索、深链和入口开关继续遵循 `CHILD_MOTION_EDUTAINMENT_DISCOVER_ENTRY_2026-05-09.md`
## 5. 结果页能力
结果页展示:
1. 作品名称;
2. 两个物品名称;
3. 两个物品图;
4. 标签;
5. 保存草稿;
6. 发布;
7. 试玩。
结果页不展示长规则说明文案。试玩按钮直接进入宝贝识物首关本地运行态。
试玩按钮进入宝贝识物首关运行态,运行态消费当前草稿中的两个物品名称和两张物品图,不重新生成或改写物品内容。
## 6. 发布后体验
发布完成后作品应进入寓教于乐内容线,并在寓教于乐入口开启时可被板块消费。
入口关闭时,发布作品完全不可见,不能通过推荐、发现普通频道、搜索、作品号、公开详情深链或浏览历史访问。
## 7. 与运行时线程的边界
本 PRD 同步约束首关运行态,已确认规则包括:
1. 礼物盒打开在本地调试绑定 `F` 键;
2. 每轮仅中间礼物盒跳出的物品随机;左右两侧篮子固定为当前草稿两个物品的顺序;
3. 下一关按钮当前占位;
4. 不新增用户未确认的计时、失败次数、分数、体力或难度递增。
5. 屏幕中上方字幕固定为“将物品放入对应的篮子里”。
6. 礼物盒位于屏幕中下方,任意手抬起后打开并跳出下一个随机物品。
7. 屏幕下方左侧和右侧分别展示两个固定篮子,左侧固定使用草稿第一个物品图,右侧固定使用草稿第二个物品图。
8. 明确左手连续横向移动达到阈值时将当前物品送入左侧篮子,明确右手连续横向移动达到阈值时将当前物品送入右侧篮子;选篮不使用动作名判定,侧别未知的手部轨迹不参与选篮。
9. 正确时展示“真棒”字幕和正确特效;错误时展示“再想一想吧”字幕和错误特效,物品回到中央。
10. 成功 20 次后展示“恭喜你!小朋友!”字幕和特效,并展示“再来一次”和“下一关”按钮。
11. 当前本地 Demo 阶段音效与语音播报接口只预留调用点,不在前端写死外部硬件或服务接口。
## 8. 验收
1. 创作入口显示 `宝贝识物` 并可进入模板表单。
2. 未填写任一物品名称时不能生成草稿。
3. 生成草稿后进入结果页,展示两个物品名称和物品图。
4. 草稿标签中始终包含精确 `寓教于乐`
5. 发布 payload 始终包含精确 `寓教于乐`
6. 发布完成后出现分享弹窗或发布完成状态。
7. 前端不读取或暴露 VectorEngine 密钥。
8. 结果页试玩进入宝贝识物运行态,不再显示“试玩关卡正在接入中”。
9. 运行态可通过 `F` 打开礼物盒,通过鼠标左键拖动映射左手横向移动,通过鼠标右键拖动映射右手横向移动。
10. 成功 20 次后出现“再来一次”和“下一关”按钮。

View File

@@ -0,0 +1,412 @@
# 汪汪声浪大作战 / bark-battle BDD 验收场景
## 背景
- 需求来源:用户提供的视频 `C:\Users\DSK\Videos\一款双方比狗叫的游戏 - 1.一款双方比狗叫的游戏(Av116504192360177,P1).mp4`,并已在 `.hermes/plans/2026-05-11_144229-bark-battle-2d-game-bdd-ddd-tdd-plan.md` 中完成抽帧分析和玩法方案整理。
- 玩法定位:浏览器 2D 声控狗叫对战小游戏,暂定中文名 `汪汪声浪大作战`,英文代号与 play type ID 建议为 `bark-battle`
- 核心玩法:双方狗狗在 30 秒限时内通过麦克风输入“狗叫声”进行声浪拔河;系统依据声音强度、有效叫声次数和叫声节奏计算推动力,实时推动顶部红蓝能量条;倒计时结束后按能量条位置判定胜负或平局。
- 文档目的:为产品、测试、前端、后端在编码前统一可验证验收口径;本文只定义 PRD/BDD 级行为与测试映射,不实现工程代码。
## 角色与目标
### 主要角色
- 浏览器玩家:进入 `bark-battle` 玩法,用麦克风发声参与对战。
- 移动端玩家:在手机浏览器中进入玩法,需要看到核心游戏信息并完成授权、对战、结算。
- 无麦克风或无 API 支持玩家:设备或浏览器不支持声控输入时,需要得到明确降级反馈并可返回。
- 测试人员:依据本文场景验证权限、校准、叫声识别、能量条、胜负结算和布局兼容。
- 前端实现人员:依据本文拆分 Web Audio 输入、领域规则、Phaser/DOM HUD 表现和自动化测试。
### 用户目标
- 玩家可以在开局前完成麦克风授权和环境噪音校准。
- 玩家发出有效狗叫时,能看到叫声计数、狗狗动画、拟声词/冲击波以及能量条变化。
- 低于阈值的背景噪音不会被误计为有效叫声。
- 单局在 30 秒后给出明确胜负、平局和关键数据。
- 移动端和不支持麦克风的环境不会进入不可操作状态。
### 非目标
- MVP 不要求识别“是否真实狗叫”,不引入机器学习声纹/物种分类;有效输入以音量阈值、峰值间隔、持续时间和校准结果为准。
- MVP 不要求实时联机对战;可先按“玩家 vs AI 对手”完成单机浏览器 runtime。
- MVP 不要求成绩持久化、作品发布、作品架、广场和排行榜;若后续接入 Genarrative 作品闭环,需要另补玩法类型集成 PRD/技术文档。
- MVP 不要求在 UI 中长期展示大段规则说明;游戏界面应保持倒计时、能量条、狗狗、麦克风状态和结算信息为主。
- MVP 不处理竞技级反作弊;播放录音、拍桌、喊叫等非狗叫输入只作为后续公平性风险记录。
## 业务规则口径
- 单局时长:默认 30 秒,从正式进入 `playing` 阶段开始计时。
- 能量条:使用 `-100``100` 的连续值表示,负数偏对手侧,正数偏玩家侧,`0` 为中线。
- 平局阈值:倒计时结束时,若能量条绝对值小于或等于 `drawThreshold`,判定平局;具体数值由实现配置,但测试需可注入固定阈值。
- 有效叫声:一次有效叫声至少满足:音量超过校准后的有效阈值、与上一次有效峰值间隔不小于 `minBarkGapMs`、持续时长在 `minBarkDurationMs``maxBarkDurationMs` 之间。
- 背景噪音:校准阶段采集到的环境声用于计算动态阈值;低于阈值的输入不得增加叫声次数,也不得让能量条出现可见推进。
- 推动力:玩家推动力由音量分数、有效叫声频率和连击加成组成;能量条按玩家推动力与对手推动力差值移动,并被限制在 `-100``100`
- UI 反馈:有效叫声应触发可观察反馈,包括玩家侧狗狗张嘴/吠叫动画、拟声词或冲击波;反馈不应遮挡倒计时和顶部能量条。
## 中文 Gherkin 场景
### 功能: 麦克风授权与开局准备
```gherkin
功能: 狗叫对战麦克风准备
背景:
假如 bark-battle
而且 navigator.mediaDevices.getUserMedia
场景: 玩家允许麦克风权限后进入环境噪音校准
那么
而且 playing
而且
场景: 校准完成后进入开局倒计时
假如
而且
那么
而且 30
而且线
场景: 玩家拒绝麦克风权限后不能开始声控对战
那么
而且
而且 playing
```
### 功能: 环境噪音校准
```gherkin
功能: 环境噪音校准
场景: 安静环境生成低但非零的有效阈值
假如 RMS 线
那么
而且
场景: 嘈杂环境生成更高的有效阈值
假如 RMS 线
那么
而且
场景: 校准期间无法获得有效音频样本
假如
那么
而且
而且
```
### 功能: 有效叫声计数
```gherkin
功能: 有效叫声计数
背景:
假如 30 playing
而且
场景: 单次超过阈值且间隔足够的叫声计数加一
假如 0
而且 minBarkGapMs
那么 1
而且
而且
场景: 持续噪音不会被无限计数
假如 1
那么 tick
而且
场景: 间隔过短的连续峰值不重复计数
假如
minBarkGapMs
那么
而且
```
### 功能: 声音大小和连续叫声推动能量条
```gherkin
功能: 声浪推动能量条
背景:
假如 30 playing
而且线
场景: 玩家推动力高于对手时能量条向玩家侧移动
假如
而且
simulation tick
那么
而且
场景: 连续大声叫声触发更强反馈
假如
那么
而且
但是
场景: 能量条到达边界后不会越界
假如
而且
simulation tick
那么 100
而且
场景: 对手推动力高于玩家时能量条向对手侧移动
假如
simulation tick
那么
而且
```
### 功能: 低噪音和无效输入过滤
```gherkin
功能: 背景噪音过滤
背景:
假如 30 playing
而且
场景: 低于阈值的背景噪音不计数
那么
而且
而且
场景: 过短脉冲不计为有效叫声
假如
但是 minBarkDurationMs
那么
而且
场景: 过长持续声被削弱为单段输入
假如
但是 maxBarkDurationMs
那么
而且
```
### 功能: 倒计时与胜负结算
```gherkin
功能: 狗叫对战胜负结算
30
背景:
假如 30 playing
场景: 倒计时每秒递减并在归零时停止对战输入
30 0
那么
而且 finished
而且
场景: 玩家侧占优时判定玩家胜利
假如 drawThreshold
那么
而且
而且
场景: 对手侧占优时判定玩家失败
假如 -drawThreshold
那么
而且
而且
场景: 能量条接近平衡时判定平局
假如 -drawThreshold drawThreshold
那么
而且
而且
```
### 功能: 再来一局与状态重置
```gherkin
功能: 对战重开
场景: 结算后点击再来一局重置本局状态
假如 finished
而且
那么 30
而且线
而且
而且
场景: 结算后返回玩法入口
假如 finished
那么
而且
```
### 功能: 移动端布局
```gherkin
功能: 移动端 bark-battle 布局
场景: 移动端进入对战页面时核心元素可见
假如使 430px
bark-battle
那么
而且
而且
而且
场景: 移动端授权和开始必须由用户手势触发
假如使
那么
而且 AudioContext
场景: 移动端结算面板不遮挡主要操作
假如
那么
而且
```
### 功能: 无 getUserMedia 或不可用环境降级
```gherkin
功能: 无麦克风 API 降级
API
退
场景: 当前浏览器不支持 getUserMedia
假如 navigator.mediaDevices.getUserMedia
bark-battle
那么
而且
而且
场景: getUserMedia 调用失败但浏览器 API 存在
假如 getUserMedia
但是 NotFoundError NotReadableError
那么
而且
而且 playing
场景: 非安全上下文导致麦克风不可用
假如
bark-battle
那么使
而且使
而且
```
### 功能: 刷新与退出时释放麦克风资源
```gherkin
功能: 麦克风资源释放
场景: 对战中离开页面停止采集
假如 playing
bark-battle
那么 MediaStream
而且 simulation tick
场景: 刷新页面后不沿用旧局临时状态
假如 playing
bark-battle
那么
而且沿
```
## 测试映射
| 场景 | 测试层级 | 建议目标文件 | 自动化状态 |
| --- | --- | --- | --- |
| 玩家允许麦克风权限后进入环境噪音校准 | application/component | `src/games/bark-battle/application/BarkBattleController.test.ts`, `src/games/bark-battle/ui/BarkBattlePermissionPanel.test.tsx` | planned |
| 校准完成后进入开局倒计时 | application/unit | `src/games/bark-battle/application/BarkBattleController.test.ts`, `src/games/bark-battle/domain/BarkBattleSession.test.ts` | planned |
| 玩家拒绝麦克风权限后不能开始声控对战 | application/component | `src/games/bark-battle/application/BarkBattleController.test.ts`, `src/games/bark-battle/ui/BarkBattlePermissionPanel.test.tsx` | planned |
| 安静环境生成低但非零的有效阈值 | unit | `src/games/bark-battle/domain/BarkNoiseCalibration.test.ts` | planned |
| 嘈杂环境生成更高的有效阈值 | unit | `src/games/bark-battle/domain/BarkNoiseCalibration.test.ts` | planned |
| 校准期间无法获得有效音频样本 | application/component | `src/games/bark-battle/application/BarkBattleController.test.ts`, `src/games/bark-battle/ui/BarkBattlePermissionPanel.test.tsx` | planned |
| 单次超过阈值且间隔足够的叫声计数加一 | unit | `src/games/bark-battle/domain/BarkDetector.test.ts` | planned |
| 持续噪音不会被无限计数 | unit | `src/games/bark-battle/domain/BarkDetector.test.ts` | planned |
| 间隔过短的连续峰值不重复计数 | unit | `src/games/bark-battle/domain/BarkDetector.test.ts` | planned |
| 玩家推动力高于对手时能量条向玩家侧移动 | unit | `src/games/bark-battle/domain/EnergyTugOfWar.test.ts` | planned |
| 连续大声叫声触发更强反馈 | unit/integration/component | `src/games/bark-battle/domain/BarkBattleScoring.test.ts`, `src/games/bark-battle/ui/BarkBattleHud.test.tsx` | planned |
| 能量条到达边界后不会越界 | unit | `src/games/bark-battle/domain/EnergyTugOfWar.test.ts` | planned |
| 对手推动力高于玩家时能量条向对手侧移动 | unit | `src/games/bark-battle/domain/EnergyTugOfWar.test.ts` | planned |
| 低于阈值的背景噪音不计数 | unit | `src/games/bark-battle/domain/BarkDetector.test.ts` | planned |
| 过短脉冲不计为有效叫声 | unit | `src/games/bark-battle/domain/BarkDetector.test.ts` | planned |
| 过长持续声被削弱为单段输入 | unit | `src/games/bark-battle/domain/BarkDetector.test.ts` | planned |
| 倒计时每秒递减并在归零时停止对战输入 | unit/application | `src/games/bark-battle/domain/BarkBattleSession.test.ts`, `src/games/bark-battle/application/BarkBattleController.test.ts` | planned |
| 玩家侧占优时判定玩家胜利 | unit/component | `src/games/bark-battle/domain/BarkBattleSession.test.ts`, `src/games/bark-battle/ui/BarkBattleResultPanel.test.tsx` | planned |
| 对手侧占优时判定玩家失败 | unit/component | `src/games/bark-battle/domain/BarkBattleSession.test.ts`, `src/games/bark-battle/ui/BarkBattleResultPanel.test.tsx` | planned |
| 能量条接近平衡时判定平局 | unit/component | `src/games/bark-battle/domain/BarkBattleSession.test.ts`, `src/games/bark-battle/ui/BarkBattleResultPanel.test.tsx` | planned |
| 结算后点击再来一局重置本局状态 | application/component | `src/games/bark-battle/application/BarkBattleController.test.ts`, `src/games/bark-battle/ui/BarkBattleResultPanel.test.tsx` | planned |
| 结算后返回玩法入口 | integration/smoke | `src/games/bark-battle/application/BarkBattleController.test.ts`, Playwright 或人工 smoke 清单 | planned |
| 移动端进入对战页面时核心元素可见 | component/visual/smoke | `src/games/bark-battle/ui/BarkBattleHud.test.tsx`, Playwright 移动端视口 smoke | planned |
| 移动端授权和开始必须由用户手势触发 | infrastructure/application/e2e-smoke | `src/games/bark-battle/infrastructure/__tests__/BrowserMicrophoneInput.test.ts`, `src/games/bark-battle/application/__tests__/BarkBattleController.test.ts`, Playwright 移动端 smoke | planned |
| 移动端结算面板不遮挡主要操作 | component/visual/smoke | `src/games/bark-battle/ui/__tests__/BarkBattleResultPanel.test.tsx`, Playwright 移动端视口 smoke | planned |
| 当前浏览器不支持 getUserMedia | infrastructure/component | `src/games/bark-battle/infrastructure/__tests__/BrowserMicrophoneInput.test.ts`, `src/games/bark-battle/ui/__tests__/BarkBattlePermissionPanel.test.tsx` | planned |
| getUserMedia 调用失败但浏览器 API 存在 | infrastructure/application/component | `src/games/bark-battle/infrastructure/__tests__/BrowserMicrophoneInput.test.ts`, `src/games/bark-battle/application/__tests__/BarkBattleController.test.ts`, `src/games/bark-battle/ui/__tests__/BarkBattlePermissionPanel.test.tsx` | planned |
| 非安全上下文导致麦克风不可用 | infrastructure/application/component | `src/games/bark-battle/infrastructure/__tests__/BrowserMicrophoneInput.test.ts`, `src/games/bark-battle/application/__tests__/BarkBattleController.test.ts`, `src/games/bark-battle/ui/__tests__/BarkBattlePermissionPanel.test.tsx` | planned |
| 对战中离开页面停止采集 | infrastructure/application/integration | `src/games/bark-battle/infrastructure/__tests__/BrowserMicrophoneInput.test.ts`, `src/games/bark-battle/application/__tests__/BarkBattleController.test.ts` | planned |
| 刷新页面后不沿用旧局临时状态 | integration/smoke | Playwright 或人工 smoke 清单 | planned |
## 验收清单
- [ ] 权限允许、拒绝、非安全上下文、API 不支持、麦克风未找到/不可读、AudioContext 被拦截、校准超时或样本不可读均有明确状态,且不会误进入 playing。
- [ ] 校准阶段会影响有效叫声阈值,低噪音不会增加叫声计数。
- [ ] 有效叫声计数具备阈值、峰值间隔、持续时长约束。
- [ ] 能量条根据双方推动力差值双向移动,并限制在 `-100``100`
- [ ] 30 秒归零后停止本局输入影响,并按玩家胜利、对手胜利、平局三类结果结算。
- [ ] 移动端核心元素可见,非关键设置收起,不在主画面堆叠长规则说明。
- [ ] 离开页面或返回入口时停止麦克风采集。
- [ ] 每个编码依据场景已在测试映射中标注测试层级和建议文件。
## 开放问题
1. MVP 是否确认只做“玩家 vs AI”还是第一版需要双人同屏或联机对战
2. `drawThreshold``minBarkGapMs``minBarkDurationMs``maxBarkDurationMs` 的首版默认值由产品/调参阶段确认,还是先采用开发可配置默认值?
3. 是否允许无麦克风设备提供键盘/点击备用输入?若允许,需要另补非声控模式场景;若不允许,当前降级只提供返回入口。
4. 是否需要在结算中记录或上报成绩、最高音量、叫声次数和声浪评分?若需要,需补埋点/后端持久化场景。
5. bark-battle 是否作为 Genarrative 正式 play type 接入创作入口、作品发布和广场,还是先作为独立 runtime 原型验证?
6. 狗狗、背景、拟声词和冲击波素材来源是临时占位、AI 生成,还是复用项目现有素材管线?

View File

@@ -4,6 +4,7 @@
## 重点入口
- [宝贝识物寓教于乐模板 PRD](./BABY_OBJECT_MATCH_EDUTAINMENT_TEMPLATE_PRD_2026-05-11.md):定义寓教于乐内容线的 `宝贝识物` 创作模板覆盖两个物品名称输入、image-2 物品图生成、精确 `寓教于乐` 标签、结果页和发布边界。
- [AI 原生幕间文字游戏模板 PRD参考 MOKU 的剧本模拟器闭环](./AI_NATIVE_TEXT_GAME_TEMPLATE_MOKU_REFERENCE_PRD_2026-05-05.md):参考 MOKU / 幕间类 AI 文游的剧本游乐场、自由行动、AI GM、记忆和模拟器强反馈经验但只落为百梦 `text-game` 模板,复用平台接口,不迁入外部社区、支付、私有存档或回放。
- [AI 原生视觉小说模板 PRDTXT 玩法平台化接入](./AI_NATIVE_VISUAL_NOVEL_TEMPLATE_PRD_2026-05-05.md):参考 `Interactive-fiction-backend` / `Interactive-fiction-frontend` 的 TXT 玩法经验,但只保留视觉小说模板创作与运行闭环,完全使用 Genarrative 平台接口,并明确删除回放和外部平台功能。
- [AI 原生幸存者类游戏模板 PRD](./AI_NATIVE_SURVIVOR_CREATOR_AND_GAMEPLAY_SYSTEM_PRD_2026-05-05.md):定义 `survivor` 幸存者挑战模板,从 Agent 创作、结果页、资产、试玩、发布到后端权威配置与前端高频运行表现的完整闭环。