기술 레퍼런스

완전한 Locus Package v2 제작 가이드

이 페이지에서
  1. 작동하는 완전한 패키지에서 시작하기
  2. 아카이브 구조
  3. locusplace.json
  4. 래퍼 필드 레퍼런스
  5. ZIP 내부의 Package v2 메타데이터
  6. View: destination.json
  7. Room: space.json
  8. Experience: experience.json
  9. 선택적 기능 및 번역된 레이블
  10. 필수 출처
  11. 보안 및 리소스 한도
  12. 파일 및 URL 가져오기
  13. 패키지 검증 및 예제

상태: 게시, 저장, 조합 및 모든 기능을 갖춘 가져오기를 위한 표준 계약입니다. Locus 1.2.1 이상은 파일 또는 공개 HTTPS URL에서 이 아카이브를 View와 Room 모두로 가져올 수 있습니다. 기존 플랫 형식의 설명: locus-asset-format.md . 이 형식은 계속 호환 입력으로 허용됩니다.

하나의 .zip 또는 .locusplace 파일은 하나 이상의 Package v2 Destination(제품명: View), Space(Room) 및 Experience를 담는 일반 ZIP 아카이브 하나입니다. Locus 자체와 모든 기능을 갖춘 휴대용 패키지가 사용하는 안전한 게시 및 무결성 래퍼입니다. ZIP 루트에는 locusplace.json 및 catalog/ 가 직접 들어갑니다. 둘을 다른 상위 디렉터리에 넣지 마세요.

검증은 파일명 확장자가 아닌 아카이브 바이트와 매니페스트를 기준으로 합니다. 완전한 패키지는 자신의 packageID, 콘텐츠 ID, contentVersion 업데이트 계열과 지원되는 Experience를 보존합니다. 동일한 콘텐츠 해시를 가져오는 것은 아무것도 바꾸지 않는 멱등 작업입니다. 유지 관리되는 패키징 및 검증 도구는 정확히 이 형식을 생성하고 검사합니다.

이 래퍼는 실행 가능한 확장이 아닌 순수 데이터를 담습니다. 동일한 Locus 바이너리에서 런타임이 사용하는 모든 Package v2 기능은 내장 아카이브, Library 다운로드 및 파일/URL 가져오기에서 동일한 콘텐츠 의미를 가집니다. 출처에 따라 이용 권한, 사용자 지정 가져오기 허용량, 업데이트 권한, 저장, 제거 및 UI 레이블은 달라질 수 있지만 Room/View 스키마나 렌더러 기능이 달라지지는 않습니다. 스크립트, 플러그인, 동적 라이브러리 및 실행 가능한 멤버는 형식에 포함되지 않습니다. 모든 출처에 동일한 경로 격리, 무결성, 리소스 한도, 구조 디코딩, 참조 완결성 및 최소 버전 검사가 적용됩니다.

이 가이드는 완전한 래퍼와 기본 매니페스트를 설명합니다. 필드 레퍼런스 는 선택적 View 및 Room 기능, 해당 에셋, 범위 및 최소 앱 버전을 설명합니다. 래퍼 스키마 및 출처 스키마 는 JSON 구조를 설명합니다. 패키징 및 검증 도구는 파일 바이트와 필드 간 규칙도 검사합니다. JSON Schema만으로 아카이브를 검증하거나 Apple Vision Pro에서 편안하게 느껴질지 입증할 수는 없습니다.

작동하는 완전한 패키지에서 시작하기

다음을 복제하거나 다운로드하세요: 공개 도구 저장소. macOS 에서 해당 저장소의 루트를 기준으로 아래 명령을 실행하세요. Python 3.9 이상과 다음 도구가 포함된 Xcode가 필요합니다: xcrun usdchecker 및 xcrun usdcat. 기본 검증은 Python 표준 라이브러리를 사용합니다. 이미지의 완전한 디코딩에는 /usr/bin/sips 를 사용하며 모델 검사에는 Xcode의 usdchecker 및 usdcat 를 사용해 모델을 검사합니다. 고급 구름, 물 반사/접촉 및 태양 없는 하늘 검사에는 NumPy와 Pillow도 필요합니다: python3 -m pip install numpy pillow.

python3 examples/locusplace/build_examples.py /absolute/path/to/locusplace-examples
python3 tools/validate_locusplace.py --current-app-version 1.4.4 /absolute/path/to/locusplace-examples/view-only.locusplace
python3 tools/validate_locusplace.py --current-app-version 1.4.4 /absolute/path/to/locusplace-examples/room-only.locusplace
python3 tools/validate_locusplace.py --current-app-version 1.4.4 /absolute/path/to/locusplace-examples/combined.locusplace

대상 디렉터리가 없거나 비어 있어야 합니다. 이 작은 합성 예제는 형식을 시험하기 위한 것이며, 그라데이션과 큐브는 실제 배포 수준의 풍경이나 완성된 Room이 아닙니다. 소스와 생성 콘텐츠는 Apache-2.0 라이선스를 따릅니다. 다음을 참고하세요: 예제 설명.

--current-app-version 는 가져오기 검증에 사용할 Locus의 대상 버전입니다. 이 값은 설치된 앱을 업그레이드하거나 기능 지원을 추가하지는 않습니다. 도구는 보수적으로 다음 기본값을 사용합니다: 1.0.0이며 대상 버전을 명시적으로 전달하세요. 완전한 가져오기에는 Locus 1.2.1 이상이 필요하며 새 필드는 각자 별도의 최소 버전을 요구합니다. Room 지면 및 중경 제어에는 이를 지원하는 1.4.4 이상 빌드가 필요합니다. 이 가이드는 해당 빌드가 현재 App Store에 있다고 보장하지 않습니다.

직접 패키지를 만들려면 예제를 편집 가능한 폴더로 풀거나 아래 구조를 만드세요. 에셋과 출처를 바꾸고 자신의 안정적인 ID를 사용하여 출력물을 패키징하세요. 출력 위치는 외부이며 기준은 해당 폴더입니다:

python3 tools/pack_locusplace.py --current-app-version 1.4.4 MyEditablePlace MyPlace.zip
python3 tools/validate_locusplace.py --current-app-version 1.4.4 --json MyPlace.zip

패키징 도구는 files 및 contentHash를 다시 계산하고 아카이브를 검증한 후에만 결과를 게시합니다. 기존 출력은 덮어쓰지 않습니다. 편집 가능한 원본은 그대로 유지합니다. 결과는 다음 경로로 가져오세요: Places → 가져오기 → View 가져오기 또는 Room 가져오기 → 파일 중 포함된 콘텐츠 유형에 맞는 가져오기 경로를 선택하세요. 결합 패키지는 콘텐츠를 함께 설치합니다. ZIP을 직접 가리키는 공개 HTTPS URL도 사용할 수 있습니다. 완성된 장소를 공유하기 전에 제작한 각 좌석, 효과, 조명 및 사운드를 Apple Vision Pro에서 확인하세요.

아카이브 구조

example.locusplace
├── locusplace.json
└── catalog/
    ├── destinations/<destination-id>/
    │   ├── destination.json
    │   ├── provenance.json
    │   └── ...
    ├── spaces/<space-id>/
    │   ├── space.json
    │   ├── provenance.json
    │   └── ...
    └── experiences/<experience-id>/
        └── experience.json

루트 파일인 locusplace.json 만 제외하고 모든 비디렉터리 멤버를 다음에 선언해야 합니다: files. 선언한 모든 파일이 존재해야 합니다. 아카이브에는 알려진 세 카탈로그 컬렉션만 담을 수 있으며, 모든 파일은 다음에 선언된 패키지 ID 내부에 있어야 합니다: contents입니다. Package v2 매니페스트는 알 수 없는 필드를 허용하여 향후 버전과의 호환성을 유지합니다. 그러나 패키지 래퍼의 알 수 없는 필드, 지원하지 않는 형식 버전, 컬렉션 및 콘텐츠 모드는 거부합니다. 출처는 공개된 스키마를 따라야 합니다.

View 전용 또는 Room 전용 아카이브는 재사용 가능한 카탈로그 콘텐츠를 설치합니다. 카탈로그 참조가 해석되면 Locus는 각 View와 Your Room, 그리고 각 View와 목적지 개구부가 있는 모든 Room의 기본 조합을 만듭니다. 명시적인 Experience는 지정한 조합만 대체하며 같은 아카이브의 콘텐츠 또는 내장/가져온 카탈로그에 이미 있는 안정적인 ID를 참조할 수 있습니다.

locusplace.json

{
  "formatVersion": 1,
  "packageID": "place.example-combined",
  "contentVersion": "1.0.0",
  "minimumAppVersion": "1.0.0",
  "contents": {
    "destinationIDs": ["destination.example-view"],
    "spaceIDs": ["space.example-room"],
    "experienceIDs": ["experience.example-combined"]
  },
  "files": [
    {
      "path": "catalog/destinations/destination.example-view/destination.json",
      "byteCount": 214,
      "sha256": "<64 lowercase hex characters>"
    }
  ],
  "contentHash": "<64 lowercase hex characters>"
}

packageID 및 모든 콘텐츠 ID는 최대 128바이트의 안정적인 ASCII 식별자입니다. 문자 또는 숫자로 시작하며 이후에는 문자, 숫자, ., _ 및 -를 사용합니다. 버전은 정확히 세 개의 숫자 성분으로 구성됩니다. 바이트가 변경되는 업데이트는 선언된 콘텐츠 ID를 유지하고 더 큰 다음 값을 사용해야 합니다: contentVersion입니다. 동일한 contentHash 를 가져오면 멱등 작업으로 아무것도 변경하지 않습니다.

contentHash 는 Unicode 경로순으로 정렬한 모든 파일 레코드의 SHA-256입니다. 각 레코드는 다음 UTF-8 바이트를 더합니다:

path NUL decimal-byteCount NUL lowercase-sha256 NUL

이 해시는 JSON 공백 및 ZIP 멤버 순서와 무관합니다. 검증 도구는 선언된 각 파일을 스트리밍으로 읽어 실제 바이트 수, ZIP CRC 및 SHA-256도 검증합니다.

래퍼 필드 레퍼런스

필드 필수 의미
formatVersion 예 정수 1이며 알 수 없는 래퍼 버전은 거부합니다.
packageID 예 이 설치/업데이트 계열의 안정적인 식별자입니다. 파일명이 아닙니다.
contentVersion 예 다음과 같은 숫자 성분 세 개: 1.2.0이며 동일한 ID에서 바이트가 변경되면 올려야 합니다.
minimumAppVersion 예 아카이브를 가져올 수 있는 가장 오래된 Locus 버전이며 세 숫자 성분으로 구성됩니다.
contents.destinationIDs 예 ZIP이 소유하는 고유한 View ID입니다. 다음을 사용하세요: [] 없으면 이 값을 사용합니다.
contents.spaceIDs 예 ZIP이 소유하는 고유한 Room ID입니다. 다음을 사용하세요: [] 없으면 이 값을 사용합니다.
contents.experienceIDs 예 ZIP이 소유하는 고유한 Experience ID입니다. 다음을 사용하세요: [] 없으면 이 값을 사용합니다.
files 예 다음을 제외한 모든 페이로드 파일의 자동 생성된 전체 인벤토리: locusplace.json.
files[].path 예 아카이브 기준 정규 경로: catalog/... 경로입니다.
files[].byteCount 예 압축 해제된 정확한 바이트 수입니다.
files[].sha256 예 압축 해제된 바이트의 SHA-256이며 소문자 16진수 64자입니다.
contentHash 예 위에서 설명한 정규 페이로드 인벤토리의 SHA-256 식별값입니다.

