feat: add edutainment drawing and visual package flows

This commit is contained in:
2026-05-14 14:17:10 +08:00
parent 10e8beea80
commit e444266e1e
109 changed files with 8788 additions and 996 deletions

View File

@@ -0,0 +1,202 @@
# 宝贝爱画本地 Demo 运行态实现方案 2026-05-13
## 1. 范围
本方案落地寓教于乐独立关卡:
```text
baby-love-drawing / 宝贝爱画
```
当前范围只做本地 Demo 闭环:
1. 寓教于乐频道默认关卡卡片;
2. 独立运行态;
3. mocap 与开发者调试输入;
4. Canvas 绘制和擦除;
5. image-2 绘画魔法后端代理;
6. localStorage 本地保存;
7. 直达路由开关保护。
本阶段不接正式持久化表,不新增作品发布、作品号、公开详情或搜索入口。
## 2. 前端接入点
已新增页面阶段:
```text
baby-love-drawing-runtime
```
已新增路由:
```text
/runtime/baby-love-drawing
```
已新增文件:
```text
packages/shared/src/contracts/edutainmentBabyDrawing.ts
src/services/edutainment-baby-drawing/babyDrawingClient.ts
src/components/edutainment-runtime/babyLoveDrawingModel.ts
src/components/edutainment-runtime/BabyLoveDrawingRuntimeShell.tsx
server-rs/crates/api-server/src/edutainment_baby_drawing.rs
```
已接入:
1. `src/components/rpg-entry/RpgEntryHomeView.tsx`:寓教于乐频道默认展示宝贝爱画卡片;
2. `src/components/platform-entry/PlatformEntryFlowShellImpl.tsx`:启动宝贝爱画运行态;
3. `src/components/platform-entry/platformEntryTypes.ts`:扩展 `SelectionStage`
4. `src/routing/appPageRoutes.ts`:扩展路由;
5. `src/routing/appRoutes.tsx`:直达路由开关保护;
6. `src/index.css`:补齐寓教于乐默认关卡卡片和宝贝爱画运行态样式;
7. `server-rs/crates/api-server/src/app.rs`:挂载绘画魔法后端路由。
## 3. 契约
契约放在:
```text
packages/shared/src/contracts/edutainmentBabyDrawing.ts
```
核心字段:
1. `templateId = "baby-love-drawing"`
2. `templateName = "宝贝爱画"`
3. `originalImageSrc` 保存原始画布图;
4. `magicImageSrc` 保存 image-2 魔法图,可为 `null`
5. `strokeTrace` 保存画笔和橡皮轨迹;
6. `saveMode = "original-only" | "original-and-magic"` 记录保存结果。
## 4. 运行态模型
运行态状态:
```text
drawing
finished
magicPending
magicReady
saved
```
工具:
```text
brush
eraser
```
颜色:
```text
红、橙、黄、绿、青、蓝、紫
```
按钮悬停:
1. 颜色选择只接受左手悬停,阈值 1500ms
2. 按钮选择接受任一手悬停,阈值 2000ms
3. 工具切换只接受右手在工具区域握拳。
4. 画笔 / 橡皮光标位置只接受右手坐标;左手缺帧或左手移动不得重置、替换或驱动画笔位置。
5. 左手需要显示独立位置指示器,帮助用户确认当前是否悬停在目标颜色上;该指示器只表达左手位置,不参与画笔 / 橡皮操作。
6. 本地 mocap handedness 当前按摄像头视角输出,宝贝爱画运行态消费前需要换算为用户身体视角:`rightHand` 作为用户左手,`leftHand` 作为用户右手。键鼠调试输入不做该换算。
7. 真实硬件短暂缺失某只手时,显示层保留上一帧位置约 320ms 并做轻微坐标平滑;绘制层仍只在当前帧确认用户右手存在时生效。
8. 为避免左手抢画笔,本关不做动态 handedness 换手纠正;`rightHand` 永远只进入用户左手选色通道,`leftHand` 永远只进入用户右手画笔通道。若硬件侧 handedness 继续抖动,宁可右手画笔短暂停住,也不允许左手驱动画笔。
9. 右手画笔通道增加单帧最大位移门禁;若 camera-left 候选点相对上一帧右手位置出现不合理大跳,判定为不可信帧,只保留上一帧光标并停止绘制。
## 5. Canvas 绘制
画板使用 DOM Canvas。
绘制规则:
1. 右手在画板内且状态为 `grab` 时生效;
2. 工具为 `brush` 时,以当前颜色绘制连续线段;
3. 工具为 `eraser` 时,以 `destination-out` 擦除;
4. 右手状态为 `open_palm` 或离开画板时结束当前笔画;
5. 当前帧没有右手坐标时只结束当前笔画,不把左手坐标用于绘制、擦除或光标定位;
6. 每条笔画记录工具、颜色、点位和时间。
## 6. 绘画魔法
前端 service
```text
createBabyDrawingMagicImage(payload)
```
后端接口:
```text
POST /api/creation/edutainment/baby-love-drawing/magic
```
请求体:
```json
{
"originalImageSrc": "data:image/png;base64,...",
"strokeTrace": []
}
```
响应体:
```json
{
"magicImageSrc": "data:image/png;base64,...",
"generationProvider": "vector-engine-gpt-image-2",
"prompt": "..."
}
```
后端使用 VectorEngine `gpt-image-2-all`,把原始画布图作为参考图,生成绘本风格图片。
本地未配置 VectorEngine 或接口失败时,前端允许提示错误并保留原图保存能力;不得把失败伪装成正式魔法图。
后端接入约束:
1. 接口需要 Bearer 鉴权;
2. 请求体限制为 8MB
3. `originalImageSrc` 只接受图片 Data URL
4. 笔触数量上限为 600 条;
5. 上游参考图字段使用 VectorEngine 统一契约 `image`
6. 关闭入口时,`creation_entry_config` 路由熔断可识别 `baby-love-drawing`
## 7. 本地保存
本地保存使用:
```text
localStorage key = genarrative.edutainmentBabyDrawing.localDrawings.v1
```
保存策略:
1. 魔法生成前保存:`saveMode = "original-only"`,只保存 `originalImageSrc`
2. 未保存原图直接生成魔法后保存:`saveMode = "original-and-magic"`,保存 `originalImageSrc``magicImageSrc`
3. 保存后展示“再画一张”和“返回”。
## 8. 验收命令
```bash
npm run test -- src/components/edutainment-runtime/babyLoveDrawingModel.test.ts src/components/edutainment-runtime/BabyLoveDrawingRuntimeShell.test.tsx src/services/edutainment-baby-drawing/babyDrawingClient.test.ts src/routing/appRoutes.test.ts
cargo test -p api-server edutainment_baby_drawing --manifest-path server-rs/Cargo.toml
cargo test -p api-server resolves_runtime_paths_to_creation_type_ids --manifest-path server-rs/Cargo.toml
npx eslint src/components/edutainment-runtime/BabyLoveDrawingRuntimeShell.tsx src/components/edutainment-runtime/babyLoveDrawingModel.ts src/services/edutainment-baby-drawing/babyDrawingClient.ts src/routing/appRoutes.tsx --ext .ts,.tsx --max-warnings 0
npm run typecheck
npm run check:encoding
```
## 9. 已覆盖测试
1. `src/components/edutainment-runtime/babyLoveDrawingModel.test.ts`:颜色 / 按钮悬停阈值、坐标归一化、笔触追加;
2. `src/components/edutainment-runtime/BabyLoveDrawingRuntimeShell.test.tsx`:画板、七色、画笔 / 橡皮、完成保存、返回按钮、左手位置指示器、mocap 摄像头视角到用户身体视角换算、左手输入不替换画笔光标位置、左手短暂缺帧不闪烁、用户左手不能抢占右手画笔、camera-left 大跳不接入画笔;
3. `src/services/edutainment-baby-drawing/babyDrawingClient.test.ts`:原图保存、原图加魔法图保存、后端魔法接口请求;
4. `src/routing/appRoutes.test.ts``/runtime/baby-love-drawing` 开启可达、关闭回落主应用;
5. `server-rs/crates/api-server/src/edutainment_baby_drawing.rs` 内部单测prompt、Data URL 校验、PNG 输出和轨迹范围摘要;
6. `server-rs/crates/api-server/src/creation_entry_config.rs` 路由映射单测:确认后端熔断可识别 `baby-love-drawing`