콘텐츠로 이동

검증과 오류

This content is for v0.4. Switch to the latest version for up-to-date documentation.

프로젝트는 JSON 형태부터 프레임을 그릴 때 필요한 것까지 여러 층에서 검사됩니다. 이 페이지에서는 각 층과 실행 위치, 메시지의 모습을 설명합니다. 다 읽고 나면 잘못된 문서를 렌더링 전에 잡아내고, 오류가 나면 그 내용을 읽어 낼 수 있습니다.

JSON Schema(schema/project.v1.schema.json)는 형태만 기술합니다. JSON 타입, 필수 필드, 열거형과 태그된 값, 알 수 없는 필드의 거부입니다. 스키마가 거부하는 문서는 절대 유효한 프로젝트가 아닙니다. 하지만 스키마가 받아들이는 문서도 유효하지 않을 수 있습니다.

에디터나 자체 도구에서 활용하세요. 엔진은 스키마가 필요 없습니다. 문서를 파싱할 때 형태를 직접 검사합니다.

형태가 맞는 문서도 의미가 맞아야 합니다. 엔진의 모델은 미디어를 열지 않고 구간, 한도, 항목 간 참조, 키프레임 순서, 트랜지션 범위를 검사합니다. 같은 검사가 문서를 불러올 때(loadProject, Project::from_json)와 직접 요청할 때 실행됩니다.

import { validateProject, validateProjectJson } from "alpha2/project";
const problems = validateProject(project); // 유효하면 []. 예외를 던지지 않음
if (problems.length > 0) console.error(problems.join("\n"));

validateProject는 엔진의 검사를 TypeScript로 그대로 따라 하므로, 에디터가 문서를 불러오기 전에 거부할 수 있습니다. validateProjectJson(text)는 텍스트에서만 보이는 문제도 알려 줍니다. 크기 초과, 중복된 필드, 소수점이나 지수로 쓴 정수(1920.0), 127단계보다 깊은 중첩입니다. alpha2/builder의 ProjectBuilder.build()는 validateProject를 실행하고 문제가 있으면 예외를 던집니다.

메시지는 문제가 된 항목을 가리키고, 형태 문제라면 그 항목까지의 경로를 알려 줍니다. 다음은 validateProject가 내는 메시지의 예입니다.

문제 메시지
스키마에 없는 필드 project.timeline.tracks[1].clips[0] has unknown field "duration"
잘못된 타입 project.settings.width must be integer
끝이 시작보다 앞선 구간 project.timeline.tracks[0].clips[0].timeline_range.end must not precede its start
없는 소스를 가리키는 클립 clip forest-clip refers to unknown source beach
트랜지션 없이 겹친 클립 clips coast-clip and forest-clip overlap without a transition
순서가 어긋난 키프레임 clip coast-clip has invalid visual properties

loadProject, alpha2-host, Python이 내는 엔진 자체의 메시지는 같은 내용을 엔진의 표현으로 전하며, 형태 문제에는 JSON 텍스트 안의 위치가 붙습니다.

invalid project JSON: unknown field `duration`, expected one of `id`, `source_id`, `timeline_range`, ... at line 1 column 1276
invalid project: clips coast-clip and forest-clip overlap without a covering transition on track photos

어떤 것은 그것을 그리는 렌더러만 검사할 수 있으므로, 프로젝트를 불러올 때는 걸러지지 않습니다.

  • 이펙트. 어떤 이펙트가 있는지는 문서가 아니라 렌더러의 레지스트리가 압니다. 등록되지 않은 이펙트나 정의의 범위를 벗어난 이펙트 파라미터를 그리는 프레임은 EFFECT_ERROR로 실패합니다. CPU 렌더러에서는 런타임 WGSL 이펙트도 같은 방식으로 실패합니다.
  • 폰트. 폰트를 하나도 등록하지 않은 채 텍스트나 자막을 보여 주는 프로젝트는 MISSING_INPUT(“the project shows text, but no fonts were registered”)으로 실패합니다.
  • 미디어. renderAt은 실패하는 대신 프레임이 없었던 소스를 알려 줍니다(missingSources, missingFrames). export는 waiting 티켓으로 필요한 프레임을 요청합니다. 네이티브에서는 alpha2-host conform과 client.conform이 렌더링 없이 프로젝트의 미디어를 점검하며, Node.js에서 미디어가 준비되지 않은 export는 Alpha2ConformError로 실패합니다.

유효한 프로젝트에도 실수일 가능성이 높은 부분이 있을 수 있습니다. 린터는 아무것도 막지 않고 이를 알려 줍니다.

import init, * as wasm from "alpha2/wasm";
import { lintProject } from "alpha2/project";
await init();
const issues = lintProject(wasm, project); // 프로젝트가 유효하지 않으면 loadProject처럼 예외를 던짐

Python에서는 alpha2.lint_project(project)입니다. 각 항목에는 kind가 있습니다.

kind 뜻
unreached_keyframe 주인이 보이는 어떤 시각에도 쓰이지 않는 키프레임. 대개 시간 기준을 잘못 고른 경우입니다.
hidden_clip 위쪽의 불투명한 전체 화면 클립에 내내 가려지는 클립.
short_transition 어떤 프레임에도 보이지 않는 트랜지션. 한 프레임보다 짧거나, 한 프레임 길이인데 그리드에서 벗어난 경우입니다.
off_frame_boundary 프레임 사이에 놓인 경계. 그 변화는 다음 프레임에서야 보입니다.
unused_source 어떤 클립이나 도달 가능한 media 노드도 읽지 않는 소스.
hdr_source 색 파이프라인이 HDR을 거부하는 프로젝트의 HDR 소스.
empty_subpath, paint_without_geometry 아무것도 그리지 않는 셰이프.

예를 들어 자신을 보여 주는 클립의 끝을 넘어서 키프레임한 셰이프 제너레이터는 다음과 같이 보고됩니다.

{ "kind": "unreached_keyframe", "owner": { "type": "source", "source": "dot" }, "property": "items[0].center", "time": 480000 }

엔진은 모든 문서에 고정된 한도를 적용합니다. 트랙 256개, 트랙당 클립 4,096개, 전체 클립 100,000개, 64 MiB의 JSON 문서, 한 변 최대 16,384픽셀·전체 최대 67,108,864픽셀의 캔버스 등입니다. 한도를 넘는 문서는 불러올 때 한도 이름을 담은 오류로 거부됩니다. 이 숫자들은 alpha2/project의 TypeScript 상수와 Python 상수로도 제공되므로, 보내기 전에 미리 확인할 수 있습니다. 전체 목록은 한도에 있습니다.