6.5 KiB
Asset Package Contract Design
Product Boundary
outputs/<area-id>/ remains the build workspace. Its package/ child is the only
publishable subtree and may be copied unchanged to another project. The package has
no dependency on the parent directory, repository checkout, absolute local paths,
QGIS, Blender, or the Cesium preview.
outputs/<area-id>/
package/ # publishable boundary
manifest.json # asset-package/v1
models/
<area-id>.glb # compressed complete static scene
roads.glb
buildings.glb
vegetation.glb
water.glb
<area-id>-cesium-preview.html # local verification only
_preview/ # vehicles, routes, dynamic signal runtime
_pipeline/ # staging, manifests and build diagnostics
osm2streets_web_out/, *.gpkg, *.qgz, *.blend, *.png
The package does not duplicate the GLBs: Cesium export and compression target the
package model paths. Build staging lives under _pipeline/ and is removed before a
successful package is published.
Manifest v1
The JSON root uses schema: "osm-asset-package/v1". Required top-level fields are:
| Field | Contract |
|---|---|
schema, packageVersion, areaId |
Stable identity and schema evolution point |
coordinateSystem |
Literal local ENU contract: X east, Y north, Z up, meters |
placement |
WGS84 anchor longitude/latitude/height plus heading correction degrees |
bounds |
WGS84 minLon, minLat, maxLon, maxLat |
assets |
Deterministic list of declared publishable assets |
sceneStats |
Optional descriptive OSM-derived counts, not loading-critical |
Each asset has id, role, category, uri, and defaultLoad. uri is a
forward-slash relative path inside package/; it must not be absolute, start with
/, contain .., or resolve outside the package. Roles are scene for the complete
static scene and layer for separately loadable semantic subsets. Categories are
fixed in v1: scene, roads, buildings, vegetation, water.
models/<area-id>.glb is the only scene entry and defaults to load. Layer GLBs are
optional alternatives for selective loading and default off; consumers must not load
both the complete scene and overlapping layers unless intentionally composing them.
The manifest deliberately excludes source_osm, source_geojson, arbitrary Cesium
JavaScript, vehicle routes, vehicle models, dynamic signal states, countdown models,
preview runtime paths, build timestamps and desktop paths. File digests and sizes may
be added under an optional integrity object only after they are computed from final
compressed files.
Pipeline Design
1. Static export seed
blender/export_cesium.py continues to own static GLB generation, WGS84 bounds,
anchor and semantic collection selection. It must emit data suitable for a manifest
seed, not a preview metadata document. Static traffic-signal geometry already in the
main scene remains part of the static scene; animated traffic signal and countdown
collections are not package assets.
2. Package staging and compression
The build orchestrator owns output paths through normalizeAreaConfig(). It adds
explicit package paths and exports static GLBs to a package staging directory beneath
_pipeline/. Compression works only on staged package files and rewrites the staged
manifest's main GLB URI after successful compression. It never needs to copy or alter
preview HTML.
After path validation, file existence checks, and manifest validation, the package
stage promotes the whole staging directory to outputs/<area-id>/package/. Promotion
is directory-level and replaces a previous package only after the new one is valid.
On failure, the previous published package remains usable and staging is retained or
reported for diagnosis according to existing pipeline failure conventions.
3. Preview adapter
The existing Cesium preview remains a verification tool outside the package. It reads
the package manifest via its relative path, then loads preview-only route, vehicle and
dynamic-signal descriptors from _preview/. Dynamic traffic assets are declared in a
preview-specific descriptor, never appended to package assets. This preserves
existing high-precision cruise validation without making it a downstream requirement.
4. Stage and compatibility behavior
Canonical order becomes intermediates/reimport -> blender -> cesium -> compress -> package -> preview. package is included in the full default build and is callable
explicitly to validate/publish existing staged static exports. preview stays an
optional/verification stage, not a package dependency.
Existing npm run build:area -- --config ... --stages ... remains supported. Root
level legacy GLB/JSON/HTML files are not deleted by the migration; they are not read
as a fallback by the new package contract. A clean full build produces the package as
the canonical downstream asset source.
Consumer Examples
Examples live in repository source, outside individual packages:
- Cesium: fetch
manifest.json, derive the ENU frame fromplacement, apply heading correction, then loadassetsbyuri. - Three.js: load the selected model URL relative to the manifest URL; expose the same ENU placement object to the host application's georeferencing adapter. It must not imply that Three.js alone converts ENU to WGS84.
Both examples load the complete scene and demonstrate selecting a single layer.
They validate that URLs are resolved relative to the manifest rather than the current
page or repository root.
Validation and Rollback
Unit tests validate schema fields, category/role legality, package-relative URI rules, and rejection of omitted/extra files. An integration fixture constructs a minimal package and verifies that Cesium and Three.js example resolvers choose identical relative URLs and placement values. A target-area package test checks final compressed GLB parsing and manifest references.
The package stage writes a stage manifest containing only final published records and
their integrity. Diagnostic checks distinguish missing package, invalid package, and
stale package. Rollback is to the prior package/ directory; legacy preview outputs
remain untouched throughout rollout.
Deferred Decisions
- Rich per-feature semantics, routing graph delivery and simulation inputs are not in v1; they should be introduced through a later schema version only when a downstream consumer requires them.
- Asset coverage improvements are downstream of this contract work.