From 26db35286e0f6bcc28dd103fb489d2016d6ed08a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=BE=B7=E5=AE=87?= Date: Tue, 18 Aug 2026 15:15:59 +0800 Subject: [PATCH] =?UTF-8?q?=E6=98=8E=E7=A1=AE=20UI=20=E7=BC=96=E8=BE=91?= =?UTF-8?q?=E5=99=A8=E5=AF=BC=E5=85=A5=E4=B8=8E=E8=AF=86=E5=88=AB=E8=BE=B9?= =?UTF-8?q?=E7=95=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 补充结构识别、语义合并和增量导入的正式行为说明 为 Rust 与前端实现添加对应内联注释 删除已撤销计划文档的技术文档引用 --- apps/ai-game-creator-shell/src-tauri/src/commands.rs | 4 ++++ .../src-tauri/src/ui_editor/commands/merge.rs | 2 ++ .../src-tauri/src/ui_editor/commands/recognition.rs | 4 +++- .../src/features/ui-editor/recognition.ts | 5 ++++- .../【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md | 8 ++++++++ 5 files changed, 21 insertions(+), 2 deletions(-) diff --git a/apps/ai-game-creator-shell/src-tauri/src/commands.rs b/apps/ai-game-creator-shell/src-tauri/src/commands.rs index 2bc1721e5..fdc0c34f6 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/commands.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/commands.rs @@ -1748,6 +1748,8 @@ pub(crate) fn import_ui_editor_local_files( enforce_project_permission_policy(root, "asset.upload")?; let _lock = acquire_project_write_lock(root, "asset.upload")?; advance_agent_runtime_project_revision_locked(root)?; + // V1 有意采用增量导入:每个文件独立写入并登记,后续失败不回滚此前成功项。 + // 调用方必须以返回结果和 manifest 为准重建已提交集合;整批原子语义需另行定义 transaction/reconciliation 合同。 let mut inputs = Vec::new(); for source in source_paths { let path = Path::new(source.trim()); @@ -1947,6 +1949,7 @@ pub(crate) fn import_ui_editor_local_fonts( let font_root = root.join("assets/fonts"); fs::create_dir_all(&font_root).map_err(|_| "创建项目字体目录失败".to_string())?; } + // 字体批次同样是增量提交合同:已经复制并登记的字体在后续失败时保留。 let mut result = Vec::with_capacity(inputs.len()); for (source_file_name, bytes, validated) in inputs { if let Some(existing) = existing_by_hash.get(&validated.content_sha256) { @@ -2213,6 +2216,7 @@ pub(crate) fn import_ui_editor_remote_assets( enforce_project_permission_policy(root, "canvas.asset_import")?; let _lock = acquire_project_write_lock(root, "canvas.asset_import")?; advance_agent_runtime_project_revision_locked(root)?; + // 远程素材导入保持与本地图片/字体相同的增量语义,不对已成功项目文件做整批回滚。 let mut downloads = Vec::new(); for asset in assets { let asset_id = json_string_field(&asset, "assetId") diff --git a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/merge.rs b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/merge.rs index a171cc660..2ee41a561 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/merge.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/merge.rs @@ -311,6 +311,8 @@ mod materialize { collect_original_nodes(&tree.root, *priority, &tree.src_ui_design, &mut records)?; } let mut occupied_ids = records.keys().cloned().collect::>(); + // 合并计划是语义投影,不要求覆盖全部源节点;未引用节点表示本次合并明确丢弃。 + // 这里只拒绝重复/未知引用,避免把“公共结构合并”误收紧为全量复制。 let mut used_original_ids = HashSet::new(); let built = build_node(plan, &records, &mut used_original_ids, &mut occupied_ids)?; Ok(UITree { diff --git a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/recognition.rs b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/recognition.rs index 73b6aa216..c3df08928 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/recognition.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/recognition.rs @@ -280,7 +280,9 @@ fn convert_node( allow_llm_edit_component: true, source: NodeSource::Llm, }, - // TODO: What is let llm give component structure at recognize step ???? + // V1 有意把识别结果限定为“结构草稿”:组件绑定属于后续独立阶段。 + // 因此空组件不是丢失数据,而是等待 visual-binding 阶段补齐 Image/Text。 + // 约定见 docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md。 components: Vec::new(), children_display_mode: ChildrenDisplayMode::Stack, children, diff --git a/apps/ai-game-creator-shell/src/features/ui-editor/recognition.ts b/apps/ai-game-creator-shell/src/features/ui-editor/recognition.ts index 024d910be..2238c6b40 100644 --- a/apps/ai-game-creator-shell/src/features/ui-editor/recognition.ts +++ b/apps/ai-game-creator-shell/src/features/ui-editor/recognition.ts @@ -1,7 +1,10 @@ import type { RecognitionDTO } from './types/RecognitionDTO'; import type { State } from './types/State'; -/** 识别结果是整棵树的替换结果,不与旧树逐节点合并。 */ +/** + * 识别结果是整棵结构草稿树的替换结果,不与旧树逐节点合并。 + * 识别阶段有意不携带视觉组件;组件绑定由后续 visual-binding 阶段完成。 + */ export function applyRecognitionResult( state: State, result: RecognitionDTO, diff --git a/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md b/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md index e9336e086..2ea7e06c3 100644 --- a/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md +++ b/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md @@ -16,6 +16,14 @@ UI Editor Inspector 的全局只读状态唯一来源是 `controller.editor.isLo 全局锁定时所有会修改 State 的 Inspector 控件必须禁用或设为只读,包括文本 / 数值输入、选择器、复选框、组件增删改排和 Sprite 九宫格预设、数值、指针导轨编辑。查看、复制以及不产生 State 修改的展开 / 折叠保持可用。所有 mutation 回调还须在入口检查只读状态,不能只依赖禁用样式,避免键盘或程序化事件绕过锁定。Transform 内不再重复显示全局“只读 / 可编辑”徽章。 +## 2026-08-18 UI Editor 结构识别、合并与增量导入边界 + +UI Editor 当前把“识别界面结构”定义为结构草稿阶段,而不是完整视觉还原阶段。识别 DTO 只负责输出节点层级、几何、名称、描述和置信度;节点组件暂为空,由后续“绑定视觉素材”阶段补齐 Image / Text 组件。`applyRecognitionResult` 可以整体替换当前 `ui_trees`,但该替换只代表结构结果,不能宣称已经保留截图中的视觉内容;组件状态继续为 `Pending`,前置检查负责阻止跳过绑定阶段。 + +多图合并使用 LLM 返回的语义投影树。`Simple` 和 `Merged` 只列出希望进入结果树的原始节点;未被计划引用的源节点表示本次合并判定为冗余或不属于目标公共结构,允许被丢弃,不要求 `used_original_ids` 覆盖全部输入节点。重复 ID 和未知 ID 仍然是错误;省略不是隐式复制或随机删除,而是合并计划的正式语义。 + +UI Editor 的图片、字体和远程素材导入采用增量提交合同:输入先完成各入口已有的预检,随后按顺序逐项写入和登记;前面已成功的项目在后续写入或登记失败时保持有效,调用方必须重新读取 manifest 取得已提交集合。该入口不提供整批事务回滚,也不承诺失败后“零文件、零 manifest 变化”;后续如需原子批量导入,必须新增明确的 transaction / reconciliation 合同,不能把当前入口静默改成另一种语义。 + ## 2026-08-18 UI Editor 左侧节点树跨界面移动 左侧 UI 节点树使用 UI-only 的虚拟超级节点统一承载现有 `ui_trees` 的页面根节点,仅改变树视图,不写入 State 或持久化契约。页面根节点和超级节点不可拖动;普通节点可在不同页面根节点之间拖动,整个子树随节点移动并保留原 `transform`。这里的“保留”只表示复制节点原本的局部布局参数,不承诺跨界面后的页面像素位置稳定:不同界面图拥有独立的画布尺寸、像素密度和父节点坐标空间,跨树坐标换算没有可靠的默认语义,因此本次不做换算,也不把跨树移动后的视觉位置描述为“保持不变”。