ZIP 내부의 Package v2 메타데이터

완전한 래퍼는 다음을 사용합니다: formatVersion: 1이며 각 destination.json, space.json 및 experience.json 는 다음을 사용합니다: formatVersion: 2입니다. Room v1–v10 숫자를 설명하는 다음 문서: 플랫 호환 형식 레퍼런스 에서 설명한 버전은 별도의 플랫 형식에 속합니다: space.json 입력입니다. 완전한 space.json 을 버전 10으로 변경해서 베이크된 조명 레이어를 사용하려 해서는 안 됩니다. 완전한 패키지에서 선택적 기능은 타입이 지정된 필드로 활성화되며 다음 항목으로 보호됩니다: minimumAppVersion.

모든 패키지 에셋 경로는 ZIP 루트가 아닌 해당 매니페스트가 있는 디렉터리를 기준으로 합니다. 각 참조는 해당 패키지 내부의 일반 파일로 해석되어야 합니다. 기본 Package v2 매니페스트는 향후 버전과 호환되는 메타데이터를 허용하지만, 개별 기능 프로파일에서는 필드 집합을 제한할 수 있습니다. 알 수 없는 필드가 렌더링된다고 가정하지 마세요. 외부 래퍼는 알 수 없는 필드를 거부하며 출처는 공개된 스키마를 따라야 합니다.

좌표는 오른손 좌표계이며 단위는 미터, 위쪽은 +Y, 앞쪽은 −Z입니다. 쿼터니언의 순서는 [x, y, z, w]입니다. 변환에는 다음을 포함할 수 있습니다: translationMeters (유한수 세 개), orientationXYZW (유한수 네 개이며 벡터 길이는 0이 아님) 및 scale (유한한 양수 세 개).

View: destination.json

{
  "formatVersion": 2,
  "id": "destination.example-view",
  "title": "Example View",
  "panorama": {
    "path": "panorama.jpg",
    "projection": "equirectangular",
    "width": 8192,
    "height": 4096,
    "initialYawDegrees": 0
  },
  "provenance": "provenance.json"
}
필드 필수 의미 및 검증
formatVersion 예 정수 2.
id 예 안정적인 View ID이며 디렉터리 및 래퍼 ID와 일치합니다.
title 예 사용자에게 보이는 비어 있지 않은 View 이름입니다.
panorama.path 예 패키지 기준 상대 경로의 최종 JPEG 또는 PNG입니다. 확장자만이 아닌 디코딩된 바이트로 유형을 판단합니다.
panorama.projection 예 정확히 equirectangular.
panorama.width, height 예 실제 디코딩 크기와 정확히 일치하는 양수 크기이며 다음 조건을 충족합니다: width == 2 * height.
panorama.initialYawDegrees 아니요 파노라마 표준 좌표계 내부의 유한한 회전값입니다. 기본값은 0.
sourceImage 아니요 패키지 기준 상대 경로의 선택적 JPEG/PNG 감사 이미지입니다. 렌더링하지는 않지만 완전한 패키지는 타입을 확인하고 디코딩하며 리소스 한도에 포함되는 데이터로 보존할 수 있습니다. 편집 가능한 원본/DCC 파일은 런타임 ZIP 외부에 둡니다.
thumbnail 아니요 패키지 기준 상대 경로의 JPEG/PNG 카탈로그 이미지입니다.
caption 아니요 사람이 읽을 수 있는 설명입니다.
generation.generator 아니요 실제 사용한 생성기 또는 도구 이름입니다.
generation.model 아니요 선택적 모델/워크플로 버전입니다.
generation.generatedAt 아니요 선택적 타임스탬프입니다. RFC 3339 UTC를 권장합니다.
depthLayers[] Package v2에서는 아니요. 공개 ZIP 가져오기에서 지원하지 않음 순서가 있는 깊이 에셋으로 예약되어 있습니다. 제품 런타임과 바이트 수준 검증 도구가 해당 인코딩을 사용하기 전까지 공개 가져오기에서는 이 필드를 거부합니다.
midground.path 아니요 두 경험 모드 모두에서 렌더링하는 런타임 중경 USDZ입니다. 내장, Library 및 가져온 패키지에 동일한 멤버 허용 목록, 구조 및 리소스 한도가 적용됩니다. 다음을 참고하세요: 중경 레퍼런스.
midground.transform 아니요 다음을 위한 선택적 유한 변환: midground.path.
midground.terrainEntities 아니요 다음에 있는 지면 단위의 고유하고 비어 있지 않은 이름: midground.path이며 런타임이 Room 풋프린트 아래 지형의 높이를 다듬는 데 사용합니다.
midground.water 아니요 앱 렌더링 물 선언. 검증된 마스크/노멀 맵 및 다음 문서에 설명된 선택적 물가 데이터를 포함합니다: 필드 레퍼런스.
sky 아니요 검증된 2:1 회색조 마스크를 통해 표시하는 앱 렌더링 절차적 밤하늘(별, 은하수, 선택적 오로라). 마스크: sky.mask이며 다음이 필요합니다: minimumAppVersion >= 1.2.4입니다. 다음을 참고하세요: 하늘 레퍼런스.
gpuTexture, gpuTextures 아니요 사용자 ZIP과 Library 패키지 모두에서 사용할 수 있는 검증된 ASTC KTX1 보조 파일입니다. v1 파노라마 보조 파일에는 다음이 필요합니다: 1.2.3이며 v2 원본 이미지 배열에는 다음이 필요합니다: 1.3.0입니다. 원본 해시, 크기 및 밉 레벨이 일치해야 합니다.
water, clouds, fireflies 아니요 런타임 물(발광 포함), 그려진 구름의 움직임 및 반딧불이 선언입니다. 다음이 필요합니다: minimumAppVersion >= 1.3.0입니다. 참조 에셋과 리소스 한도에는 공통 Package v2 계약이 적용됩니다.
environment.sunPath 아니요 제작된 태양 없는 하늘 및 선택적 마스크 태양 원반. 다음이 필요합니다: 1.3.0 및 제작 확인서.
celestial 아니요 애니메이션 천체 및 참조 텍스처. 다음이 필요합니다: 1.2.4또는 선택적 기능이 요구하는 더 높은 최소 버전(구름 셸 이동/변화에는 다음이 필요합니다: 1.3.0).
nearOrbit 아니요 근궤도 프로파일, 텍스처 에셋 및 콘텐츠에 결합된 대체 표현 증명입니다. v1 및 v2에는 다음이 필요합니다: 1.3.0이며 v2에는 타일 매니페스트, 타일 이미지 및 GPU 보조 파일이 포함됩니다.
splat.variants, splat.ply Package v2에서는 아니요. 공개 ZIP 가져오기에서 지원하지 않음 향후 에셋 참조로 예약되어 있습니다. splat 백엔드가 삭제되어 공개 가져오기에서는 필드 전체를 거부합니다.
splat.metricScaleFactor Package v2에서는 아니요. 공개 ZIP 가져오기에서 지원하지 않음 예약된 계약의 유한한 양수 배율입니다.
splat.groundPlaneOffset Package v2에서는 아니요. 공개 ZIP 가져오기에서 지원하지 않음 예약된 계약의 제작자 지정 지면 오프셋이며 유한수입니다.
splat.placement Package v2에서는 아니요. 공개 ZIP 가져오기에서 지원하지 않음 예약된 계약의 선택적 공통 변환입니다.
environment 아니요 표시되는 View의 밝기, 선택적 소형 SDR Room 조명 및 직사광 기본값은 다음과 같습니다.
audio.path Package v2에서는 아니요. 공개 ZIP 가져오기에서 지원하지 않음 런타임 오디오 파일로 예약되어 있습니다. 제품에서 완전한 오디오 바이트 검증과 재생을 지원하기 전까지 공개 가져오기에서는 이 필드를 거부합니다.
audio.loops Package v2 오디오에 사용됨. 공개 ZIP 가져오기에서 지원하지 않음 예약된 계약에서 반복을 제어하는 불리언입니다.
provenance 가져오기의 경우 예 패키지 기준 상대 경로의 출처 JSON입니다.

