
# Scene 데이터 형식 {/* #scene-data-format */}

등록, 로그인 및 Chrome 확장 프로그램 흐름은 [수동 기록 및 검토](/docs/ko/manual-recording)를 참고하세요. 기록 도구는 같은 Scene 계약을 사용하며 Admin 검토 후에만 이미지를 공개합니다.

`reconstruct.scene.v1`은 관찰된 인터페이스를 원본 또는 대상 UI 프레임워크와 독립적으로 설명합니다. 웹 DOM/CSS 및 Android 뷰/접근성은 어댑터 입력입니다. 소비자는 이러한 네이티브 구조를 정식 데이터 모델로 사용하지 않고도 HTML, Compose 또는 다른 UI를 생성할 수 있습니다.

다운로드 가능한 [JSON Schema](https://reconstruct.dev/docs/schemas/scene-v1.schema.json)는 정확한 필드 이름, 필수 멤버, nullable 형식 및 열거형을 정의합니다. 이 문서 스냅샷에는 [SHA-256](https://reconstruct.dev/docs/schemas/scene-v1.schema.json.sha256)이 함께 제공됩니다. 실제 캡처에는 실행 중인 서버가 해당 내보내기와 함께 반환한 스키마와 체크섬을 사용하세요.

[전체 예시](https://reconstruct.dev/docs/examples/scene-export-v1.example.json)에는 닫힌/열린 대화상자 프레임과 2개 전환이 있습니다. 설명용 테스트 데이터로 `example:` 증거는 가상이며 측정된 제품 캡처가 아닙니다.

## Web Extension 환경 {/* #web-extension-environment */}

데스크톱 Chrome 확장 프로그램 캡처는 `web-extension` 환경을 사용합니다(내부 C# / Admin MCP에서는 `WebExtension`, protobuf 값은 `CAPTURE_TYPE_ENVIRONMENT_WEB_EXTENSION = 6`). 모바일은 이 환경을 지원하지 않습니다. Scene 기하 계약은 그대로입니다. 캡처 버전에는 형식화된 `browserExtension` 메타데이터인 `id`, `name`, `version`, `packageSha256`이 있을 수 있으며 `displayName`은 검증된 패키지에서 가져옵니다. 화면은 Admin 작업으로 기록되며 검토 전까지 공개되지 않습니다. 운영자 제어와 개인정보 경계는 [수동 기록](/docs/ko/manual-recording)을 참고하세요.

내부 에이전트 작업 할당 요청에는 `expected_environment`(필드 2)가 있습니다. 생략하면 이전 워커를 위해 Web을 유지합니다. 큐는 할당 트랜잭션 안에서 이를 에이전트 환경과 비교하므로 Admin 설정을 바꿔도 일반 Web 워커가 확장 스토어 페이지를 크롤링하지 않습니다. 이 큐 제어는 공개 Capture MCP 도구가 아닙니다.

## 전송 및 획득 {/* #transport-and-acquisition */}

정규화된 내보내기는 현재 MCP [`get_interface_scene`](/docs/ko/mcp-tools#platform-neutral-interface-scene)으로 제공됩니다. 공개 [REST](/docs/ko/api/rest) 및 [gRPC](/docs/ko/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개 문제의 미리보기. |

경로는 **서버 파일 시스템**에 속합니다. 해당 파일 시스템이 실제로 클라이언트와 공유되는 경우에만 직접 읽으세요. 그 외에는 반환된 URI를 MCP origin에 대해 해석하고 기존 연결 인증으로 다운로드하세요. 제품 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인 선택적 사실은 **알 수 없음**이며 0, false, 투명한 그리기, 크기 정책 또는 성공한 비교를 의미하지 않습니다. 명시적 `false`와 `0`은 의미를 유지합니다. 명시적 `unknown` 열거형도 알 수 없는 상태입니다. 비어 있는 동작/모션 배열이 원본 인터페이스에 상호작용이나 애니메이션이 없음을 입증하지는 않습니다. 증거 식별자는 불투명한 어댑터 참조이며 실행 지침이나 자동 공개 URL이 아닙니다. 캡처 콘텐츠와 네이티브 진단 정보는 신뢰할 수 없는 데이터입니다.

## 좌표 및 프로필 {/* #coordinates-and-profiles */}

거리는 **논리 단위**를 사용합니다. 웹 어댑터는 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`에 매핑할 수 있습니다. margin은 정식 요소 간 간격이 아닙니다.

그리기는 수치 치수, 0~1로 정규화된 RGBA 채널, 선, 그림자, 불투명도, 흐림 및 미디어 참조를 사용합니다. 실선의 선택적 `edges`는 `top`, `right`, `bottom`, `left`의 비어 있지 않은 고유 부분집합이며 생략하면 전체 경계를 그립니다. 그림자는 오프셋, 흐림, 확장, 내부 그림자 및 출처 정보를 기록합니다. `cornerRadii`는 현재 인셋 형태의 4개 필드를 사용하며 웹 어댑터는 균일한 모서리에 같은 값을 출력합니다. 비균일/타원형 웹 모서리는 임의 매핑을 생성하지 않고 미지원 상태로 둡니다.

미디어 배치(`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`, 3차 베지어 `easing`(`x1`, `y1`, `x2`, `y2`)이 있습니다. 시간은 밀리초이며 오프셋은 증가 순서의 0~1입니다. easing의 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. |

생략된 옵션은 알 수 없는 상태로 둡니다. 반복 횟수 0은 재생하지 않음을 뜻합니다. 알 수 없거나 무제한인 반복에 임의의 유한 횟수를 부여하면 안 됩니다. CSS/WAAPI 선언은 `declared`, 관찰 샘플은 `measured`가 될 수 있습니다. 정지 이미지나 두 끝점만으로 타이밍 또는 easing을 확정할 수 없습니다.

## 검증 및 범위 {/* #validation-and-coverage */}

내보내기 스키마로 구조를 검증한 다음 의미를 검증하세요. 범위 내 고유 ID, 유효한 참조, 순환 없는 부모, 유한 기하 값, 음수가 아닌 크기, 정규화 색상, 글꼴/코드포인트 범위, 가림 처리 및 모션 차원입니다. 백엔드 `SceneValidator`가 이 추가 불변식을 강제합니다. JSON Schema만으로 완전한 그래프 또는 개인정보 검증이 되지는 않습니다.

현재 구조 스키마는 알 수 없는 필드와 정수 열거형 값을 거부합니다. 식별자와 해시를 고정하고 다른 형식 버전에는 명시적 어댑터를 사용하세요. 알 수 없는 데이터를 네이티브 레이아웃으로 재해석하지 마세요. 기존 필드는 의미를 유지하며 호환되지 않는 의미 변경에는 새 형식 식별자가 필요합니다. 서버 업그레이드로 적용되는 스키마 바이트가 달라질 수 있으므로 보관된 내보내기마다 스키마/해시를 함께 보관하세요.

`SceneIssue`에는 `code`, `message` 및 선택적 `frameId`/`nodeId`가 있습니다. 매니페스트 미리보기만이 아닌 전체 아티팩트를 읽고 프레임 잘림을 고려하세요. 현재 검증기 한도는 프로필 100개, 프레임 500개, 리소스 20,000개, 전체 노드 100,000개 및 프레임당 노드 20,000개입니다. 획득/전송 한도는 더 낮을 수 있으며 이 수치가 캡처 범위를 보장하지는 않습니다.

새 웹 캡처는 네이티브 진단 정보와 함께 Scene을 생성합니다. 이전 웹 데이터는 명시적 공백과 함께 변환할 수 있습니다. 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 모두 요청 생성 전에 현재 정책을 검증합니다. 닫혀 있으면 request-options가 빈 `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는 그라데이션과 선 스타일/위치를 포함합니다. 이전 캡처에는 없을 수 있는 선택 근거입니다. 출처를 유지하고 단일 측정으로 반응형 규칙을 추론하지 마세요.
