# 抓大鹅 Match3D 创作与运行态最小落地技术方案 2026-04-30 ## 1. 文档目的 本文件承接 PRD《AI 原生抓大鹅 Match3D 玩法创作工具与玩法系统 PRD》,冻结首版 demo 的最小可开发方案。 本轮目标不是先做一个纯前端临时小游戏,而是在当前平台内新增独立 `match3d` 玩法域,跑通下面这条最小主链: 1. 平台创作入口选择“抓大鹅”。 2. Agent 对话确认题材、需要消除次数和难度。 3. 编译 Match3D 草稿。 4. 进入结果页编辑游戏名称、标签和封面图。 5. 发布前试玩,可随时停止并返回修改。 6. 发布作品。 7. 玩家进入单局运行态。 8. 前端即时呈现点击、飞入、入槽、三消、腾格、胜负过渡。 9. 后端权威确认点击、入槽、消除、失败、胜利和成绩。 本文是后续并行开发的工程合同。若实现过程中发现字段、路由、表结构或前后端职责需要变化,必须先更新本文,再进入对应编码分支。 --- ## 2. 本轮明确不做 1. 不做多关卡链。 2. 不做排行榜展示。 3. 不做道具逻辑,只预留字段和扩展点。 4. 不做真实 3D 模型和真实 3D 物理遮挡。 5. 不做洗牌、重置、旋转、放大等局内操作。 6. 不做必须试玩通关才能发布。 7. 不做前端本地最终规则真相。 8. 不接入 `server-node` 或 PostgreSQL。 9. 不把 Match3D 挂到 RPG、拼图或大鱼吃小鱼旧命名下。 --- ## 3. 分层边界 ## 3.1 前端 前端继续使用当前 `React + TypeScript + Vite` 平台壳层,负责所有即时呈现的局内反馈: 1. 创作入口、Agent 工作区、结果页、试玩和运行态 UI。 2. 参考图片上传入口。 3. 运行态圆形空间、2D 物品、倒计时和 `7` 格备选栏展示。 4. 基于后端快照做 2D 命中检测、悬停、按压、选中反馈。 5. 在等待后端确认期间,先行播放飞入、入槽、三消、腾格、胜利和失败过渡。 6. 收到后端确认后,以权威快照校正本地表现。 7. 后端拒绝或版本冲突时,回滚本次即时反馈。 前端禁止: 1. 把本地即时反馈作为最终规则真相。 2. 本地生成可提交成绩。 3. 本地伪造胜利、失败、消除计数或运行态持久化结果。 4. 在 UI 中默认展示长篇玩法规则说明。 ## 3.2 api-server `server-rs/crates/api-server` 负责 Match3D 对外 HTTP facade: 1. 鉴权、请求上下文、错误 envelope。 2. 创作 Agent 的 LLM turn 编排。 3. 参考图片上传复用现有资产/OSS 能力。 4. 调用 `spacetime-client` 读写 Match3D 会话、作品和运行态。 5. 对前端返回稳定 HTTP DTO,不泄露 SpacetimeDB 内部表结构。 ## 3.3 SpacetimeDB `server-rs/crates/spacetime-module` 负责 Match3D 真相态: 1. 存储 Agent session / message。 2. 存储作品 profile。 3. 存储运行态 run snapshot。 4. 通过 procedure 同步返回会话、作品和运行态快照。 5. 在 reducer/procedure 内保持确定性,不做网络、文件系统或外部模型调用。 ## 3.4 纯领域 crate 新增: ```text server-rs/crates/module-match3d ``` 职责: 1. 创作配置校验。 2. 物品类型规划。 3. 初始布局生成输入/输出模型。 4. 2D 遮挡与可点击快照计算。 5. 点击确认。 6. 入槽与三消确认。 7. 胜负确认。 8. 成绩基础数据计算。 `module-match3d` 不直接依赖 Axum、不访问 OSS、不调用 LLM、不读写 SpacetimeDB 表。 --- ## 4. 共享契约 ## 4.1 TypeScript shared contracts 新增: ```text packages/shared/src/contracts/match3dAgent.ts packages/shared/src/contracts/match3dWorks.ts packages/shared/src/contracts/match3dRuntime.ts ``` ### `match3dAgent.ts` 承载: 1. `Match3DAgentSession` 2. `Match3DAgentMessage` 3. `Match3DCreatorConfig` 4. `Match3DCompileDraftRequest` 5. `Match3DCompileDraftResult` ### `match3dWorks.ts` 承载: 1. `Match3DWorkProfile` 2. `Match3DWorkSummary` 3. `Match3DWorkUpdateRequest` 4. `Match3DPublishRequest` 5. `Match3DPublishResult` ### `match3dRuntime.ts` 承载: 1. `Match3DRunSnapshot` 2. `Match3DItemSnapshot` 3. `Match3DTraySlot` 4. `Match3DStartRunRequest` 5. `Match3DClickItemRequest` 6. `Match3DClickItemResult` 7. `Match3DStopRunRequest` 8. `Match3DRestartRunRequest` ## 4.2 Rust shared contracts 新增: ```text server-rs/crates/shared-contracts/src/match3d_agent.rs server-rs/crates/shared-contracts/src/match3d_works.rs server-rs/crates/shared-contracts/src/match3d_runtime.rs ``` 并在 `server-rs/crates/shared-contracts/src/lib.rs` 导出。 Rust DTO 只承载 HTTP contract 和跨 crate 稳定模型,不直接暴露 `module-match3d` 内部结构。 ## 4.3 命名约束 1. 对外展示:抓大鹅。 2. 工程域:`match3d`。 3. TypeScript 类型前缀:`Match3D`。 4. Rust 类型前缀:`Match3D`。 5. HTTP path:`/api/creation/match3d/*` 与 `/api/runtime/match3d/*`。 6. SpacetimeDB 表与 procedure 前缀:`match3d_`。 --- ## 5. SpacetimeDB 表 首版保持最小闭环,复杂结构统一使用结构化字段 + `snapshot_json` / `draft_json`,避免过早拆出多张高耦合子表。 新增表属于安全 schema 演进;后续如果改字段,必须遵守 `SPACETIMEDB_SCHEMA_CHANGE_CONSTRAINTS.md`,不能直接删除、重排或改名已有列。表结构变更后必须同步对齐 `migration.rs`。 ## 5.1 `match3d_agent_session` 作用:保存 Match3D 创作 Agent 会话、配置草稿和发布指针。 字段: 1. `session_id: String`,主键。 2. `owner_user_id: String`,索引。 3. `seed_text: String`,用户初始输入或自动配置摘要。 4. `current_turn: u32`。 5. `progress_percent: u32`。 6. `stage: String`,建议值:`Collecting`、`ReadyToCompile`、`DraftCompiled`、`Published`。 7. `config_json: String`,序列化 `Match3DCreatorConfig`。 8. `draft_json: String`,序列化草稿结果。 9. `last_assistant_reply: String`。 10. `published_profile_id: String`,未发布为空字符串。 11. `created_at: Timestamp`。 12. `updated_at: Timestamp`。 ## 5.2 `match3d_agent_message` 作用:保存 Match3D 创作 Agent 消息流水。 字段: 1. `message_id: String`,主键。 2. `session_id: String`,索引。 3. `role: String`,建议值:`user`、`assistant`、`system`。 4. `kind: String`,建议值:`text`、`action`、`error`。 5. `text: String`。 6. `created_at: Timestamp`。 ## 5.3 `match3d_work_profile` 作用:保存 Match3D 作品主表和发布状态。 字段: 1. `profile_id: String`,主键。 2. `owner_user_id: String`,索引。 3. `source_session_id: String`。 4. `author_display_name: String`。 5. `game_name: String`。 6. `theme_text: String`。 7. `summary_text: String`。 8. `tags_json: String`。 9. `cover_image_src: String`。 10. `cover_asset_id: String`。 11. `clear_count: u32`。 12. `difficulty: u32`。 13. `config_json: String`。 14. `publication_status: String`,建议值:`Draft`、`Published`。 15. `play_count: u32`。 16. `updated_at: Timestamp`。 17. `published_at: Option`,未发布为 `None`。 ## 5.4 `match3d_runtime_run` 作用:保存 Match3D 单局运行态快照和成绩基础数据。 字段: 1. `run_id: String`,主键。 2. `owner_user_id: String`,索引。 3. `profile_id: String`,索引。 4. `status: String`,建议值:`Running`、`Won`、`Failed`、`Stopped`。 5. `snapshot_version: u32`。 6. `started_at_ms: i64`。 7. `duration_limit_ms: i64`,首版固定 `600000`。 8. `finished_at_ms: i64`,未结束为 `0`。 9. `elapsed_ms: i64`。 10. `clear_count: u32`。 11. `total_item_count: u32`。 12. `cleared_item_count: u32`。 13. `failure_reason: String`,建议值为空、`TimeUp`、`TrayFull`。 14. `snapshot_json: String`,序列化 `Match3DRunSnapshot`。 15. `created_at: Timestamp`。 16. `updated_at: Timestamp`。 ## 5.5 `match3d_play_record` 首版可选,若本轮不做排行榜,可先不建表,只在 `match3d_runtime_run` 保留成绩字段。 若实现成绩历史,字段建议: 1. `record_id: String`,主键。 2. `profile_id: String`,索引。 3. `owner_user_id: String`,索引。 4. `run_id: String`。 5. `status: String`。 6. `elapsed_ms: i64`。 7. `cleared_item_count: u32`。 8. `total_item_count: u32`。 9. `created_at: i64`。 --- ## 6. SpacetimeDB procedure 本轮全部使用 procedure 同步返回快照,避免 `api-server` 在写入后再读 private table。 ## 6.1 创作链 1. `create_match3d_agent_session(input)` 创建会话,写入初始配置或空配置,返回 session snapshot。 2. `get_match3d_agent_session(input)` 获取会话、消息和当前 draft。 3. `submit_match3d_agent_message(input)` 只写 user message,不调用 LLM,不生成 assistant 回复。 4. `finalize_match3d_agent_message_turn(input)` 由 `api-server` LLM turn 完成后写入 assistant message、配置状态、进度和 `last_assistant_reply`。 5. `compile_match3d_draft(input)` 校验题材、需要消除次数、难度,生成草稿和作品 draft profile。 ## 6.2 作品链 1. `update_match3d_work(input)` 更新游戏名称、标签、封面、题材、需要消除次数和难度。 2. `publish_match3d_work(input)` 校验基础信息完整后发布作品,不要求试玩通关。 3. `list_match3d_works(input)` 查询当前用户作品。 4. `get_match3d_work_detail(input)` 查询作品详情,支持结果页恢复和作品详情页。 5. `delete_match3d_work(input)` 可后置;若接入创作中心删除,需要与其他玩法卡片删除语义一致。 ## 6.3 运行态链 1. `start_match3d_run(input)` 基于作品配置生成单局快照,返回 `Match3DRunSnapshot`。 2. `get_match3d_run(input)` 返回当前权威运行态快照。 3. `click_match3d_item(input)` 根据 `run_id / item_instance_id / client_snapshot_version` 权威确认点击、入槽、三消、失败或胜利,返回新快照和确认结果。 4. `stop_match3d_run(input)` 把运行态标记为 `Stopped`,供试玩中止和返回结果页使用。 5. `restart_match3d_run(input)` 复用同一作品配置创建新 run,返回新快照。 6. `finish_match3d_time_up(input)` 可选。若倒计时由前端触发,前端在倒计时归零时调用该 procedure,后端确认 `TimeUp`。也可以由 `click_match3d_item` 或 `get_match3d_run` 懒确认超时。 ## 6.4 procedure 输入输出约束 1. 所有 mutation 输入必须带 `owner_user_id` 或由 `api-server` 注入用户上下文,SpacetimeDB 内部仍需以可信身份或 owner 字段校验归属。 2. 运行态 mutation 必须携带 `client_snapshot_version`。 3. 若版本不匹配,返回 `VersionConflict`,并携带最新快照。 4. procedure 返回字符串化 JSON 时,`spacetime-client` 必须负责反序列化和错误归一化。 --- ## 7. 运行态确认协议 Match3D 首版采用“前端即时反馈 + 后端权威确认”。 ## 7.1 点击流程 ```text 玩家点击物品 -> 前端基于最新快照做 2D 命中检测 -> 前端立即播放按压/选中/飞入表现 -> 前端调用 click_match3d_item -> 后端确认点击是否合法 -> 后端返回新快照与确认结果 -> 前端按确认结果固化或回滚表现 ``` ## 7.2 点击请求 ```ts interface Match3DClickItemRequest { runId: string; itemInstanceId: string; clientSnapshotVersion: number; clientEventId: string; clickedAtMs: number; } ``` 字段说明: 1. `clientSnapshotVersion` 用于发现前端基于旧快照操作。 2. `clientEventId` 用于前端去重和日志定位。 3. `clickedAtMs` 只用于观测,不作为成绩可信时间源。 ## 7.3 点击结果 ```ts type Match3DClickConfirmStatus = | 'Accepted' | 'RejectedNotClickable' | 'RejectedAlreadyMoved' | 'RejectedTrayFull' | 'VersionConflict' | 'RunFinished'; interface Match3DClickItemResult { status: Match3DClickConfirmStatus; run: Match3DRunSnapshot; acceptedItemInstanceId?: string; clearedItemInstanceIds: string[]; failureReason?: 'TimeUp' | 'TrayFull'; } ``` ## 7.4 前端回滚规则 1. `Accepted`:固化飞入、入槽、消除或胜负表现。 2. `RejectedNotClickable`:被点物品回到原位,备选栏恢复。 3. `RejectedAlreadyMoved`:直接应用后端最新快照。 4. `RejectedTrayFull`:应用后端失败快照。 5. `VersionConflict`:取消当前局部动画,应用最新快照,允许用户继续操作。 6. `RunFinished`:应用后端胜负快照,进入结算。 ## 7.5 快照版本 1. 每次后端接受会改变运行态的操作,`snapshot_version` 必须递增。 2. 前端所有即时反馈都基于某个明确版本。 3. 前端同时只能有一个未确认的点击操作;首版不做多点击并发队列。 4. 如果动画期间用户再次点击,前端应忽略或排队到当前确认完成后再处理;首版建议忽略。 --- ## 8. 运行态快照 ## 8.1 `Match3DRunSnapshot` ```ts interface Match3DRunSnapshot { runId: string; profileId: string; status: 'Running' | 'Won' | 'Failed' | 'Stopped'; snapshotVersion: number; startedAtMs: number; durationLimitMs: number; serverNowMs: number; remainingMs: number; clearCount: number; totalItemCount: number; clearedItemCount: number; traySlots: Match3DTraySlot[]; items: Match3DItemSnapshot[]; failureReason?: 'TimeUp' | 'TrayFull'; } ``` 说明: 1. `serverNowMs` 用于前端校准倒计时。 2. `remainingMs` 由后端按 `durationLimitMs` 和服务端时间计算。 3. 前端可以本地递减倒计时,但归零失败必须调用后端确认或等待下一次后端确认。 ## 8.2 `Match3DItemSnapshot` ```ts interface Match3DItemSnapshot { itemInstanceId: string; itemTypeId: string; visualKey: string; x: number; y: number; radius: number; layer: number; state: 'InBoard' | 'Flying' | 'InTray' | 'Cleared'; clickable: boolean; } ``` 说明: 1. `Flying` 可以作为前端表现态使用,不要求后端逐帧落库。 2. 后端主要确认 `InBoard -> InTray -> Cleared` 的权威状态变化。 3. `clickable` 是后端计算给前端的可点击快照,前端命中检测必须尊重它。 4. `x / y / radius` 统一使用 `0~1` 归一化舞台坐标。圆心为 `(0.5, 0.5)`,圆形可用半径为 `0.5`。 5. 后端生成物品时必须保证 `distance((x, y), (0.5, 0.5)) + radius <= 0.5 - safeMargin`。首版 `safeMargin` 用于覆盖圆形边框和阴影,避免物品被边界压住或裁切。 6. 前端渲染收到旧快照或异常坐标时,可以只做显示层兜底收束,但不得把兜底后的表现坐标写回为规则真相。 ## 8.3 `Match3DTraySlot` ```ts interface Match3DTraySlot { slotIndex: number; itemInstanceId?: string; itemTypeId?: string; visualKey?: string; } ``` ## 8.4 2D 遮挡口径 首版不做真实物理遮挡。 建议后端按以下输入计算 `clickable`: 1. 物品圆形或近似圆形碰撞范围。 2. `layer` 越大越靠上。 3. 被更高层物品覆盖到低于可点击阈值时,标记为不可点击。 4. 阈值首版作为领域常量,后续体验后再参数化。 前端基于 `clickable` 和自身命中检测呈现即时反馈;后端仍在点击确认时再次校验。 --- ## 9. 领域规则冻结 ## 9.1 创作配置 ```ts interface Match3DCreatorConfig { themeText: string; referenceImageSrc?: string; clearCount: number; difficulty: number; } ``` 规则: 1. `themeText` 必填。 2. `clearCount` 必须为正整数。 3. `difficulty` 范围 `1~10`。 4. `referenceImageSrc` 首版只支持图片,不支持视频。 ## 9.2 物品数量 ```text totalItemCount = clearCount * 3 ``` 每种 `itemTypeId` 的数量必须是 `3` 的倍数。 消除物类型数按创作输入的 `clearCount` 计算: ```text itemTypeCount = clearCount <= 25 ? clearCount : 25 ``` 当 `clearCount <= 25` 时,运行态快照中的不同 `itemTypeId` 数量必须等于 `clearCount`;当 `clearCount > 25` 时,不同 `itemTypeId` 数量必须等于 `25`。超过 `25` 组的消除目标按这 `25` 种类型轮转生成,确保每种类型的最终数量仍是 `3` 的倍数。 这 `25` 组在同一局内还必须对应 25 套不同的形状和颜色签名,不能有两组视觉上撞型。 ## 9.3 demo 视觉素材 首版使用 25 个内置积木件视觉键和前端内置几何图形资产,不接真实图片生成。 1. 当前 demo 使用 25 个积木件视觉键作为默认素材池;前端首版将其映射为无文字的 2D 图标和程序化 3D 积木模型,不渲染写实图,也不能显示为带文字或透明气泡的小球。 2. `visualKey` 不允许在前端统一兜底为同一个素材;未知 key 至少要有稳定的颜色差异,避免多个不同 `itemTypeId` 被玩家误认为同一种物品。 3. 运行态图案必须使用实心、高饱和、无文字的几何 SVG,并保持与 3D 模型同一批 `visualKey` 对应关系;外层命中按钮不得再显示半透明气泡底。 4. 每局按使用类型数量分配五档相对体积:XL 型 `1.60~2.30` 占 `20%`,L 型 `1.25~1.60` 占 `30%`,M 型固定 `1.00` 占 `30%`,XS 型 `0.65~0.85` 占 `15%`,S 型 `0.35~0.50` 占 `5%`。非整数配额按最大余数补齐,总数必须等于本局使用类型数量。 5. 同一局内同一个颜色和造型的 `visualKey` 只能对应一个尺寸档位和一个半径,不能出现同一物品类型三件副本大小不同,也不能出现同一视觉键在复用时被分配到两种大小。前端不得自行改写规则半径,只负责按快照表现。 6. 后续接入真实题材图片素材前,必须另补资产生成方案。 ## 9.4 难度 首版 `difficulty` 只作为布局和生成算法参数。 后端需要保留参数入口,但难度公式先保持简洁: 1. 难度越高,物品尺寸可整体略小。 2. 难度越高,堆叠层级可略深。 3. 难度越高,首屏可直接三消的可见组合可略少。 4. 同一局内允许有轻微尺寸差异,但每个物品仍必须完整落在圆形空间内。 具体数值不在 A0 冻死,由 B1 领域 crate 分支给出首版常量并通过测试覆盖。 --- ## 10. api-server HTTP facade ## 10.1 创作链 ```text POST /api/creation/match3d/sessions GET /api/creation/match3d/sessions/:sessionId POST /api/creation/match3d/sessions/:sessionId/messages POST /api/creation/match3d/sessions/:sessionId/messages/stream POST /api/creation/match3d/sessions/:sessionId/compile ``` 说明: 1. 同步消息接口用于普通提交。 2. 流式接口复用现有 Agent SSE 基建。 3. `messages` 只写 user message,LLM 推理由 `api-server` 完成后 finalize 到 SpacetimeDB。 4. `compile` 不生成额外素材,只生成 Match3D 草稿和作品 draft。 ## 10.2 作品链 ```text PATCH /api/creation/match3d/works/:profileId POST /api/creation/match3d/works/:profileId/publish GET /api/creation/match3d/works GET /api/creation/match3d/works/:profileId ``` 首版发布不要求试玩通关。 ## 10.3 运行态链 ```text POST /api/runtime/match3d/works/:profileId/runs GET /api/runtime/match3d/runs/:runId POST /api/runtime/match3d/runs/:runId/click POST /api/runtime/match3d/runs/:runId/stop POST /api/runtime/match3d/runs/:runId/restart POST /api/runtime/match3d/runs/:runId/time-up ``` `time-up` 可后置;若不单独实现,`get` 或下一次 `click` 必须能懒确认超时失败。 ## 10.4 错误语义 HTTP 层使用现有 API envelope。 建议错误码: 1. `MATCH3D_SESSION_NOT_FOUND` 2. `MATCH3D_WORK_NOT_FOUND` 3. `MATCH3D_RUN_NOT_FOUND` 4. `MATCH3D_INVALID_CONFIG` 5. `MATCH3D_PUBLISH_BLOCKED` 6. `MATCH3D_RUN_VERSION_CONFLICT` 7. `MATCH3D_RUN_ALREADY_FINISHED` --- ## 11. 前端落点 ## 11.1 contracts 与 service 新增: ```text src/services/match3d-creation/ src/services/match3d-works/ src/services/match3d-runtime/ ``` 分别负责 Agent/草稿、作品/发布、运行态请求。 ## 11.2 组件 新增: ```text src/components/match3d-creation/ src/components/match3d-result/ src/components/match3d-runtime/ ``` ## 11.3 平台入口 需要接入: 1. `src/components/platform-entry/platformEntryCreationTypes.ts` 2. `src/components/platform-entry/PlatformEntryCreationTypeModal.tsx` 3. `src/components/platform-entry/usePlatformCreationAgentFlowController.ts` 入口展示: 1. 名称:`抓大鹅` 2. 子标题:`经典消除玩法` ## 11.4 运行态 UI 首版运行态必须移动端优先: 1. 圆形空间占据主要区域。 2. 备选栏固定 `7` 格。 3. 3D 模式下,备选栏格子使用与圆形空间内一致的程序化 3D 模型预览,固定斜 `45` 度视角,且不接入场内物理碰撞;托盘预览必须共享一个 WebGL renderer,按实际容器宽高更新正交相机,并以独立 pivot 居中每个模型后定位到对应格子;不能每格创建独立 renderer;仅 WebGL 回退或 `2D` 模式使用 2D 图标。 4. 倒计时清晰但不遮挡物品。 5. 物品点击区域稳定,不因动画造成布局跳动。 6. 胜利/失败结算使用独立面板,不在当前面板下方展开。 ## 11.5 本地 mock 口径 F3 运行态即时反馈分支可以先用本地 mock snapshot 开发,但必须满足: 1. mock 类型来自 `packages/shared/src/contracts/match3dRuntime.ts`。 2. mock 字段不得脱离 A0 文档。 3. 接入真实 API 时删除或降级为测试 fixture。 --- ## 12. 并行开发包 ## 12.1 第二波并行 ### B1 + B2:领域 crate 与 shared contracts 写入范围: 1. `server-rs/crates/module-match3d/` 2. `server-rs/Cargo.toml` 3. `server-rs/crates/shared-contracts/src/match3d_*.rs` 4. `packages/shared/src/contracts/match3d*.ts` 交付: 1. 领域规则单测。 2. DTO 编译通过。 3. 不接 SpacetimeDB。 ### B3:SpacetimeDB 表与 procedure 写入范围: 1. `server-rs/crates/spacetime-module/src/match3d/` 2. `server-rs/crates/spacetime-module/src/lib.rs` 3. `server-rs/crates/spacetime-module/src/migration.rs` 4. 生成后的 bindings 由后续 B4 处理。 交付: 1. 表和 procedure 定义。 2. 与 `module-match3d` 规则接线。 3. `spacetime build` 或仓库现有等价脚本通过。 B3 当前落地状态: 1. `server-rs/crates/spacetime-module/src/match3d/` 已承载 Match3D 的表、procedure 输入输出类型和 procedure 实现,并由 `server-rs/crates/spacetime-module/src/lib.rs` 挂载导出。 2. `migration.rs` 已纳入 `match3d_agent_session`、`match3d_agent_message`、`match3d_work_profile`、`match3d_runtime_run` 四张表,后续字段变更继续按 `SPACETIMEDB_SCHEMA_CHANGE_CONSTRAINTS.md` 追加兼容字段。 3. 运行态 `start_match3d_run`、`click_match3d_item`、`stop_match3d_run`、`finish_match3d_time_up` 通过适配层调用 `module-match3d` 的领域规则,SpacetimeDB 层只负责归属校验、事务写入、权威快照持久化和 procedure JSON 返回。 4. B3 对外仍返回当前首版快照字段 `snapshotVersion / clientSnapshotVersion` 对应语义;`module-match3d` 内部的 `board_version` 只在适配层中转换,避免影响并行中的 B4/F3 接入。 5. SpacetimeDB module 的有效验收命令是 `spacetime build --module-path crates/spacetime-module`;不要用普通 native `cargo test -p spacetime-module` 作为验收口径,因为该 crate 会链接 SpacetimeDB 宿主符号。 ### F1:创作入口与 Agent UI 写入范围: 1. `src/components/platform-entry/` 2. `src/components/match3d-creation/` 3. `src/services/match3d-creation/` 交付: 1. 平台入口可见。 2. Agent 工作区能收集题材、需要消除次数和难度。 3. 可用 mock client,等待 B5 接口。 ### F3:运行态即时反馈 UI 写入范围: 1. `src/components/match3d-runtime/` 2. `src/services/match3d-runtime/` 交付: 1. 圆形空间、2D 物品、`7` 格备选栏。 2. 点击命中、飞入、入槽、三消、腾格、胜负过渡。 3. 后端确认失败时的回滚和快照校正逻辑。 4. 先用 mock snapshot。 ## 12.2 第三波并行 ### B4 + B5:spacetime-client 与 api-server facade 写入范围: 1. `server-rs/crates/spacetime-client/src/match3d.rs` 2. `server-rs/crates/spacetime-client/src/lib.rs` 3. `server-rs/crates/api-server/src/match3d.rs` 4. `server-rs/crates/api-server/src/app.rs` 5. `server-rs/crates/api-server/src/main.rs` 如需注册模块 交付: 1. HTTP facade 可调用 SpacetimeDB procedure。 2. 创作、作品、运行态接口返回 shared-contract DTO。 3. 后端定向测试通过。 ### F2:结果页与发布 写入范围: 1. `src/components/match3d-result/` 2. `src/services/match3d-works/` 3. 创作中心作品恢复相关最小接线。 交付: 1. 编辑游戏名称、标签、封面图。 2. 试玩入口。 3. 发布入口。 ### F4:平台分发最小接入 写入范围: 1. 创作中心作品货架。 2. 首页/分类/广场卡片映射。 3. 作品详情启动运行态入口。 交付: 1. 已发布 Match3D 作品可进入平台列表。 2. 卡片可进入详情或运行态。 ## 12.3 最后集成 ### Q1:集成验收 交付: 1. 创作到发布到试玩主链通过。 2. 运行态点击、入槽、三消、失败、胜利通过。 3. 移动端视口检查通过。 4. `npm run api-server` 通过。 5. 对应测试与 `npm run check:encoding` 通过。 --- ## 13. 合并顺序 建议合并顺序: 1. A0:本文档。 2. B1 + B2:领域 crate 与 shared contracts。 3. B3:SpacetimeDB 表和 procedure。 4. B4 + B5:spacetime-client 与 api-server facade。 5. F1 / F2 / F3:前端创作、结果页、运行态。 6. F4:平台分发。 7. Q1:集成收口。 如果 F1/F3 先完成,应只以 mock client 保持可编译,不直接修改后端合同。 --- ## 14. 验收命令 后续编码分支按改动范围执行。 文档分支: ```powershell npm run check:encoding -- docs/technical/MATCH3D_CREATION_AND_RUNTIME_MINIMAL_IMPLEMENTATION_2026-04-30.md docs/technical/README.md ``` 后端分支: ```powershell cargo test -p module-match3d cargo test -p shared-contracts npm run api-server npm run check:encoding ``` SpacetimeDB 分支按仓库现有发布脚本执行,并在需要生成绑定时使用 `spacetime generate` 或仓库封装脚本。不得手写生成文件。 前端分支: ```powershell npm run check:encoding npm run typecheck ``` 若新增定向测试,应补跑对应 `vitest`。 --- ## 15. 一句话结论 Match3D 首版按独立玩法域落地:前端负责所有局内即时反馈以保证手感,后端通过 SpacetimeDB procedure 权威确认规则和成绩,api-server 只暴露稳定 HTTP facade,后续并行分支必须围绕本文冻结的 DTO、表、procedure 和路由推进。