완전한 ZIP은 이 바이너리가 실제로 사용하는 필드와 다음과 같이 명시적으로 보존하는 메타데이터를 허용합니다: sourceImage도 콘텐츠의 유형과 리소스 한도를 검증할 수 있을 때 허용합니다. midground 는 공통 런타임 계약의 일부이며 다음이 필요합니다: minimumAppVersion >= 1.2.1. depthLayers, splat 및 레거시 audio 블록의 필드는 현재 사용하는 런타임이 없으며 예약되었거나 폐기되었습니다. 따라서 이 바이너리는 유형을 모르는 경로를 허용하는 대신 출처에 관계없이 거부합니다. 후속 바이너리가 해당 기능을 구현하면 필드의 에셋 참조, 유형 및 한도 검사, 런타임 소비자 및 최소 앱 버전을 공통 계약에 추가해야 합니다. 별도의 공개 가져오기 스위치를 추가해서는 안 됩니다.

12,288×6,144(12K)를 권장하지만 필수는 아닙니다. 8,192×4,096, 6,144×3,072, 4,096×2,048과 같은 낮은 해상도도 정확히 2:1이며 실제 디코딩 크기로 선언하면 유효합니다. 12K라고 표시하기 위해 작은 원본을 확대하지 마세요. 디테일은 늘어나지 않고 메모리만 낭비합니다.

파노라마 좌표는 고정되어 있습니다: u = 0.5 는 yaw 0이자 초기 전방/월드 −Z입니다. u 는 동쪽 +X 방향으로 증가합니다. 이음새는 u = 0/1, yaw ±180°이며 이미지의 맨 위 행은 천정입니다. initialYawDegrees 는 이 좌표계 안에서 이미지를 회전하며 좌표계를 다시 정의하지 않습니다.

선택적 View 조명:

{
  "environment": {
    "imageBasedLight": "thumbnail.jpg",
    "skyGainEV": 0,
    "exposureEV": 0,
    "horizonPitchDegrees": 0,
    "colorGrade": {"contrast": 1.15, "saturation": 1.2},
    "directSun": {"enabled": false, "illuminanceLux": 5000}
  }
}
필드 의미
imageBasedLight Room 지오메트리와 반사 조명에만 사용하는 별도의 2:1 JPEG/PNG입니다. 다음 이미지를 재사용해서는 안 됩니다: panorama.path이며 1024×512를 권장합니다. 생략하면 렌더러가 중립적인 대체값을 사용합니다.
skyGainEV 눈에 보이는 파노라마에만 적용되는 유한한 EV 게인입니다.
exposureEV IBL에만 적용되는 유한한 EV 게인입니다.
horizonPitchDegrees 제작자가 지정한 유한한 수평선 보정값입니다.
colorGrade.contrast 선택적 SDR 표시 파노라마 대비이며 범위는 0.5 ~ 2.0; 1.0 는 중립값입니다.
colorGrade.saturation 선택적 SDR 표시 파노라마 채도이며 범위는 0.0 ~ 2.0; 1.0 는 중립값입니다.
directSun.enabled 별도의 방향광을 제작자가 지정했는지 여부입니다.
directSun.azimuthDegrees, elevationDegrees 유한한 방향 각도입니다. 활성화했을 때 두 값 모두 필수입니다.
directSun.illuminanceLux 유한한 0 이상의 조도입니다.

