Skip to main content

Worlds Service

상태: 1차 MVP 구현 완료

기준일: 2026-08-09

1. 목적과 도메인 경계

Worlds는 Cinema와 독립적으로 고정 환경을 생성하고 보관하는 서비스다. 생성된 월드는 여러 Cinema Project와 Scene에서 재사용할 수 있다.

  • World Model은 벽, 바닥, 천장, 통로, 고정 구조물과 환경 외형을 생성한다.
  • 인물, 이동 가능한 소품, 카메라 배치는 생성된 월드와 분리된 Composition 계층이 관리한다.
  • Cinema는 mutable World가 아니라 불변 WorldRevision을 참조한다.
  • Provider와 모델 선택은 서버 설정이며 사용자 UI에 노출하지 않는다.

2. 입력 계약

입력 종류필수 입력의미
TEXTtextPrompt자연어 기반 생성형 환경
IMAGE이미지 1개단일 시점 기반 환경
MULTI_IMAGE동일 장면 이미지와 선택적 azimuthDegrees동일 촬영 위치에서 방향을 달리한 입력을 기본 계약으로 사용
VIDEO비디오 1개이동하는 시점이 포함된 환경 입력

소스 이미지를 서로 다른 카메라 위치에서 촬영했음을 나타내는 위치 좌표는 현재 Marble 공개 API에 없다. 따라서 MULTI_IMAGE는 위치 이동 기반 정밀 재구성을 보장하지 않는다.

원본 미디어는 기존 Presigned Upload API로 SurfAI S3에 먼저 저장한다. 생성 요청은 외부 URL 대신 안정적인 s3Path, 파일명, MIME, 이미지 순서와 선택적인 방위각·파노라마 여부를 기록한다.

3. Provider 추상화

첫 Adapter는 World Labs Marble이다. 기준 요청은 다음과 같다.

POST https://api.worldlabs.ai/marble/v1/worlds:generate
Content-Type: application/json
WLT-Api-Key: <server-secret>
{
"display_name": "Mystical Forest",
"model": "marble-1.1",
"world_prompt": {
"type": "text",
"text_prompt": "A mystical forest with glowing mushrooms"
}
}

Provider Adapter의 공통 책임은 다음과 같다.

WorldModelProvider
├── submit(input) -> providerOperationId
├── getOperation(providerOperationId)
├── getWorld(providerWorldId)
└── parseCompletedOperation(operation)

Provider의 원본 응답은 진단과 재현을 위해 providerSnapshot에 저장하되, 공개 API 응답은 Provider 독립 계약으로 변환한다.

4. 데이터 모델

World

사용자가 관리하는 논리적 컨테이너다.

World
├── id / ownerId
├── name / description
├── currentRevisionId?
├── archivedAt?
└── createdAt / updatedAt

WorldGenerationAttempt

외부 비동기 실행과 입력 스냅샷을 보존한다.

WorldGenerationAttempt
├── id / worldId
├── version
├── status
├── providerKey / providerModel
├── providerOperationId? / providerWorldId?
├── inputSnapshot
├── errorCode? / errorMessage?
├── submittedAt? / completedAt?
└── createdBy / createdAt / updatedAt

상태 흐름은 다음과 같다.

QUEUED -> SUBMITTED -> PROCESSING -> INGESTING -> READY
\-> PARTIAL
\------------------------------------> FAILED

WorldRevision

하나의 완료된 환경 월드다. 생성 후 수정하지 않는다.

WorldRevision
├── id / worldId / version
├── sourceAttemptId
├── status: READY | PARTIAL | ARCHIVED
├── providerWorldId
├── spatialManifest
├── providerSnapshot
├── contentHash
└── createdAt

WorldArtifact

종류기본 활용
THUMBNAIL목록 미리보기
PANO월드 상세 미리보기
SPZ_100K저사양 Preview
SPZ_500K기본 3D Viewer
SPZ_FULL고품질 확인
COLLIDER_MESH_GLB충돌과 배치 계산
HQ_MESH_GLB선택적 외부 정밀 작업
FULL_RES_MESH_GLB선택적 전체 해상도 Mesh
SPLAT_PLY선택적 분석·외부 편집

