# 运行态输入设备抽象层 2026-05-10 ## 背景 拼图运行态接入 mocap 后,鼠标/触控和 mocap 曾各自维护一套选择、坐标换算和拖拽提交逻辑。这样会让新设备只能在单个玩法里打补丁,也容易出现同一动作在不同设备下语义不一致的问题:例如 mocap `grab` 只触发选中,而不是像鼠标按住一样持续拖拽。 后续运行态还会接摇杆、键盘、体感、摄像头手势等输入来源,因此输入设备接入必须收口到全项目通用层。 ## 决策 新增 `src/services/input-devices/` 作为前端运行态通用输入设备抽象层: 1. `runtimeDragInputController` 只维护设备无关的拖拽会话状态机。 2. `runtimeInputGeometry` 只处理 client 坐标、归一坐标、元素边界和网格命中换算。 3. 设备适配层把鼠标、触控、mocap 等输入归一为 `press / move / release / tap / drop`。 4. 玩法组件负责把通用输入点解释成自己的目标对象和落点,不把拼图、方洞或大鱼等玩法规则写进输入层。 ## 当前接入 `useMocapInput` 解析 mocap `hands[].landmarks` 时应优先用 MediaPipe 21 点里的 `wrist / index_mcp / middle_mcp / ring_mcp / pinky_mcp` 加权计算掌心派生点;少于 3 个掌心关键点时才回退到 `wrist` 或直出 `hand.x/y`。这样运行态光标不会直接贴在腕部或指尖。 拼图运行态已接入该层: - 鼠标/触控 `pointerdown / pointermove / pointerup` 进入同一个 drag controller。 - mocap `grab` 进入同一个 drag controller,并强制使用持续拖拽语义。 - mocap 光标按 60Hz 插值更新 UI 位置,并在拖拽中用插值后的当前点持续驱动输入层,避免输入包帧率低或抖动时出现明显跳变。 - 合并大块由拼图运行态把手部坐标命中到任一成员拼块;本地拼图运行时再按 `mergedGroupId` 执行整组平移。 ## 调试模式 前端全局调试模式统一通过 `src/config/debugMode.ts` 判断。默认跟随 Vite 开发态:`import.meta.env.DEV` 为真时开启,生产构建默认关闭;如需显式覆盖,可设置 `VITE_DEBUG_MODE=true` 或 `VITE_DEBUG_MODE=false`。 拼图运行态的 mocap 调试面板只在全局调试模式下渲染。面板默认折叠,只保留一行连接状态,展开后才显示动作、手势、解析告警和原始包预览,避免开发诊断信息遮挡拼图棋盘和底部操作。 ## 接入规则 新玩法或新设备接入时遵循以下边界: 1. 输入层可以知道设备类型和几何换算,但不能知道玩法业务规则。 2. 设备适配层只负责把原始输入转换成通用输入事件。 3. 玩法壳层负责从通用输入点解析本玩法目标,例如拼块、洞口、角色或实体。 4. 玩法壳层负责决定 drop 后调用哪个本地运行态函数或后端接口。 5. 需要取消输入时优先按 `inputId` 取消,避免 mocap 丢帧误伤正在进行的鼠标/触控会话。 ## 验证 基础抽象层验证: ```bash npm run test -- src\services\input-devices\runtimeDragInputController.test.ts src\services\useMocapInput.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" ```