색 보정은 표시되는 SDR 파노라마에만 영향을 줍니다. 해당 텍스처를 재사용하며 View를 HDR로 바꾸거나 원본에 없는 하이라이트 디테일을 추가하지 않습니다. 비활성화된 태양에도 다음 값을 담을 수 있습니다: 5000 lux이므로 햇빛 추가 는 패키지에서 지정한 꺼짐 상태를 바꾸지 않고 앱 기본값에서 시작합니다.

visibleSkyHDR 및 hdrManifest 은 폐기되어 거부됩니다. USDZ 외부의 EXR은 표시되는 View나 Room 조명 맵으로 사용할 수 없습니다. OpenEXR은 Room 에셋의 USDZ 텍스처 형식으로 여전히 허용되며 모델 내부에서 검증합니다.

Room: space.json

{
  "formatVersion": 2,
  "id": "space.example-room",
  "title": "Example Room",
  "scene": "scene.usdz",
  "thumbnail": "thumbnail.jpg",
  "caption": "A quiet house arranged around a sunlit courtyard.",
  "previewCamera": {
    "yawDegrees": -28,
    "pitchDegrees": -10,
    "zoom": 1.0
  },
  "seatedOrigin": {
    "translationMeters": [0, 0, 0],
    "orientationXYZW": [0, 0, 0, 1]
  },
  "safeHeadVolume": {
    "centerMeters": [0, 1.2, 0],
    "sizeMeters": [1.2, 0.6, 1.2]
  },
  "destinationOpenings": [
    {
      "id": "front",
      "transform": {
        "translationMeters": [0, 1.2, -2],
        "orientationXYZW": [0, 0, 0, 1]
      },
      "widthMeters": 4,
      "heightMeters": 2.5
    }
  ],
  "collision": {"mode": "embedded"},
  "teleportCatalog": {"path": "teleport-points.json", "houseID": "example-room"},
  "quality": {
    "status": "unverified",
    "triangleCount": 0,
    "materialCount": 0,
    "entityCount": 0,
    "maxTextureDimension": 0
  },
  "provenance": "provenance.json"
}
필드 필수 의미 및 검증
formatVersion 예 정수 2.
id 예 안정적인 Room ID이며 디렉터리 및 래퍼 ID와 일치합니다.
title 예 사용자에게 보이는 비어 있지 않은 Room 이름입니다.
scene 예 패키지 기준 상대 경로의 자체 완결형 USDZ입니다. .blend 및 기타 제작 파일은 대신 사용할 수 없으며 다른 위치에도 포함할 수 없습니다.
thumbnail 아니요 Room 카드에 표시하는 패키지 기준 상대 경로의 디코딩된 JPEG 또는 PNG입니다. 선언하면 반드시 존재하고 완전히 디코딩되어야 하며 아카이브 이미지 한도를 공유합니다. 생략하면 기본 기호를 사용합니다.
caption 아니요 다음을 위한 비어 있지 않은 사용자용 문구: 이 Room에 관하여. UTF-8 최대 2,000바이트입니다.
previewCamera.yawDegrees, pitchDegrees 아니요 제한된 3D 미리보기의 유한한 초기 각도입니다. 몰입 공간의 배치에는 영향을 주지 않습니다.
previewCamera.zoom 카메라 사용: 제한된 3D 미리보기의 초기 배율이며 유한한 양수입니다. 재설정하면 제작자가 지정한 이 자세로 돌아갑니다. 뷰어는 지원되는 상호작용 범위로 값을 제한합니다.
seatedOrigin.translationMeters 예 제작자가 지정한 착석 바닥 기준점을 나타내는 유한수 세 개이며 단위는 미터입니다.
seatedOrigin.orientationXYZW 예 유한하고 정규화된 쿼터니언 성분 네 개입니다. 착석 좌표계는 피치나 롤 없이 똑바로 서 있어야 합니다.
safeHeadVolume.centerMeters 예 Room 좌표의 유한수 세 개이며 단위는 미터입니다.
safeHeadVolume.sizeMeters 예 유한하며 반드시 양수인 크기 세 개입니다.
destinationOpenings 예 직사각형 개구부 배열입니다. 독립적인 Room 전용 가져오기에는 정확히 하나가 필요합니다. 개구부가 없거나 여러 개이면 제작자가 지정한 virtual-space Experience가 같은 아카이브에 있어야 합니다.
destinationOpenings[].id 항목당 Experience 조합에 사용하는 고유한 패키지 ID입니다.
destinationOpenings[].transform 항목당 필수 위치/쿼터니언 자세입니다.
destinationOpenings[].widthMeters, heightMeters 항목당 유한하며 반드시 양수인 크기입니다.
collision.mode 예 embedded 또는 separate.
collision.path 조건부 다음의 경우 금지됩니다: embedded이며 다음의 경우: separate: 필수이며 패키지 기준 상대 경로의 자체 완결형 USDZ입니다. 멤버, 텍스처 및 지오메트리는 다음과 동일한 규칙으로 검증합니다: scene입니다. 이 지오메트리와 장면 지오메트리는 Room 리소스 한도를 공유합니다. 이름만 바꾼 제작 원본은 허용되지 않습니다.
quality.status 예 unverified 또는 verified.
quality.triangleCount, materialCount, entityCount, maxTextureDimension 예 제작자가 측정한 0 이상의 값입니다. 0은 미측정을 뜻하며 실제 USD는 별도로 검사합니다.
teleportCatalog.path 예 패키지 기준 상대 경로의 텔레포트 JSON입니다. 선택한 집에 지점이 하나 이상 있어야 하며, 그렇지 않으면 Room을 Virtual Space로 열 수 없습니다. 파일명이 다음 확장자로 끝나지 않아도 필드 역할에 따라 JSON 1 MiB 한도를 적용합니다: .json이며 대소문자 또는 Unicode 파일시스템 별칭으로 우회할 수 없습니다.
teleportCatalog.houseID 예 다음 JSON에서 비어 있지 않은 houses 배열 하나를 선택하는 ID입니다.
spatialAdaptation.wallEntities 아니요 벽을 가리키는 고유하고 비어 있지 않은 USD 엔티티 이름입니다. 이 메타데이터는 벽을 숨기지 않습니다.
spatialAdaptation.roofEntities 아니요 벽 이름과 겹치지 않는 고유하고 비어 있지 않은 이름입니다.
spatialAdaptation.deskEntitiesByTeleportID 아니요 선언된 텔레포트 ID를 제작자가 지정한 비어 있지 않은 책상 엔티티 이름에 연결하는 맵입니다.
provenance 예 패키지 기준 상대 경로의 출처 JSON입니다.