모든 Artifact는 providerUrl과 별도로 SurfAI s3Path, MIME, byte size, checksum, ingestion status를 가진다. 외부 URL은 장기 표시 URL로 사용하지 않는다.

spatialManifest는 최소한 다음 값을 가진다.

{
"coordinateConvention": "MARBLE_RAW_OPENCV",
"metricScaleFactor": 1.0,
"groundPlaneOffset": 0.0,
"viewerTransform": {
"rotationXDegrees": 180
}
}

5. 비동기 처리와 수집

브라우저는 World Labs API를 직접 호출하지 않는다. Backend Worker가 Provider Operation을 지수 backoff로 확인한다. 완료 후 외부 Artifact를 스트리밍 방식으로 SurfAI 영구 버킷에 복사한다.

  • DB lease를 사용해 다중 Backend 인스턴스의 중복 처리를 방지한다.
  • Provider Operation 완료와 SurfAI World 준비 완료를 구분한다.
  • 필수 Artifact 수집이 끝나야 READY다.
  • 일부 Artifact만 수집되면 PARTIAL로 표시해 누락 결과를 사용자에게 숨기지 않는다.
  • 외부 CDN 응답은 임의 크기 청크를 그대로 S3에 전달하지 않고 AWS multipart uploader로 결합해 저장한다.
  • Artifact 수집 실패는 같은 Provider World ID의 최신 결과 URL을 다시 조회한 뒤 실패 파일만 재수집한다. 이 동작은 World 생성 요청을 새로 만들지 않는다.
  • 완료·실패 이벤트는 기존 사용자 WebSocket 채널을 통해 전달한다.

POST /v1/worlds/:worldId/artifacts/retry는 최근 FAILED 또는 PARTIAL 시도의 실패 Artifact를 PENDING으로 되돌린다. Worker는 저장된 providerWorldId로 World Labs 결과를 다시 조회하고, 이미 READY인 Artifact는 건너뛴다.

6. 화면 구조

Route책임
/worlds내 월드 목록, 상태, Pano/Thumbnail
/worlds/new입력 방식 선택, 원본 업로드, 생성 요청
/worlds/:worldIdRevision 이력, Pano, SPZ Viewer, Artifact 상태
/worlds/:worldId/compose향후 인물·오브젝트·카메라 배치

SPZ Viewer는 Three.js와 Spark를 사용한다. semantics_metadata.metric_scale_factor를 위치와 Gaussian 크기에 적용하고, center의 Y 좌표에서 ground_plane_offset을 뺀다. Three.js View에서는 Marble 안내에 따라 X축 180도 변환을 적용한다.

7. Cinema 연결

1차 Worlds 구현은 Cinema Entity에 직접 의존하지 않는다. 후속 단계에서 별도 Binding을 추가한다.

CinemaSceneWorldBinding
├── projectId / sceneId
├── worldRevisionId
├── worldTransform
├── status
└── createdBy / createdAt

시작·종료 Frame 생성 시에는 다음 불변 Snapshot을 사용한다.

WorldRevision
+ WorldCompositionRevision
+ CameraRevision
= FrameRecipe

8. 1차 구현 범위

  1. 독립 Backend worlds 모듈과 Migration
  2. World 생성·목록·상세·보관 API
  3. Marble text/image/multi-image/video Adapter
  4. Operation 추적과 Artifact S3 수집
  5. 독립 Sidebar 메뉴와 /worlds 화면
  6. Pano Preview와 SPZ 3D Viewer

Composition, 캐릭터 배치, Cinema Binding, PLY/HQ Mesh 주문형 Export는 후속 범위다.

9. 실행 설정

World Labs 인증 정보와 모델은 Backend 환경변수로만 관리한다. Frontend와 사용자 요청에는 API Key 또는 모델 선택지를 노출하지 않는다.

WORLDLABS_API_KEY=<required>
WORLDLABS_BASE_URL=https://api.worldlabs.ai
WORLDLABS_MODEL=marble-1.1
WORLDLABS_TIMEOUT_MS=60000

WORLDLABS_API_KEY를 제외한 값에는 위 기본값이 적용된다. Key를 변경한 뒤에는 Backend 프로세스를 재시작해야 한다.