feat: add shared runtime input device layer
Some checks failed
CI / verify (push) Has been cancelled

This commit is contained in:
2026-05-10 17:50:00 +08:00
parent 643161a168
commit 86fc382413
12 changed files with 1095 additions and 179 deletions

View File

@@ -23,6 +23,9 @@
7. 当前作品没有下一关时,通关弹窗展示后端 handoff 返回的相似作品;用户点击具体候选作品时直接 `startPuzzleRun(profileId, null)`,从目标作品第 `1` 关重新开始。
8. 失败状态点击“重新开始”时,正式 run 使用当前关 `levelId` 重新 `startPuzzleRun`,草稿/本地 run 使用本地重建,二者都保留当前失败关卡。
9. 结果页草稿试玩没有正式后端 run 时,继续使用本地 run、local leaderboard 和本地下一关兜底。
10. 运行态输入采用全项目通用的 `src/services/input-devices/` 抽象层承接指针、触控、mocap 等设备都先归一为 `press / move / release / tap / drop` 拖拽语义,再由拼图运行态解析具体拼块和落点。
11. mocap `grab` 不是点击选中语义,而是持续拖拽语义;松手时按当前棋盘归一坐标提交 drop。合并大块只需要提交其中任一成员拼块 `pieceId`,本地拼图运行时会按 `mergedGroupId` 解析整组平移。
12. 拼图作品详情或开局遇到后端 `404 / NOT_FOUND / 资源不存在` 时,平台入口不再停留在空详情或运行态错误页,而是清理当前拼图详情/run 状态并返回首页。
## 工程落点
@@ -38,6 +41,15 @@
3. `src/components/rpg-entry/RpgEntryFlowShell.agent.interaction.test.tsx`
- 公开拼图玩法交互测试断言前端本地交换函数被调用。
- 同时断言后端 `swap / drag` 不参与棋盘交互,后端 `leaderboard / next-level` 继续参与非即时链路。
4. `src/services/input-devices/`
- `runtimeDragInputController` 提供设备无关的拖拽会话状态机。
- `runtimeInputGeometry` 提供屏幕坐标、归一坐标和网格命中的通用转换能力。
- 玩法组件只传入“这个点对应哪个目标”和“drop 到哪个目标”的玩法解释,不在输入层写拼图专用规则。
5. `src/components/puzzle-runtime/PuzzleRuntimeShell.tsx`
- 鼠标/触控与 mocap 共用同一个 runtime drag controller。
- 合并块成员不再被 mocap 路径过滤mocap 可从合并块任一占用格抓取,并复用本地运行时的大块拖拽规则。
6. `src/components/platform-entry/PlatformEntryFlowShellImpl.tsx`
- `openPuzzleDetail``openPuzzlePublicWorkDetail``startPuzzleRunFromProfile` 对拼图作品缺失统一回首页。
## 边界

View File

@@ -5,6 +5,7 @@
## 文档列表
- [CHILD_MOTION_DEMO_WARMUP_IMPLEMENTATION_SPEC_2026-05-09.md](./CHILD_MOTION_DEMO_WARMUP_IMPLEMENTATION_SPEC_2026-05-09.md):冻结儿童动作识别互动玩法 Demo 固定热身关的开发落地规格,覆盖横屏展示、摄像头背景虚化、角色剪影、绿色圆环 2 秒保持、动作教学、当前会话内空间边界记录和后续关卡安全暂停规则。
- [RUNTIME_INPUT_DEVICE_ABSTRACTION_2026-05-10.md](./RUNTIME_INPUT_DEVICE_ABSTRACTION_2026-05-10.md)记录运行态输入设备抽象层明确鼠标、触控、mocap 等设备统一归一为通用拖拽语义,玩法组件只负责解释目标和落点。
- [RUST_WORKSPACE_DEPENDENCY_CONSOLIDATION_2026-05-07.md](./RUST_WORKSPACE_DEPENDENCY_CONSOLIDATION_2026-05-07.md):记录 `server-rs` Cargo 依赖集中配置口径,第三方版本和 workspace 内部 crate path 统一维护在根 `server-rs/Cargo.toml`,成员 crate 只保留 feature/optional 差异。
- [DEV_RUST_STACK_PORT_CONFLICT_PRECHECK_2026-05-09.md](./DEV_RUST_STACK_PORT_CONFLICT_PRECHECK_2026-05-09.md):记录本地完整 Rust 栈启动时 `api-server`、主站 Vite 和后台 Vite 端口占用的误判根因、脚本预检策略和 Windows 排障命令。
- [VECTOR_ENGINE_GPT_IMAGE_2_GENERATION_2026-05-09.md](./VECTOR_ENGINE_GPT_IMAGE_2_GENERATION_2026-05-09.md):记录 GPT-image-2 图片生成从 APIMart 迁移到 VectorEngine `gpt-image-2-all` 的接口、环境变量、尺寸映射、错误口径和验收命令。

View File

@@ -0,0 +1,55 @@
# 运行态输入设备抽象层 2026-05-10
## 背景
拼图运行态接入 mocap 后,鼠标/触控和 mocap 曾各自维护一套选择、坐标换算和拖拽提交逻辑。这样会让新设备只能在单个玩法里打补丁,也容易出现同一动作在不同设备下语义不一致的问题:例如 mocap `grab` 只触发选中,而不是像鼠标按住一样持续拖拽。
后续运行态还会接摇杆、键盘、体感、摄像头手势等输入来源,因此输入设备接入必须收口到全项目通用层。
## 决策
新增 `src/services/input-devices/` 作为前端运行态通用输入设备抽象层:
1. `runtimeDragInputController` 只维护设备无关的拖拽会话状态机。
2. `runtimeInputGeometry` 只处理 client 坐标、归一坐标、元素边界和网格命中换算。
3. 设备适配层把鼠标、触控、mocap 等输入归一为 `press / move / release / tap / drop`
4. 玩法组件负责把通用输入点解释成自己的目标对象和落点,不把拼图、方洞或大鱼等玩法规则写进输入层。
## 当前接入
拼图运行态已接入该层:
- 鼠标/触控 `pointerdown / pointermove / pointerup` 进入同一个 drag controller。
- mocap `grab` 进入同一个 drag controller并强制使用持续拖拽语义。
- mocap 松手时按当前棋盘归一坐标提交 drop。
- 合并大块由拼图运行态把手部坐标命中到任一成员拼块;本地拼图运行时再按 `mergedGroupId` 执行整组平移。
## 接入规则
新玩法或新设备接入时遵循以下边界:
1. 输入层可以知道设备类型和几何换算,但不能知道玩法业务规则。
2. 设备适配层只负责把原始输入转换成通用输入事件。
3. 玩法壳层负责从通用输入点解析本玩法目标,例如拼块、洞口、角色或实体。
4. 玩法壳层负责决定 drop 后调用哪个本地运行态函数或后端接口。
5. 需要取消输入时优先按 `inputId` 取消,避免 mocap 丢帧误伤正在进行的鼠标/触控会话。
## 验证
基础抽象层验证:
```bash
npm run test -- src\services\input-devices\runtimeDragInputController.test.ts
```
拼图接入验证:
```bash
npm run test -- src\components\puzzle-runtime\PuzzleRuntimeShell.test.tsx
```
跨平台入口缺失作品兜底验证:
```bash
npm run test -- src\components\rpg-entry\RpgEntryFlowShell.agent.interaction.test.tsx -t "missing puzzle public detail returns to platform home"
```