diff --git a/docs/prd/【AI游戏创作】项目开发工作台PRD-2026-07-20.md b/docs/prd/【AI游戏创作】项目开发工作台PRD-2026-07-20.md index 9e38ea713..79c93f2a9 100644 --- a/docs/prd/【AI游戏创作】项目开发工作台PRD-2026-07-20.md +++ b/docs/prd/【AI游戏创作】项目开发工作台PRD-2026-07-20.md @@ -1,6 +1,6 @@ # AI 游戏创作项目开发工作台 PRD -更新时间:`2026-09-21`(2026-09-20 音频生成并入图片类那份后台任务账本、派生/修改类任务并入同一「生成任务」侧栏,2026-09-21 卡片浮层改为「提交即关」、**「生成任务」侧栏从画布左侧贴边改为画布右上角锚点(开关常驻)**、**资源卡可拖到对话栏批量 @ 引用**、**替换面板改为非模态浮层并支持在画布上点选目标**(验收现场两条修正:任务锚点改挂画布那一格、展开后开关让位),见 §3.10 / §5.3 / §7.8 / §7.9 与 [`【功能说明】AGC聊天素材引用`](../【功能说明】AGC聊天素材引用-2026-09-08.md);2026-09-14 图片类生成后台化:入口 IPC 为 `start_local_project_asset_generation` + 项目内任务账本 + 本地排队 + 非模态「生成任务」面板;2026-09-13 新增的功能画布底部工具栏入口矩阵 §3.10 / §7.9,以及右侧 Supervisor 对话气泡、可访问对比度与过程卡布局收口,资源卡预览、分区布局、非破坏性资源编辑、资源替换与 Godot 双根合同保持不变;2026-09-21 Godot 工作区发现放宽:一层多命中按目录名排序取第一个,`project.godot` 允许是链接/reparse point/硬链接,见 §3.8) +更新时间:`2026-10-04`(2026-10-04 运行视窗「点选素材」补上 Phaser 4 / three.js 画面上的已登记素材识别与退化口径,见 §3.4;2026-09-20 音频生成并入图片类那份后台任务账本、派生/修改类任务并入同一「生成任务」侧栏,2026-09-21 卡片浮层改为「提交即关」、**「生成任务」侧栏从画布左侧贴边改为画布右上角锚点(开关常驻)**、**资源卡可拖到对话栏批量 @ 引用**、**替换面板改为非模态浮层并支持在画布上点选目标**(验收现场两条修正:任务锚点改挂画布那一格、展开后开关让位),见 §3.10 / §5.3 / §7.8 / §7.9 与 [`【功能说明】AGC聊天素材引用`](../【功能说明】AGC聊天素材引用-2026-09-08.md);2026-09-14 图片类生成后台化:入口 IPC 为 `start_local_project_asset_generation` + 项目内任务账本 + 本地排队 + 非模态「生成任务」面板;2026-09-13 新增的功能画布底部工具栏入口矩阵 §3.10 / §7.9,以及右侧 Supervisor 对话气泡、可访问对比度与过程卡布局收口,资源卡预览、分区布局、非破坏性资源编辑、资源替换与 Godot 双根合同保持不变;2026-09-21 Godot 工作区发现放宽:一层多命中按目录名排序取第一个,`project.godot` 允许是链接/reparse point/硬链接,见 §3.8) ## 1. 产品定位 @@ -76,6 +76,7 @@ - 运行视窗必须占满中央工作区为游戏保留的可用区域。loopback 预览页通过客户端本地 preview server 注入的只读尺寸桥上报文档实际宽高;宿主只接受当前 iframe、当前 loopback origin 的固定版本消息,并将完整游戏文档等比缩放、居中放入视窗。iframe 首次适配后发生的真实内容增高或缩短仍必须被接受;仅浏览上下文宽高回灌或内容宽高未变化时保持当前状态,不触发重复渲染。 - 窗口或中央区域尺寸变化后必须重新测量和适配;内容已经放得下时保持 `1:1`,不得无故放大。游戏文档宽高超过视窗时缩小整体画面,不显示 iframe 横向或纵向滚动条,也不得用单纯裁切替代完整展示。尺寸桥以根布局 `ResizeObserver` 为主,并在页面可见时每 `500ms` 至多探测 `512` 个元素作为绝对定位溢出的低频兜底;探测截断时不得用部分样本下调尺寸,viewport 耦合的 `100vh / 100% / bottom / right` 布局也不得形成自反馈。相同测量结果去重,不监听整页属性、文本或子节点突变;桥不读取项目正文、不修改 manifest、游戏文件或运行业务状态。桥脚本只能注入到真实 HTML 标签上下文,不能把脚本、样式、模板或注释中的 `` / `` 文本误判为结束标签;省略结束标签的 UTF-8 HTML 仍需安全注入。 - 运行视窗右下角提供“全屏预览”:只把游戏画面那一格送进全屏,顶部页签、右侧对话和底部信息栏不跟着放大;再次点击该入口、按 `Esc` 或由宿主退出全屏都回到原布局。宿主没有 Fullscreen API 时整枚入口不渲染,不留点了没反应的按钮。 +- 运行视窗提供“点选素材”:把画面上点中的内容落成一条 `runtime-region` 引用插入对话,只影响这一次引用——不改资源选中、不改信息栏判据、不写 manifest 或版本、不重载预览,也不代表“该素材正在被这个位置使用”。预览页是 Phaser 4 或 three.js 玩法时,点中由**已登记素材**渲染的精灵、图集帧、贴图网格或模型,引用必须带该素材的稳定 id,显示名与其它引用入口一致;玩法没有发布引擎句柄、对象既没有标注也取不到贴图地址、或画面是程序化绘制时,退化为不带素材的区域引用——不报错、不伪造 id、引用照常能插入能发送。 - 运行视窗下方的信息栏只在**有真实内容**时存在(当前判据是**资源选中态**:在资源画布或浮层资源面板里选中一张资源后切到运行页签仍保留,信息栏渲染它的只读字段;运行画面上的“点选素材”只往对话插入引用,不改选中):没有内容时整栏不渲染,有内容时自动展开并可手动收起到只剩一行开合按钮;不显示示例字段、默认数值、未载入控件或功能说明。暂时没有数据源的区域(「数值微调」的登记表)不渲染区域标题与卡片,等编辑态登记表接进来后与内容一起出现。Agent 对话标题栏不显示头像图标,“与陶泥儿的对话”及副标题按标题栏左侧对齐,钱包和审批入口继续位于右侧。 - 数值修改立即写入当前项目的编辑态配置。 diff --git a/docs/project-memory/plans/【实施计划】AGC运行画面点选引擎适配-2026-10-04.md b/docs/project-memory/plans/【实施计划】AGC运行画面点选引擎适配-2026-10-04.md new file mode 100644 index 000000000..fce5be70a --- /dev/null +++ b/docs/project-memory/plans/【实施计划】AGC运行画面点选引擎适配-2026-10-04.md @@ -0,0 +1,63 @@ +# 【实施计划】AGC 运行画面点选识别 Phaser 4 与 three.js 画面上的已登记素材 + +| 字段 | 值 | +| --------- | ----------------------------------------------------------------------- | +| Milestone | `docs/project-memory/plans/【里程碑】AGC运行画面点选引擎适配-2026-10-04.md` | +| Status | in-progress | +| Owner | omp agent(issue #612) | + +## 修改边界 + +允许修改: + +- `apps/ai-game-creator-shell/src-tauri/resources/preview/local-preview-fit.js`(新增):现有预览桥脚本(尺寸上报 + DOM 点选)整体迁入,并新增 canvas 分支与两个引擎适配器。 +- `apps/ai-game-creator-shell/src-tauri/src/preview.rs`:`PREVIEW_FIT_BRIDGE_SCRIPT` 改为 `include_str!` 引用上面的文件;注入、去重扫描、`/__genarrative/local-preview-fit.js` 路由与响应逻辑不变。 +- `apps/ai-game-creator-shell/src/features/project-workspace/runtimeInspectResourceMatch.ts`(新增):把宿主侧「点选结果 → manifest 素材 id」的匹配抽成纯函数。 +- `apps/ai-game-creator-shell/src/view/project-development/index.tsx`:`handleRuntimeInspectSelection` 改为调用该纯函数,派发载荷结构不变。 +- `apps/ai-game-creator-shell/tests/runtimeInspectEngines.test.ts`、`apps/ai-game-creator-shell/tests/runtimeInspectResourceMatch.test.ts`(新增)。 +- `apps/ai-game-creator-shell/src-tauri/src/main.rs`:`DEFAULT_GAME_SCRIPT_JS` 补引擎句柄发布。 +- `apps/ai-game-creator-shell/template-library/v1/phaser-2d-starter/project/game/game.js`、`.../threejs-3d-starter/project/game/main.js`:补引擎句柄发布(只改本地模板源,不重新发布 zip)。 +- 文档收口:`docs/【功能说明】AGC聊天素材引用-2026-09-08.md`(「当前已完成」清单与本里程碑证据表)、`docs/prd/【AI游戏创作】项目开发工作台PRD-2026-07-20.md` §3.4(如行为与草案有出入)。 + +明确不修改: + +- `runtime-region` 引用契约、`genarrative.local-preview-inspect.v1` 消息版本号、`LocalGamePreviewFrame.tsx` 的解析与净化、Rust `direct_codex_user_item` 的校验口径(不新增字段;若实测必须加字段,单独评审)。 +- `packages/shared`、manifest / 版本绑定 / 素材替换链路、AGC 玩法 Skill 与 Runtime Prompt、模板 zip 发布与线上索引。 +- DOM 点选语义与 `enabled / disabled / cancelled` 协议。 + +## 实现顺序 + +1. **搬运桥脚本(行为零变化)**:把 `PREVIEW_FIT_BRIDGE_SCRIPT` 的字符串体原样落到 `resources/preview/local-preview-fit.js`,`preview.rs` 改 `include_str!`。跑 Rust 定向测试 + 一次真机 DOM 点选,确认尺寸上报与 DOM 点选完全不变。 +2. **拆出命中解析**:桥内把 `handleInspectMove` / `handleInspectClick` 共同的部分抽成 `resolveInspectTarget(clientX, clientY)`,返回 `{ selection, rect }`;DOM 分支逻辑等价搬运。 +3. **引擎句柄契约**:桥惰性读取 `window.__GENARRATIVE_PREVIEW_GAME__ = { engine: 'phaser', game }` 或 `{ engine: 'three', THREE, scene, camera, renderer }`(`THREE` 命名空间要求见下「风险」第 2 条);只认显式句柄,不做鸭子类型猜引擎。缺句柄或 `engine` 未知 → 走第 6 步退化。 +4. **Phaser 4 适配**:`game.input.activePointer` 取指针 → `scene.input.hitTestPointer(pointer)` 优先;无命中对当前激活场景的 `scene.children.list` 逆序(含 `depth`)用 `getBounds()` 与指针世界坐标求交兜底。素材身份:`getData('genarrativeResourceId' | 'genarrativeResourcePath')` 优先,其次 `texture.getSourceImage()` / `texture.source[].image` 的 `currentSrc || src` 与 `texture.key` + `frame.name`。矩形:`getBounds()` 世界矩形按相机换算屏幕矩形。多场景只取激活场景;全程 try/catch,任何一步抛错按"未命中"处理。 +5. **three.js 适配**:`renderer.domElement` 矩形归一化出 NDC → `new THREE.Raycaster()` + `setFromCamera` → `intersectObjects(scene.children, true)` 取最近命中。素材身份:`object.userData.genarrativeResourceId | genarrativeResourcePath` 优先,其次沿 `object.material` 的贴图槽取 `texture.image.currentSrc || texture.source.data.currentSrc`。矩形:命中对象 `Box3` 八角投影取 min/max。 +6. **退化路径**:以上任一步拿不到结果时,按现状输出(`label` = 元素/画面可得的名字,`sourcePath` / `resourceIds` 为空,矩形 = 现状 DOM 语义),不报错、不伪造 id。 +7. **宿主匹配抽纯函数**:`runtimeInspectResourceMatch.ts` 实现优先级——显式 `resourceIds`(已按 manifest 过滤)→ `sourcePath` 与 `localPath` 的精确后缀匹配 → 文件名匹配(现有口径);序列帧 `imageSequenceFrames[].imageSrc` 参与后两档;结果去重且只保留 manifest 现有素材 id。`index.tsx` 改为调用它。 +8. **脚手架与模板句柄**:`main.rs` 默认脚本与两个模板源补发布句柄(Phaser 在 `new Phaser.Game(...)` 处持有实例;three.js 在场景装配后发布)。 +9. **真机与文档收口**:两条 smoke(见下),补「当前已完成」清单与证据表。 + +## 验证命令 + +1. `cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --offline -- preview` +2. `npx vitest run apps/ai-game-creator-shell/tests/runtimeInspectEngines.test.ts apps/ai-game-creator-shell/tests/runtimeInspectResourceMatch.test.ts apps/ai-game-creator-shell/tests/resourceReferenceInput.test.tsx` +3. `npm run agc:typecheck`(含 `check:tests:types`、`tsc`、skill-pack 指纹、包布局声明、`check-config`) +4. `npm run check:encoding`、`npm run check:doc-index`、`git diff --check` +5. 真机:`npm run agc` 拉起客户端 → 新建 Phaser 4 项目(默认脚手架)与 three.js 项目各点一次已登记素材,核对引用芯片名与载荷 `resourceIds`,并各点一次空白与 DOM HUD 确认退化与不回归。 + +## 风险与回滚点 + +1. **桥脚本迁移**(顺序 1):纯搬运,但桥同时承载尺寸上报(`resolveLocalGamePreviewFitLayout` 依赖它),任何字符差异都可能表现为画面适配回归。回滚点:该步单独一次提交,红了就 revert 该提交再重做。 +2. **three.js 需要 `THREE` 命名空间**:Raycaster / Vector2 / Box3 都是模块内类,桥拿不到;从 `camera.constructor` 只能拿到相机类,因此句柄契约要求同时暴露 `THREE`。若实测希望避免暴露命名空间,退路是要求玩法暴露少量构造器(`Raycaster`)——需要改契约,先评审再动手。 +3. **Phaser 4 相机换算**:世界↔屏幕矩形依赖 4.2.1 的相机字段与缩放行为;实测不稳定时降级为"命中对象但只给点标记矩形",不阻塞引用插入(主规范第 5 条的退化分支)。 +4. **`hitTestPointer` 只覆盖 `setInteractive()` 对象**:几何兜底必须存在,否则未开交互的精灵点不中。 +5. **three.js 递归 raycast 成本**:只在点选模式下按需执行(move 节流),不做常驻监听。 +6. **three.js 真机验收的模板来源**:本里程碑只改本地模板源,不重新发布 `template.zip`;three.js smoke 用模板工程 + 手工补一行句柄进行(句柄就是对外契约),正式"开箱可用"由下一个里程碑的模板发布覆盖。这条限制必须写进交付记录。 +7. **净化为不可绕过**:引擎档取到的 id / 路径先过既有 `sanitizeInspectResourceId` / `sanitizeInspectSourcePath` 再进载荷;宿主匹配只保留 manifest 现有 id,未知值一律丢弃(Rust 拒绝口径不变)。 + +## 已完成 + +- 桥脚本搬运 + 引擎档落地:桥脚本落到 `resources/preview/local-preview-fit.js`,`preview.rs` 改 `include_str!`,DOM 点选语义与协议不变,新增 canvas 引擎档。 +- 宿主匹配抽成纯函数 `runtimeInspectResourceMatch.ts`,`index.tsx` 改为调用它,派发载荷结构不变。 +- 脚手架与三个起步模板发布只读引擎句柄:`DEFAULT_GAME_SCRIPT_JS`、`phaser-2d-starter`、`threejs-3d-starter`、`blank-3d-scene`。 +- 自动化验证通过:五个前端用例文件(`runtimeInspectEngines` / `runtimeInspectResourceMatch` / `localGamePreviewFrame` / `resourceReferenceInput` / `appSurface`)292 passed / 9 skipped(301 项);`npm run agc:typecheck` 通过;`cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --offline -- preview` 通过(43 passed)。 diff --git a/docs/project-memory/plans/【里程碑】AGC运行画面点选引擎适配-2026-10-04.md b/docs/project-memory/plans/【里程碑】AGC运行画面点选引擎适配-2026-10-04.md new file mode 100644 index 000000000..02f7d4472 --- /dev/null +++ b/docs/project-memory/plans/【里程碑】AGC运行画面点选引擎适配-2026-10-04.md @@ -0,0 +1,53 @@ +# 【里程碑】AGC 运行画面点选识别 Phaser 4 与 three.js 画面上的已登记素材 + +| 字段 | 值 | +| ----------- | -------------------------------------------------------- | +| Version | 1.0 | +| Status | proposed | +| Date | 2026-10-04 | +| Parent Spec | `docs/【功能说明】AGC聊天素材引用-2026-09-08.md`「运行画面素材点选」、`docs/prd/【AI游戏创作】项目开发工作台PRD-2026-07-20.md` §3.4 | + +## 目标 + +- 运行画面点选在 Phaser 4 与 three.js 玩法上,能识别点中对象用的是哪一张已登记素材,并让引用载荷带上该素材的稳定 id。 +- 识别不出来时不伪造、不报错,按主规范退化为不带素材的区域引用。 +- HTML 区域点选语义、预览消息协议、引用发送链路与 Rust 校验口径逐字不变。 +- 新建 Phaser 4 项目与 three.js 起步工程开箱即具备点选所需的引擎句柄。 + +## 范围 + +- 运行画面点选的引擎档识别:命中对象解析、素材身份来源与优先级、命中矩形高亮。 +- 宿主侧把识别结果映射成 manifest 素材 id(含"精确优先于文件名"的口径)。 +- 起步工程与新建项目默认脚手架的引擎句柄发布。 +- 上述行为的自动化证据与真机 smoke 证据。 + +## 不在范围内 + +- 生成期契约落位:把句柄发布与对象素材标注写进 AGC 玩法 Skill / Runtime Prompt,并重新发布模板产物(`template.zip` 与线上索引)——另立里程碑。 +- 运行期资源使用关系持久化(不记录"某素材在某位置被用过",不注入代码、不写侧车)。 +- Cocos Creator / Godot / Unity 的点选;纯 2D canvas 引擎与 Babylon.js。 +- `runtime-region` 引用契约、预览消息版本号、Rust `resourceIds` 校验、资源选中与信息栏判据的任何变化。 +- 旧项目自动获得能力(不写迁移、不做兼容分支;限制如实写进能力说明)。 + +## 依赖与前置条件 + +- 主规范(`docs/【功能说明】AGC聊天素材引用-2026-09-08.md`)与本节里程碑评审通过。 +- 可拉起的 AGC 真机客户端(`npm run agc`,端口与栈规约按 `genarrative-dev-stack-port-routing`),以及一份可复现的 Phaser 4 / three.js 起步工程。 +- 一张已登记到 manifest 的项目素材(图片;three.js 侧另需一张贴图)。 +- 不依赖后端服务、Provider 或登录态。 + +## 验收标准 + +- [ ] Phaser 4 起步工程:点中由已登记素材渲染的精灵 / 图集帧,引用芯片显示该素材名,载荷 `resourceIds` 命中该素材 id。 +- [ ] three.js 起步工程:点中贴了已登记贴图的 Mesh(含 GLB 内嵌纹理的模型走显式标注路径),结果同上。 +- [ ] 同一对象同时存在显式素材标注与贴图地址推断时,取显式标注。 +- [ ] 无引擎句柄 / 点中空白 / 程序化绘制三种情况:退化为不带素材的区域引用,零报错、零伪造 id,引用可插入可发送。 +- [ ] 命中对象时高亮为该对象在画面上的区域;取不到对象矩形时高亮范围与 DOM 档一致。 +- [ ] DOM 点选(HTML HUD、媒体 `src`、资源标识属性)行为与现有用例逐字不变。 +- [ ] 起步工程与新建项目默认脚手架发布引擎句柄;新建 Phaser 4 项目不额外改代码即可点选。 + +## 证据要求 + +- 自动化:引擎档识别的 JS 单元用例(jsdom 中加载真实桥脚本 + 假引擎对象)、宿主素材映射纯函数用例、桥注入与协议回归用例、`npm run agc:typecheck`。 +- 运行时:Phaser 4 与 three.js 各一条真机点选 smoke(截图或录制,含引用芯片与载荷证据)。 +- 边界:三种退化情况各一条、净化与数量上限不回归、`resourceIds` 只取 manifest 现有素材。 diff --git a/docs/project-memory/shared-memory/pitfalls.md b/docs/project-memory/shared-memory/pitfalls.md index 20a8f87ba..2075bcd2b 100644 --- a/docs/project-memory/shared-memory/pitfalls.md +++ b/docs/project-memory/shared-memory/pitfalls.md @@ -2,6 +2,18 @@ 这里只记录对当前开发仍有用的症状、根因、排查方法和风险边界。同一事实保留一个当前口径;退役对象的专属过程与单轮测试结果由 Git 历史追溯。遇到旧路径或版本时,以现行代码和专题文档为准。 +## 2026-10-04 Phaser 4 `hitTestPointer` 的返回顺序不是叠放顺序 + +- **现象**:运行画面点选 Phaser 4 画面时,按「数组第一个 / 最后一个」当最上层会点错对象——点的是上层精灵,引用却落到下层的素材上;对象越多越容易错。 +- **原因**:`hitTestPointer` 返回的是输入对象的注册 / 内部列表顺序,与真实叠放无关;叠放由命中相机 `renderList` 的索引决定(含 depth 与入序)。 +- **结论(现行口径)**:点选命中要按 `pointer.camera.renderList` 的索引取最上层;几何兜底也必须按 depth + 入序排序,不能沿用注册顺序取值。 + +## 2026-10-04 Phaser 4 默认 XHR 装载下贴图元素是 blob 地址 + +- **现象**:运行画面点选拿不到原始素材路径——贴图元素上的地址是会话内的 blob 地址,按文件名反推素材会得到无意义的临时名。 +- **原因**:Phaser 4 默认用 XHR 装载图片,地址只在当前会话内有效,不携带仓库 / manifest 里的路径信息。 +- **结论(现行口径)**:Phaser 4 项目的素材身份必须靠玩法显式标注(`setData`)发布,不要试图从 blob 地址反推文件名;没有标注就退化为不带素材的区域引用。与主规范「运行画面素材点选(2026-10-04)」的边界一致。 + ## 2026-10-03 AGC 画布「引用」死按钮:window 事件的消费者挂在一个只在另一条链路赋值的 ref 上 - **现象**(Issue 602):AGC 资源画布选中一张已登记素材,选中工具条点「引用」(图标 `@`、可见文案与 `title` 都是「引用」)没有任何反应——聊天输入框里不出现 `@素材名` 芯片,也没有任何提示。普通项目(`directProjectMode`)必现,立项策划项目(`planningStartMode`)复现不出来;把素材卡拖到对话栏的批量引用同样没反应。 diff --git a/docs/【功能说明】AGC聊天素材引用-2026-09-08.md b/docs/【功能说明】AGC聊天素材引用-2026-09-08.md index 6718d6e2c..a654238bd 100644 --- a/docs/【功能说明】AGC聊天素材引用-2026-09-08.md +++ b/docs/【功能说明】AGC聊天素材引用-2026-09-08.md @@ -1,6 +1,6 @@ # AGC 聊天素材引用 -更新时间:2026-10-03 +更新时间:2026-10-04 AGC 聊天输入框支持以结构化引用标记当前项目已登记素材,并提供 Codex 风格的 Skill 提及。输入 `@` 会按素材名称、资源 ID 和类型过滤候选项;输入 `$` 会按当前 DirectProject 可用 Skill 名称过滤候选项;也可以点击输入框右侧的 `@` 按钮打开素材选择面板。 @@ -53,6 +53,37 @@ AGC 聊天输入框支持以结构化引用标记当前项目已登记素材, 输入校验按整条消息判断是否有内容:每个 `input_text` 片段都允许是空字符串、空格或换行,不逐片段拒绝,也不合并、删除或改写片段;原始文字、分段和 `content[]` 顺序保持不变。整条消息必须至少包含一段非空白文字,或至少一个非文本 part(素材引用 / 运行画面引用 / Skill 引用 / 附件引用),否则返回“聊天内容不能为空”。各类引用继续执行原有字段、数量、manifest 归属和路径安全校验;即使消息同时带有正文,非法引用也必须拒绝,不能由正文绕过。 +## 运行画面素材点选(2026-10-04) + +「点选素材」把运行画面里点中的内容落成一条 `runtime-region` 引用插入对话。点选只影响这一次引用:不改资源选中、不改信息栏判据、不写 manifest 或版本、不重载预览。 + +### 必须成立的行为 + +1. **HTML 区域**:点中预览页里的 DOM 元素时,语义保持 2026-09 起的能力——元素矩形、元素上的资源标识属性或媒体 `src` 参与引用身份,行为逐字不变。 +2. **引擎画面**:预览页是 Phaser 4 或 three.js 的 canvas 玩法时,点中由**已登记项目素材**渲染的精灵、图集帧、贴图网格或模型,引用必须带该素材的稳定 id;同一素材在对话里的显示名与其它引用入口(`@` 候选、资源卡「引用」、拖拽批量引用)完全一致。 +3. **身份来源与优先级**:玩法在渲染对象上显式标注的素材身份优先于从贴图地址推断出的文件名;两者都取不到时按第 4 条退化。推断结果必须与 manifest 现有资产对得上——宁可不成引用,也不伪造 id。 +4. **无法确定素材时退化**:画面为程序化绘制、对象没有标注也取不到贴图地址、预览页没有发布引擎句柄——全部退化为**不带素材**的区域引用,与今天的 DOM 退化语义一致:不报错、不静默丢弃,引用仍能插入、能发送;Rust 对未知素材 id 的既有拒绝口径不变。 +5. **命中反馈**:能定位到命中对象时,高亮范围是命中对象在画面上的区域;取不到对象矩形时退化为与 DOM 档一致的高亮范围。 +6. **协议与净化不变**:运行画面点选与 DOM 点选共用同一套预览消息协议、同一套字段净化与数量上限;引擎侧取到的标识必须先过同一套净化才能进入引用载荷。 + +### 边界与非目标 + +- 支持范围是 Phaser 4 与 three.js 两条 AGC 主力链路;Cocos Creator、Godot、Unity 走各自编辑器桥接,不在本能力范围内。 +- 玩法必须先发布一个只读的引擎句柄,点选才能进入引擎档;未发布的项目按第 4 条退化。**改动前生成的历史项目不会自动具备该句柄**,需要重新生成或人工补充——能力说明里必须如实标注,不承诺历史项目可用。 +- 不引入运行期资源使用关系的持久化:不记录"某素材在画面上某位置被用过",不注入玩法代码、不写资源侧车、不改 manifest。 +- 不做像素级或颜色拾取,不为了识别素材去改写玩法源码、资源文件或渲染结果。 +- **Phaser 4 默认装载下贴图地址不可得**:Phaser 4 默认用 XHR 装载图片,贴图元素上的地址是会话内的临时地址,读不回原始素材路径。这类项目**必须由玩法显式标注素材身份**才能点出素材;没有标注就按第 4 条退化(退化为不带素材的区域引用),不猜。 +- **只认玩法发布的只读引擎句柄**:预览页没有发布该句柄、或句柄声明的引擎类型不在支持范围内时,一律退化为不带素材的区域引用;宿主不通过扫描全局对象去猜引擎。 + +### 验收标准与证据 + +| 条款 | 验收方式 | 证据 | +| ---- | -------- | ---- | +| 2、3 | Phaser 4 与 three.js 各一条真机 smoke:起步工程 + 一张已登记素材,点中渲染对象后核对引用芯片名与 `resourceIds` | 待补 | +| 1、6 | 现有 DOM 点选与运行视窗用例不回归 | 待补 | +| 4 | 无引擎句柄 / 命中空白 / 程序化绘制三种情况的退化用例 | 待补 | +| 5 | 高亮矩形:声明级用例 + 真机目视 | 待补 | + ## 粘贴解析(2026-09-22) 把含引用 token 的纯文本粘进输入区时,可以逐字命中的 token 会原位变回引用芯片: