技术参考

完整 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 文件是一个普通 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.