USDZ는 미터 단위의 오른손 좌표계이며 위쪽은 +Y입니다. 지원되는 런타임 USD, 텍스처 및 오디오 멤버만 포함합니다. USDZ 멤버는 압축하지 않고 저장해야 합니다. 검증 도구는 실제 스테이지를 로드하고 평탄화하여 지오메트리를 집계합니다. 작거나 0인 quality 값으로는 한도를 초과하는 모델을 숨길 수 없습니다.

필수 텔레포트 JSON(선택한 집에 지점이 하나 이상 있어야 함):

{
  "houses": {
    "example-room": [
      {
        "id": "work-desk",
        "title": "Work desk",
        "anchorXZ": [0.5, 0.5],
        "sourceFloorOffset": 0,
        "eyeHeight": 1.15,
        "yawRadians": 0
      }
    ]
  }
}

anchorXZ 는 유한하고 정규화된 두 값이며 범위는 0...1; sourceFloorOffset 은 제작된 모델 단위로 유한하며 0 이상입니다. eyeHeight 는 유한한 양수이며 단위는 미터입니다. yawRadians 는 월드 좌표계의 +Y를 중심으로 한 유한한 모델 회전값입니다. 지점 ID는 고유하며 제목은 비어 있으면 안 됩니다.

Experience: experience.json

{
  "formatVersion": 2,
  "id": "experience.example-combined",
  "title": "Example Room · Example View",
  "destinationID": "destination.example-view",
  "spaceID": "space.example-room",
  "supportedModes": ["virtual-space"],
  "composition": {
    "destinationOpeningID": "front",
    "destinationYawDegrees": 0,
    "destinationPitchDegrees": 0,
    "destinationExposureOffsetEV": 0
  },
  "compatibility": {
    "minimumViewerVersion": "1.0.0",
    "requiredCapabilities": ["world-tracking"]
  }
}
필드 필수 의미 및 검증
formatVersion 예 정수 2.
id 예 안정적인 Experience ID입니다.
title 예 사용자에게 보이는 비어 있지 않은 타일 이름입니다.
destinationID 예 이 ZIP에 있거나 이미 설치된 안정적인 View ID입니다.
spaceID 조건부 안정적인 Room ID입니다. 다음에서 필수입니다: virtual-space이며 보통 다음의 경우 생략합니다: room-portal.
supportedModes 예 비어 있지 않으며 중복이 없는 배열입니다. 허용되는 값은 다음뿐입니다: virtual-space 또는 room-portal.
composition.destinationOpeningID 조건부 다음의 경우 필수: virtual-space이며 참조한 Room의 개구부 이름입니다.
composition.destinationYawDegrees 아니요 이 조합의 유한한 하늘 정렬 오프셋입니다.
composition.destinationPitchDegrees 아니요 이 조합의 유한한 하늘 피치 오프셋입니다.
composition.destinationExposureOffsetEV 아니요 이 조합의 유한한 상대 노출 오프셋입니다.
compatibility.minimumViewerVersion 아니요 선언적 최소 뷰어 버전 문자열입니다.
compatibility.requiredCapabilities 아니요 선언적 기능 문자열입니다.

View 전용 및 Room 전용 ZIP은 재사용 가능한 콘텐츠를 설치하고 기본 조합 목록에 참여합니다. 특정 조합의 개구부, 방향, 노출, 제목, 모드 또는 호환성을 바꿀 때만 명시적 Experience가 필요합니다. 참조는 같은 아카이브 안에서 또는 내장/기설치된 안정적인 ID를 통해 해석할 수 있습니다. 해석되지 않는 참조가 있으면 전체 가져오기가 실패합니다.

선택적 기능 및 번역된 레이블

선택적 필드를 해당 View 또는 Room 매니페스트에 추가하고 참조하는 모든 에셋을 그 매니페스트와 함께 넣으세요. 필드 레퍼런스 는 미디어와 마스크, 사운드와 Room 음악, 중경과 바람, 물, 하늘, 구름, 태양 경로, 천체, 근궤도, 블랙홀, 점광원, GPU 텍스처 보조 파일, 좌석과 그룹, 조명, 애니메이션, 비디오 표면, 파티클 및 베이크된 조명 레이어를 다룹니다. 또한 다음을 정의합니다: localizations, provenanceDetail 및 Room의 viewGroundFloorOffsetMeters, viewGroundKeepOut 및 viewMidgroundVisibility 제어 항목입니다.

