技術參考
完整 Locus Package v2 製作指南
本頁內容
狀態:正式的發佈、存儲、組合及完整功能導入契約。Locus 1.2.1 及以上版本可通過文件或公開 HTTPS URL 導入此歸檔,用於 View 和 Room。舊的扁平格式見
locus-asset-format.md 仍可作為兼容輸入。
一個 .zip 或 .locusplace 文件是一個普通 ZIP 歸檔,包含一個或多個 Package v2 Destination(產品名稱為 View)、Space(Room)及 Experience。Locus 自身和支持完整功能的可移植包均使用這一安全發佈與完整性封裝。ZIP 根目錄包含 locusplace.json 和
catalog/ 直接放置,不要再套一層父目錄。
校驗基于歸檔字節與 manifest,而非文件擴展名。完整包會保留其 packageID、內容 ID、
contentVersion 更新流及受支持的 Experience;導入相同內容哈希時為冪等操作,不產生變化。維護中的打包器和校驗器會生成並檢查這一確切格式。
此外層封裝只承載數據,不承載可執行擴展。對於同一個 Locus 二進制文件,運行時使用的每項 Package v2 能力,無論歸檔是內置、從 Library 下載,還是從文件或 URL 導入,內容語義都相同。來源可能影響使用權、自定義導入額度、更新權限、存儲、移除及 UI 標籤,但不會啓用另一套 Room/View schema 或渲染功能。腳本、插件、動態庫及可執行成員不屬於此格式。所有來源均遵守相同的路徑隔離、完整性、資源預算、結構解碼、引用閉合及最低版本檢查。
本指南介紹完整外層封裝及基礎 manifest。 字段參考 介紹可選的 View 與 Room 能力、相關資產、取值範圍及最低 app 版本。 外層封裝 schema 和 來源信息 schema 描述 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 版本,校驗將以此 為準;它不會升級已安裝的 App,也不會賦予 App 新能力。工具保守地默認為 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中。每個已聲明文件都必須存在。歸檔只能包含規定的三個目錄集合,每個文件都必須位於 contents中聲明的包 ID 對應目錄內。Package-v2 清單可向前兼容未知字段;但未知的封裝清單字段、不支持的格式版本、集合及內容模式會被安全拒絕。來源信息遵循其已公開的格式規範。
僅含 View 或僅含 Room 的歸檔會安裝可復用的目錄內容。目錄解析後,Locus 會生成默認配對:每個 View 與“你的房間”配對,也與每個聲明 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,由 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 (四個有限數值組成的非零長度四元數),以及
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 |
否 | 兩種 Experience Mode 都會渲染的運行時中景 USDZ。內置、Library 和導入的包均遵守同一套成員允許清單、結構與資源預算。參見 中景參考. |
midground.transform |
否 | 用於以下內容的可選有限變換: midground.path. |
midground.terrainEntities |
否 | 以下字段中不重復且非空的地面單元名稱: midground.path;運行時據此調整 Room 佔地範圍下的地形。 |
midground.water |
否 | App 渲染的水面聲明,包含經校驗的遮罩/法線貼圖,以及 字段參考. |
sky |
否 | App 渲染的程序化夜空(星星、銀河及可選極光),通過經校驗的 2:1 灰度遮罩 sky.mask;要求 minimumAppVersion >= 1.2.4。參閱 天空參考. |
gpuTexture, gpuTextures |
否 | 經過校驗的 ASTC KTX1 輔助紋理,用戶 ZIP 與 Library 包均可使用。v1 全景輔助紋理要求 1.2.3;v2 源圖數組要求 1.3.0。源文件哈希、尺寸和 mip 層級必須匹配。 |
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 接受該 App 版本實際使用的字段,以及明確保留的元數據,例如 sourceImage;前提是能驗證資源類型及其是否符合資源預算。 midground 屬於公共運行時契約,要求 minimumAppVersion >= 1.2.1.
depthLayers, splat,以及舊版 audio 塊仍為預留或已停用,當前沒有運行時使用方。因此當前二進制文件會對所有來源拒絕這些內容,而不會接受未經類型校驗的路徑。後續二進制文件實現某項能力時,必須將該字段的資產引用、類型與預算檢查、運行時使用方及最低 app 版本一並加入公共契約,不得另設公開導入開關。
推薦 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 |
獨立的 2:1 JPEG/PNG,僅用於照亮 Room 幾何體及反射。不得復用 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 |
有限、非負的照度。 |
調色只影響顯示的 SDR 全景圖。它復用原圖紋理,不會把 View 轉換成 HDR,也不會補回源圖缺失的高光細節。關閉的太陽仍可保存 5000 lux,使得 添加陽光 從 app 默認值開始,不改變包中作者設定的關閉狀態。
visibleSkyHDR 和 hdrManifest 已停用,會被拒絕。外層包中的 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,最多 2,000 個 UTF-8 字節。 |
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 |
是 | 作者填寫的非負測量值。零表示未測量;實際 USD 會單獨檢查。 |
teleportCatalog.path |
是 | 傳送點 JSON,路徑相對於包目錄。選中的房屋必須至少有一個點,否則 Room 無法進入 Virtual Space。其 1 MiB JSON 預算按字段用途強制執行,即使文件名不以下列擴展名結尾: .json;文件系統的大小寫或 Unicode 別名不能繞過此限制。 |
teleportCatalog.houseID |
是 | 用於選擇該 JSON 中一個非空房屋條目的 ID,條目位於 houses 數組中。 |
spatialAdaptation.wallEntities |
否 | 不重復且非空的牆體 USD 實體名;此元數據不會隱藏牆體。 |
spatialAdaptation.roofEntities |
否 | 不重復、非空且與牆體名稱不重疊的名稱。 |
spatialAdaptation.deskEntitiesByTeleportID |
否 | 從已聲明的傳送點 ID 到非空的作者指定桌子實體名的映射。 |
provenance |
是 | 來源信息 JSON,路徑相對於包目錄。 |
USDZ 使用米制、右手坐標系、+Y 朝上,且僅包含受支持的運行時 USD、紋理與音頻成員。USDZ 成員必須以存儲方式寫入,不得壓縮。校驗器會加載並展平真實 stage,統計幾何體;即使 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 以作者模型單位計量,必須有限且非負; 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 |
否 | 聲明式最低 viewer 版本字符串。 |
compatibility.requiredCapabilities |
否 | 聲明式能力標識字符串。 |
純 View 和純 Room ZIP 會安裝可復用內容,並加入默認組合矩陣。只有需要覆蓋某個組合的開口、朝向、曝光、標題、模式或兼容性時,才需要顯式 Experience。引用可指向同一歸檔內的內容,或內置及已安裝的穩定 ID;任何無法解析的引用都會使整個導入失敗。
可選能力與翻譯標籤
將可選字段寫入其所屬 View 或 Room 的清單,並把每個引用資源放在相應清單旁。 字段參考
涵蓋媒體與蒙版、聲音及 Room 音樂、中景與風、水體、天空、雲層、太陽路徑、天體、近軌道、黑洞、點光源、GPU 輔助紋理、座位與分組、燈光、動畫、視頻表面、粒子及烘焙光照層。它也定義了 localizations,
provenanceDetail,以及 Room 的 viewGroundFloorOffsetMeters,
viewGroundKeepOut,以及 viewMidgroundVisibility 控制項。
例如,以下可選字段應放入其他內容已完整的 Room manifest 中,並要求外層封裝的 minimumAppVersion: "1.4.4" 或更高版本:
{
"viewGroundFloorOffsetMeters": 0.2,
"viewGroundKeepOut": false,
"viewMidgroundVisibility": "terrainOnly"
}
這些字段在導入、內置和 Library 內容中含義相同。字段參考中的 Library 能力名稱屬於 Library offer;不要將自行編造的 requiredCapabilities 字段添加到 locusplace.json。完整包導入流程會檢查最低 App 版本和實際的類型化內容。
必填來源信息
每個導入的 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 個字符;應搭配 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 衝突、符號鏈接、重復條目、加密內容、未聲明文件、哈希不匹配、不受支持的 manifest、損壞圖像、USDZ 內無效 EXR 紋理、損壞的 USDZ 結構、壓縮的 USDZ 成員及不受支持的 USDZ 資產類型。Room 預算基於系統加載器實際解析的 USD stage 檢查;作者自報的質量信息只是製作元數據,無法降低這些統計值。
字節級圖像允許清單是嚴格限定的:導入的全景、 sourceImage,
thumbnail,以及 imageBasedLight 柵格圖像字段僅允許 JPEG 或 PNG;USDZ 紋理可用 JPEG、PNG 或 OpenEXR。不會隱式接受其他 ImageIO 可解碼格式。外層包中的 3D 製作格式也會被拒絕。USDZ 僅允許包含 USD/USDA/USDC、JPEG、PNG、OpenEXR、M4A、WAV 和 MP3 成員。
| 資源預算 | v1 限制 |
|---|---|
| 下載文件或本地歸檔 | 1 GiB |
| ZIP 條目數 | 4,096 |
| 根 manifest | 1 MiB |
| 任一資源文件 | 768 MiB |
| 解壓後載荷總量 | 2 GiB |
| 壓縮比 | 200:1 |
| 任一導入的 JSON 文件 | 1 MiB |
| 來源信息 JSON | 64 KiB |
| 圖像尺寸 | 32,768 px |
| 一張圖像 | 1.5 億像素 |
| 所有 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 也支持完整的 Package v2 ZIP,可用於 View、Room,以及包含訪客所選內容類型的組合包。現有扁平 View/Room ZIP 仍可作為兼容輸入。如果格式錯誤的歸檔包含 locusplace.json ,會被視為無效完整包而拒絕,絕不會回退到扁平解析器。URL 導入拒絕憑據、片段、localhost、 .local及非公網 DNS 解析結果。每次請求只解析一次主機名,所有返回地址都必須是公網地址。TLS 連接會連接到解析得到的確切數字 IP,同時驗證原始主機名。每次重定向都會在建立新連接前重新解析並固定地址,最多跟隨五次重定向;聲明大小和實際流式下載大小都受到限制。
校驗與目錄解析在同一卷的私有暫存目錄內完成。整個庫的咨詢鎖會串行處理清單、配額檢查及提交。首次安裝使用排他的原子重命名,更新使用原子目錄交換。任何失敗都會移除暫存內容,並保持已安裝包不變。
包校驗與示例
以下命令維護髮布及完整功能導入所用的完整 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: /usr/bin/sips,以及 USD 工具 usdchecker 和 usdcat (隨 Xcode/命令行工具安裝)。完成 JPEG 或 PNG 結構校驗後,ImageIO 會解碼全部像素;EXR 校驗僅用於 USDZ 內部的紋理。USD 工具會加載實際的房間 USD 場景、展開其圖層並測量幾何數據。任何校驗失敗都會返回非零退出碼。檢查範圍涵蓋歸檔、完整性、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.