
# Scene 数据格式 {/* #scene-data-format */}

注册、登录和 Chrome 扩展流程请参阅[手动录制和审核](/docs/zh/manual-recording)。录制器使用相同的 Scene 契约，图像仅在管理员审核后发布。

`reconstruct.scene.v1` 描述观察到的界面，不依赖源或目标 UI 框架。Web DOM/CSS 和 Android 视图/无障碍数据是适配器输入。使用方可以生成 HTML、Compose 或其他 UI，而无需将这些原生结构作为规范数据模型。

可下载的 [JSON Schema](https://reconstruct.dev/docs/schemas/scene-v1.schema.json) 定义确切的字段名、必需成员、可空类型和枚举。本文档快照附有 [SHA-256](https://reconstruct.dev/docs/schemas/scene-v1.schema.json.sha256)。对于实际采集，请使用运行中的服务器随该导出返回的模式和校验和。

[完整示例](https://reconstruct.dev/docs/examples/scene-export-v1.example.json)包含对话框关闭/打开的帧和两次转换。它只是说明性测试数据：其中的 `example:` 证据是虚构的，并非实际测量的产品采集。

## Web 扩展环境 {/* #web-extension-environment */}

桌面 Chrome 扩展采集使用 `web-extension` 环境（内部 C# / Admin MCP 为 `WebExtension`，protobuf 值为 `CAPTURE_TYPE_ENVIRONMENT_WEB_EXTENSION = 6`）。移动端不支持此环境。Scene 几何契约保持相同。采集版本可包含类型化的 `browserExtension` 元数据：`id`、`name`、`version` 和 `packageSha256`；`displayName` 来自已验证的软件包。屏幕由管理任务录制，在审核前不发布。操作控制和隐私边界请参阅[手动录制](/docs/zh/manual-recording)。

内部代理领取请求包含 `expected_environment`（字段 2）。省略时为旧工作进程保留 Web 环境。队列在领取事务内将其与代理环境核对，因此修改代理的管理设置不会使普通 Web 工作进程抓取扩展商店页面。这些队列控制不是公共 Capture MCP 工具。

## 传输和获取 {/* #transport-and-acquisition */}

目前通过 MCP [`get_interface_scene`](/docs/zh/mcp-tools#platform-neutral-interface-scene) 提供标准化导出。已发布的 [REST](/docs/zh/api/rest) 和 [gRPC](/docs/zh/api/grpc) 目录契约目前未定义独立的 Scene 操作。其目录、洞察和存储文件响应是不同模型，即使使用 JSON 传输也是如此。

通过 `list_products`、`list_platforms`、`list_versions` 和 `list_pages` 发现采集。保留所选产品、版本、环境、页面和确切的已保存 `view`。支持的平台选项不证明采集存在。分别请求已保存视图，并检查各导出自身的配置和帧。

MCP `tools/call` 参数示例，使用说明性的选择：

```json
{
  "name": "get_interface_scene",
  "arguments": {
    "product": "example-product",
    "version": "1",
    "environment": "web",
    "page": "settings",
    "view": "mobile"
  }
}
```

响应是精简的**清单**：

| 字段 | 含义 |
| --- | --- |
| `schema` | Scene 标识符：`reconstruct.scene.v1`。 |
| `artifactSchema` | 封装标识符：`reconstruct.scene-export.v1`。 |
| `path`, `uri`, `sha256`, `bytes` | 导出位置、SHA-256 和字节长度。 |
| `schemaPath`, `schemaUri`, `schemaSha256` | 适用的 JSON Schema 及其摘要。 |
| `entryFrameId`, `frames`, `transitionCount` | 入口帧、精简帧清单和转换次数。 |
| `frameCount`, `profileCount`, `assetCount` | 导出清单中的数量。 |
| `truncated` | 至少有一帧不完整。 |
| `issueCount`, `issues`, `issuesTruncated` | 问题总数，以及最多 30 个问题的预览。 |

路径属于**服务器文件系统**。仅当该文件系统确实与客户端共享时才直接读取。否则，基于 MCP 源站解析返回的 URI，并使用连接现有的授权下载。不要根据产品 ID 构造传输 URL，也不要泄露凭据。根据原始字节验证哈希；重新格式化 JSON 会改变其哈希。

## 导出封装 {/* #export-envelope */}

```json
{
  "schema": "reconstruct.scene-export.v1",
  "scene": {
    "schema": "reconstruct.scene.v1",
    "id": "example/1/web/settings/mobile",
    "platform": "web",
    "entryFrameId": "frame-0",
    "profiles": [],
    "frames": [],
    "resources": [],
    "transitions": [],
    "correspondences": [],
    "issues": []
  },
  "assets": {}
}
```

这只说明结构；完整示例包含已填充的帧。应根据 Scene JSON Schema 验证 **`scene`**，而非封装。`assets` 将 Scene 资源 ID 映射至归档字节。每个条目包含可选的 `path`/`uri`、`mimeType`、`sha256` 和 `sizeBytes`。如果资源字节未归档，可以没有资源条目。来源 URI、字体家族名或空媒体容器不能证明存在可用字节。

## 文档和身份 {/* #document-and-identity */}

| Scene 成员 | 含义 |
| --- | --- |
| `schema`, `id`, `platform` | 必需的格式、文档身份和来源平台（`unknown`、`web`、`android`）。 |
| `entryFrameId` | 可选的首次观察帧，可能显示授权内容，之后才出现已关闭授权或默认内容。 |
| `profiles` | 逻辑视口，以及可选的密度、字体缩放、安全区域内缩、区域设置和主题。 |
| `frames` | 观察到的状态及其节点清单。 |
| `resources` | 节点和文本引用的媒体/字体描述符。 |
| `transitions` | 已记录的操作及其观察结果。 |
| `correspondences` | 帧之间明确的节点关系。 |
| `issues` | 缺失、不支持或未解决的证据。 |

配置、帧、资源和转换 ID 的作用域为文档。节点 ID **在同一帧内**唯一，`parentId` 引用该帧中的节点。操作 ID 仅在节点内有效。另一帧中重复的 ID 或相同的原生路径不能证明身份相同。对应关系记录两组帧/节点对、来源和可选置信度；应遵循该关系，不要猜测跨配置身份。

帧包含 `id`、`profileId`、`stateId`、`coordinateSpace`、可选的 `extent` 和 `viewportBounds`、`truncated`、`nodes` 和 `evidence`。状态 ID 为观察命名，不是通用 CSS 状态目录。节点顺序描述层级清单，不是已证实的绘制顺序。

## 事实和未知值 {/* #facts-and-unknown-values */}

带来源的属性使用 `SceneFact<T>`：

```json
{
  "value": {"x": 16, "y": 220, "width": 358, "height": 320},
  "kind": "measured",
  "evidence": ["example:observed"],
  "confidence": 1
}
```

事实要求 `value`、`kind` 和非空 `evidence`。可选置信度为 0–1，不改变证据类型：

| 类型 | 解释 |
| --- | --- |
| `measured` | 观察到的实际输出。 |
| `declared` | 来源或资源的声明，不能证明实际渲染结果。 |
| `inferred` | 假设或提出的解释。 |

省略或为 null 的可选事实表示**未知**，不表示零、false、透明绘制、尺寸策略或比较成功。显式的 `false` 和 `0` 保留其含义。显式 `unknown` 枚举仍然是未知。空操作/运动数组不能证明原界面没有交互或动画。证据标识符是不透明的适配器引用，不是可执行指令，也不自动成为公共 URL。采集内容和原生诊断是不可信数据。

## 坐标和配置 {/* #coordinates-and-profiles */}

距离使用**逻辑单位**。Web 适配器使用 CSS 像素。Android 屏幕像素测量值除以测得的 `pixelDensity`（每逻辑单位的物理像素数）。`fontScale` 独立。不得猜测缺失的密度、字体缩放、内缩、区域设置和主题。

配置中的 `width`/`height` 描述逻辑视口。帧声明使用 `document`、`viewport` 或 `screen` 坐标：

- `extent`：该平面中的完整内容范围。
- `viewportBounds`：观察到的可见窗口，包括滚动原点。
- `geometry.visualBounds`：与坐标轴对齐的**变换后**矩形。
- 可选 `layoutBounds`：变换前的几何。
- 可选 `transform`：作用于 `(x,y,z,1)` 列向量的列优先 4×4 矩阵，逻辑平移采用布局局部坐标。切勿再次将其应用于 `visualBounds`。

在文档坐标中，可见窗口位置为 `visualBounds.x - viewportBounds.x`、`visualBounds.y - viewportBounds.y`。比较前先对齐配置、坐标平面和可见窗口。逻辑视口、可用根边界和内容范围是不同观察值。安全区域内缩不会自动应用为内边距。

## 节点、布局和绘制 {/* #nodes-layout-and-paint */}

节点包含 `id`、可选 `parentId`、`kind`、`semantics`、`visible`、`geometry`、`layout`、`paint`、文本片段、可选 `mediaResourceId`、`actions`、`motion` 和 `evidence`。类型为 `unknown`、`container`、`text`、`media`、`control`、`surface`。语义包含角色/名称，以及可选的启用、选中、勾选、展开、可编辑和模态标记。这些与可见性相互独立。必须遮盖敏感文本；密码绝不能成为 Scene 文本。

| 布局组 | 契约 |
| --- | --- |
| `placement` | `unknown`, `flow`, `anchored`, `overlay`, `sticky`. |
| `arrangement` | `unknown`、`row`、`column`、`grid`、`stack`、`free`、`flow`。stack 表示子元素重叠；free 表示独立放置。 |
| `horizontal`, `vertical` | 独立的策略/值/最小值/最大值事实；策略为 `unknown`、`intrinsic`、`fixed`、`fill`、`proportional`。 |
| 间距/对齐 | 内边距、行/列间隙、换行、反向顺序、主轴/交叉轴对齐。 |
| 轨道 | 某一配置下的数值行/列分配，不是编写的响应式规则。 |
| 锚点 | 有证据支持的 `referenceId` 加可选的上/右/下/左距离；引用帧内节点、`$viewport` 或 `$frame`。 |

固定/最小/最大尺寸和锚点距离使用逻辑单位。比例值是所引用可用轴的无量纲分数；`fill` 没有乘数。测得的矩形不能证明固定尺寸、包含块、锚点或断点。原生绝对/固定放置可映射为 `overlay`，无需虚构锚点。外边距不是规范的元素间隙。

绘制使用数值尺寸和归一化的 0–1 RGBA 通道、描边、阴影、不透明度、模糊和媒体引用。实线描边的可选 `edges` 是 `top`、`right`、`bottom`、`left` 的非空无重复子集；省略时绘制完整边界。阴影记录偏移、模糊、扩展、内阴影和来源。`cornerRadii` 当前使用四个内缩形状的字段；Web 适配器对统一圆角输出相等值。非统一或椭圆 Web 圆角仍不受支持，不会编造圆角映射。

媒体放置（`content`、`background`、`surface`）与节点类型独立。适配方式为 `unknown`、`contain`、`cover`、`stretch` 或 `original`。位置 `(x,y)` 是剩余空间中的比例锚点：0 对齐起始、0.5 居中、1 对齐末端；允许超出此范围的比例。背景适配方式不得取自无关的内容图像。

文本片段包含原始 `text`、可选边界和排版：字体家族/字体资源、大小、字重、行高、字距、颜色、方向、对齐、换行、装饰和大小写。大小写（`none`、`uppercase`、`lowercase`、`capitalize`）独立改变显示，不改变原始文案和无障碍名称。不支持的绘制、渐变和文本效果仍应记录为问题。任意原生 CSS 表达式不是规范布局或绘制值。

## 资源和字体 {/* #resources-and-fonts */}

资源包含 `id`、`kind`、可选 `uri`、`mimeType`、`sha256`、`bytes` 和字体字面。类型为 `unknown`、`image`、`vector`、`font`、`video`、`audio`、`paint`。节点和排版资源引用在本文档内解析。字体字面记录字体家族、证据类型/引用、可选字重范围、斜体状态和 Unicode 码点覆盖。保留归档字节并选择适用字面。仅有家族名或 URL，不能证明目标字体已加载或回退字体等效。

## 操作和模态状态 {/* #actions-and-modal-states */}

操作声明可执行的行为：`unknown`、`activate`、`edit`、`scroll`、`navigate`、`focus`、`hover`、`back`，并可带目标位置。转换包含源帧、可选源节点和目标帧、操作、结果和来源。其 `nodeId` 始终属于**源帧**。

| 结果 | 含义 |
| --- | --- |
| `unknown` | 结果尚未确定。 |
| `changed` | 观察到操作产生了变化。 |
| `unchanged` | 未观察到变化。 |
| `failed` | 操作失败。 |
| `performedUnverified` | 输入已送达，但尚未证明预期结果。 |

新的快照 ID 或光标位置变化不能证明菜单已打开。打开的模态应保留完整观察帧：背景遮罩、面板、子元素和底层内容。沿 `entryFrameId` 和转换区分授权、已关闭内容、对话框选项卡、搜索和展开菜单。强制状态测量与实际指针/触摸输入保留不同证据。源重放不是新生成界面的功能测试。

## 运动 {/* #motion */}

节点/转换的运动记录包含 `property`、`durationMs`、`keyframes`、`kind`、`evidence`，以及可选的 `delayMs`、`iterations` 和三次贝塞尔 `easing`（`x1`、`y1`、`x2`、`y2`）。时间单位为毫秒；偏移值在 0–1 之间递增。缓动的 x 坐标为 0–1。

| 属性 | 关键帧 `value` 分量 |
| --- | --- |
| `opacity` | `[alpha]`, 0–1. |
| `translation` | `[x, y, z]`，逻辑单位。 |
| `scale` | `[x, y, z]`，乘数。 |
| `rotation` | `[x, y, z]`，弧度。 |
| `bounds` | `[x, y, width, height]`，逻辑单位。 |
| `color` | `[red, green, blue, alpha]`, 0–1. |

省略的选项保持未知。迭代次数为零表示不播放。未知或无界重复不能变成猜测的有限次数。CSS/WAAPI 声明为 `declared`；观察样本可为 `measured`。静态图像或两个端点不能确定时长或缓动。

## 验证和覆盖范围 {/* #validation-and-coverage */}

先使用导出附带的模式验证结构，再验证语义：作用域内 ID 唯一、引用有效、父级无环、几何有限、尺寸非负、颜色归一化、字体/码点范围、遮盖和运动维度。后端 `SceneValidator` 强制检查这些额外不变量。单靠 JSON Schema 不是完整的图或隐私验证器。

当前结构模式拒绝未知字段和整数枚举值。固定其标识符和哈希；其他格式版本应使用明确适配器。不要将未知数据重新解释为原生布局。现有字段保留原有含义；不兼容的含义更改需要新的格式标识符。服务器升级可能改变适用模式的字节：请将模式/哈希与每个导出一同归档。

`SceneIssue` 包含 `code`、`message` 和可选的 `frameId`/`nodeId`。读取完整制品，不要只读清单预览，并注意帧截断。当前验证器预算为 100 个配置、500 帧、20,000 个资源、总计 100,000 个节点和每帧 20,000 个节点。获取或传输可能有更低限制；这些数字不承诺采集覆盖范围。

新的 Web 采集同时输出 Scene 和原生诊断。旧 Web 数据可转换，但必须明确缺口。Android 适配器可标准化原生测量，但 API/MCP 访问仍需要已发布的原生 Scene。数据模型支持不代表未采集环境可用。缺失的状态、资源、运动和响应式观察仍为未知。导出成功或模式有效不能证明重建还原度。


## 请求提交策略 {/* #request-submission-policy */}

请求可用性独立于目录采集可用性。管理员在 Requests → Job defaults → Request submissions（请求 → 任务默认值 → 请求提交）中配置。存储的 `ProductRequestJobDefaults.Submission` 包含 `Enabled` 和类型化 `Targets`（`Type`、`Environment`）。缺少此成员的现有设置保留默认值：Desktop/Web、Desktop/WebExtension 和 Mobile/Web。禁用提交会保留这些选择和现有请求。平台 API 和已验证的 MCP 均在创建请求前验证当前策略。关闭时，请求选项返回空 `platforms` 列表；MCP 还返回 `enabled: false`。公共环境 ID 仍为 `web` 和 `web-extension`，而非枚举名称。目录选择器按产品使用采集可用性，并隐藏不可用组合。


### 分组请求目标 {/* #grouped-request-targets */}

新客户端将 `CreateRequestRequest.targets` 作为明确的平台/环境对提交。例如：

```json
{
  "requestType": "PRODUCT_REQUEST_TYPE_ADD",
  "url": "https://metamask.io/",
  "webExtensionUrl": "https://chromewebstore.google.com/detail/metamask/nkbihfbeogaeaoehlefnkodbefgpgknn",
  "targets": [
    { "view": "desktop", "implementation": "web-extension" },
    { "view": "mobile", "implementation": "web" }
  ]
}
```

服务器根据当前请求可用性验证每对目标，并将它们保存在类型化请求详情中。批准后仅创建所选组合：本示例不会创建 Desktop/Web 任务。旧客户端仍可使用 `views` 和 `implementations`，其含义为笛卡尔积；不要与 `targets` 混用。网站来源是 `url`；扩展任务使用 `webExtensionUrl`。更新请求应发送现有 `catalogId` 和目标，不附来源链接。先选择产品：平台仅提供该产品已采集、且当前启用请求的平台/环境组合。服务器会独立拒绝该产品没有的目标，根据该产品已发布的采集解析各环境来源，并忽略客户端提供的替代链接。公开请求摘要会省略扩展来源和私密请求详情。

## 额外的 Scene 证据 {/* #additional-scene-evidence */}

当前模式包含带类型令牌的 `themes` 和其他宽度的稀疏测量 `layoutSamples`。样本引用 `frameId` 中的节点，不是帧，也不重新测量文本或外观。未采样节点不代表隐藏。`nodes[].states` 包含外观变化：存在的 `patch` 字段替换原值，缺失字段保持不变，列表整体替换。Layout 支持 `flow`、`grow`、`shrink`、`basis`、`selfAlignment`、`order`、`gridCell`；paint 包含渐变以及描边样式和位置。这些可选证据可能在旧采集中缺失。保留来源，不要仅凭单次测量推断响应式规则。