예를 들어 아래 선택적 필드는 완전한 Room 매니페스트에 추가하며, 래퍼에 다음이 필요합니다: minimumAppVersion: "1.4.4" 이상:

{
  "viewGroundFloorOffsetMeters": 0.2,
  "viewGroundKeepOut": false,
  "viewMidgroundVisibility": "terrainOnly"
}

가져온 콘텐츠, 내장 콘텐츠 및 Library 콘텐츠에 동일한 의미가 적용됩니다. 필드 레퍼런스의 Library 기능 이름은 Library 상품용입니다. 임의로 만든 requiredCapabilities 필드를 다음 파일에 추가하지 마세요: locusplace.json입니다. 완전한 패키지 가져오기 경로는 최소 앱 버전과 타입이 지정된 콘텐츠 자체를 검사합니다.

필수 출처

가져오는 모든 Destination 및 Space는 출처 JSON 문서를 가리킵니다. 제작자/대행사, 라이선스 또는 모든 권리 보유 선언 중 정확히 하나, 요청하는 크레딧, 수정 사항, AI 사용 여부 및 해당되는 경우 AI 제공자를 기록합니다. 원본/소스 에셋 URL은 선택 사항이지만 자격 증명이나 프래그먼트가 없는 HTTPS여야 합니다. 출처가 없거나 크기 제한을 초과하거나 형식이 잘못되면 전체 가져오기가 실패합니다. 다음을 참고하세요: 출처 레퍼런스.

{
  "formatVersion": 1,
  "creatorOrAgency": "Your name or studio",
  "sourcePageURL": "https://example.com/project",
  "originalAssetURL": "https://example.com/original",
  "license": {
    "identifier": "YOUR-LICENSE-ID",
    "name": "Your license name",
    "url": "https://example.com/license"
  },
  "requestedCredit": "Credit line requested by the creator",
  "modificationNotes": "Converted and packaged for Locus.",
  "aiGenerated": false
}
필드 필수 의미 및 제약
formatVersion 예 정수 1.
creatorOrAgency 예 비어 있지 않은 제작자/스튜디오 이름이며 최대 200자입니다.
sourcePageURL 아니요 공개 HTTPS 프로젝트 페이지입니다. 자격 증명이나 프래그먼트는 허용하지 않습니다.
originalAssetURL 아니요 공개 HTTPS 원본 페이지입니다. 원본 파일을 포함하지 않고 출처를 기록합니다.
license.identifier 조건부 비어 있지 않은 식별자이며 최대 100자입니다. 다음과 함께 필수입니다: license입니다. Locus는 에셋의 라이선스를 결정하지 않습니다.
license.name 조건부 비어 있지 않은 이름이며 최대 200자입니다. 다음과 함께 필수입니다: license.
license.url 조건부 공개 HTTPS 라이선스 URL입니다. 다음과 함께 필수입니다: license.
rights.statement 조건부 비어 있지 않은 권리 선언이며 최대 1,000자입니다. 다음 URL rights.url 을 함께 사용하고 다음 항목은 사용하지 않습니다: license.
rights.url 조건부 공개 HTTPS 권리 선언 URL입니다. 다음 중 정확히 하나: license 또는 rights 가 필요합니다.
requestedCredit 예 비어 있지 않은 크레딧 문구이며 최대 1,000자입니다.
modificationNotes 예 비어 있지 않은 준비 메모이며 최대 2,000자입니다.
aiGenerated 예 불리언입니다.
aiProvider 조건부 다음 조건이면 필수이며 비어 있으면 안 됩니다: aiGenerated 은 true이며 false일 때는 금지됩니다. 최대 200자입니다.
importSource 아니요 Locus가 이미지에서 직접 생성하는 View용으로 예약됨: photos, files 또는 url입니다. 타사 패키지에서는 생략해야 합니다.

문서는 64 KiB로 제한됩니다. 에셋을 교체한 뒤 예제의 출처를 그대로 복사하지 마세요. 저장소의 라이선스와 사용자 에셋의 라이선스는 별도 선언입니다.

ZIP은 런타임 배포물이며 제작 백업이 아닙니다. 모든 페이로드 파일은 알려진 Package v2 에셋 필드에서 도달할 수 있어야 합니다. 참조되지 않은 파일은 다음에 있어도 거부됩니다: locusplace.json.files. .blend, .blend1, .blend2, .fbx, .obj, .mtl, .gltf 및 .glb 파일은 선언해도 거부됩니다. 해당 원본 파일은 ZIP 밖에 두세요. Room에는 최종 USDZ를 배포합니다. 패키징된 View에는 최종 2:1 파노라마와 선택적으로 작은 2:1 JPEG/PNG Room 조명 이미지 하나를 배포합니다.

보안 및 리소스 한도

검증은 확장자가 아닌 바이트를 검사합니다. 경로 이탈, 절대 경로나 비정규 경로, 역슬래시, 제어 문자, 대소문자/Unicode 충돌, 심볼릭 링크, 중복 항목, 암호화된 콘텐츠, 미선언 파일, 해시 불일치, 미지원 매니페스트, 잘못된 이미지, USDZ 내부의 유효하지 않은 EXR 텍스처, 잘못된 USDZ 구조, 압축된 USDZ 멤버 및 미지원 USDZ 에셋 유형을 거부합니다. Room 리소스 한도는 시스템 로더가 실제로 해석하는 USD 스테이지를 기준으로 검사합니다. 자체 보고 품질 블록은 제작 메타데이터이므로 실제 집계를 줄일 수 없습니다.

