# 宝贝爱画本地 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`。