바이트 수준의 이미지 허용 목록은 엄격합니다. 가져온 파노라마, sourceImage, thumbnail 및 imageBasedLight 래스터 필드는 JPEG 또는 PNG여야 하며 USDZ 텍스처는 JPEG, PNG 또는 OpenEXR일 수 있습니다. 그 외에 ImageIO가 디코딩할 수 있는 형식도 암묵적으로 허용하지 않고 거부합니다. USDZ 외부의 3D 제작 형식도 거부합니다. USDZ에는 USD/USDA/USDC, JPEG, PNG, OpenEXR, M4A, WAV 및 MP3 멤버만 포함할 수 있습니다.

한도 v1 한도
다운로드 또는 로컬 아카이브 1 GiB
ZIP 항목 4,096
루트 매니페스트 1 MiB
페이로드 파일 하나 768 MiB
압축 해제된 전체 페이로드 2 GiB
압축률 200:1
가져온 JSON 파일 하나 1 MiB
출처 JSON 64 KiB
이미지 크기 32,768 px
이미지 한 장 1억 5,000만 픽셀
모든 View 이미지 5억 픽셀
USDZ 항목 4,096
USDZ 파일 / 압축 해제 바이트 768 MiB / 1.5 GiB
USDZ 텍스처 크기 / 전체 픽셀 16,384 px / 5억
로드된 Room 지오메트리 삼각형 500만 개, 머티리얼 1,024개, 엔티티 100,000개

파일 및 URL 가져오기

View의 경우 가져오기 페이지에서 사진, 파일 또는 직접 공개 HTTPS URL의 JPG, PNG 또는 HEIC 이미지 한 장을 받을 수 있습니다. Locus는 이미지를 Destination 전용 Package v2 페이로드로 정규화하고 이 임시 패키지에 동일한 검증 도구와 원자적 설치 도구를 적용합니다. 파일과 URL로는 View 및 Room의 완전한 Package v2 ZIP도 가져올 수 있습니다. 방문자가 선택한 콘텐츠 유형이 들어 있다면 결합 패키지도 허용됩니다. 기존 플랫 View/Room ZIP은 계속 호환 입력으로 허용됩니다. 잘못된 아카이브에 locusplace.json 가 있으면 유효하지 않은 완전한 패키지로 거부하며 플랫 파서로 다시 시도하지 않습니다. URL 가져오기는 자격 증명, 프래그먼트, localhost, .local 및 비공개 DNS 결과를 거부합니다. 호스트 이름은 요청당 한 번 확인하며 모든 응답이 공개 주소여야 합니다. TLS 소켓은 원래 호스트 이름을 인증하면서 확인한 바로 그 숫자 IP에 연결됩니다. 리디렉션마다 새 연결 전에 이 주소 확인 및 IP 고정 단계를 반복합니다. 리디렉션은 최대 5회까지 따르며, 선언된 다운로드 크기와 실제 수신 크기를 모두 제한합니다.

검증 및 카탈로그 참조 해석은 동일 볼륨의 비공개 스테이징 디렉터리에서 완료합니다. 라이브러리 전체에 적용하는 권고 잠금으로 인벤토리, 할당량 검사 및 커밋을 순차 처리합니다. 최초 설치는 배타적 원자적 이름 변경을, 업데이트는 원자적 디렉터리 교환을 사용합니다. 실패하면 스테이징을 제거하고 설치된 패키지는 그대로 둡니다.

패키지 검증 및 예제

아래 명령은 게시 및 모든 기능을 갖춘 가져오기에 사용하는 완전한 Package v2 래퍼를 관리합니다. 레거시 플랫 도구는 다음에 계속 문서화되어 있습니다: locus-asset-format.md.

설치하지 않고 두 파일명 중 어느 쪽이든 검증할 수 있습니다:

python3 tools/validate_locusplace.py --current-app-version 1.4.4 MyPlace.locusplace
python3 tools/validate_locusplace.py --current-app-version 1.4.4 MyPlace.zip
python3 tools/validate_locusplace.py --current-app-version 1.4.4 --json MyPlace.locusplace

Python 코드는 표준 라이브러리와 macOS ImageIO를 사용합니다. ImageIO 호출에는 /usr/bin/sips, 그리고 USD 도구 usdchecker 및 usdcat (Xcode/Command Line Tools에 포함)를 사용합니다. ImageIO는 JPEG 또는 PNG 구조 검증 후 모든 픽셀을 디코딩합니다. EXR 검증은 USDZ 내부 텍스처로 한정되며, USD 도구는 실제 Room 스테이지를 로드하고 평탄화하여 측정합니다. 실패하면 0이 아닌 코드로 종료하며, 아카이브, 무결성, Package v2, 출처, 이미지/EXR 및 USDZ를 검사합니다. 설치 및 카탈로그 간 참조 해석의 최종 판단은 visionOS 가져오기 기능이 담당합니다.

편집 가능한 디렉터리를 일반 ZIP으로 패키징합니다. 모든 무결성 레코드를 다시 계산하며 이 검증 도구가 결과를 승인한 경우에만 게시합니다:

python3 tools/pack_locusplace.py --current-app-version 1.4.4 MyEditablePlace MyPlace.zip

임시 또는 무시되는 디렉터리에 실제 View 전용, Room 전용 및 결합 예제 아카이브를 생성한 다음 검증하세요:

python3 examples/locusplace/build_examples.py /tmp/locusplace-examples
for package in /tmp/locusplace-examples/*.locusplace; do
  python3 tools/validate_locusplace.py --current-app-version 1.4.4 "$package"
done

비공개 에셋 다운로드나 유료 서비스 호출 없이 소스에서 예제를 생성합니다. 빌드 도구와 예상 구조는 다음에 설명되어 있습니다: 예제 README.