Files
gods-eye-view/docs/DIRECTOR-DATA-PACKS.md
T
Sameh Khamis fb30287898 Draw the last native world labels through the label overlay
The Directions A and B letters and a data pack's media label were the two
Cesium text labels left, kept by an allow-list in noCesiumLabels.test.mjs.
Both now publish entries to the shared world-overlay host, and the
allow-list is gone, so any Cesium label in src is a test failure.

Directions publishes the letters to the directions-markers source; the
markers keep only their points. A clicked endpoint's letter hangs over the
surface that was clicked. One placed without a click stays hidden until its
ground-floor cell resolves, then requests a render, so a still camera shows
it; a cell that settles with no height falls back to the ellipsoid. Each
position is computed once.

A pack resource handle gains label(entry). The application passes its
shared overlay host to SceneDirector through dataPacks.overlayHost; without
one a media pack fails to load rather than drawing a native label. Each
labelled resource takes a source from a pool and returns it on dispose, as
the host never removes a source, so two presentations of one pack never
clear each other's labels and repeat loads add no sources. A label written
after dispose is ignored. The media label is protected, so it always draws
as before.

Live (Denver, keyless globe): a clicked A and a programmatic B both anchor
on their dots over 1.58 km ground. Documented in docs/CURRENT-STATE.md and
docs/DIRECTOR-DATA-PACKS.md.
2026-11-04 12:30:31 -08:00

6.5 KiB
Raw Blame History

Director data packs

Version-5 scene documents can declare dataPacks on a scene and select them by dataPackIds on each shot. Import validates declarations without loading assets. Loading, seeking or playing a shot acquires only its selected packs. A shot with no pack IDs clears the preceding shot's packs. Existing scene recipes and assets keep their current paths, notices and behavior.

A pack manifest is version 1 and requires an ID, format, source, attribution and placement. Sources describe storage; placement describes geography. Source names refer to trusted application registrations, never scripts to import. A document cannot supply request headers, keys, cookies, endpoints or executable handlers.

{
  "version": 5,
  "scenes": [{
    "id": "example",
    "title": "My geographic notes",
    "dataPacks": [{
      "id": "notes",
      "version": 1,
      "format": "geojson",
      "source": { "adapter": "assets", "path": "my-scene/notes.geojson" },
      "attribution": { "text": "Your name", "license": "Your asset's actual license" },
      "placement": { "altitudeReference": "ellipsoid" }
    }],
    "shots": [{
      "id": "overview",
      "camera": { "lat": 30.2672, "lon": -97.742, "alt": 2600, "pitch": -70 },
      "durationSec": 4,
      "holdSec": 2,
      "dataPackIds": ["notes"]
    }]
  }]
}

For the standalone application, put that asset at public/scene-assets/my-scene/notes.geojson. The registered assets source has an explicit /scene-assets/ base on the application's origin. Importing a file from disk does not grant access to adjacent local files or infer a remote base. Relative paths cannot contain traversal, query strings, fragments, URL syntax, percent escapes or empty segments. Asset directories are served as static files; this is not a new arbitrary-URL proxy.

Formats and placement

  • geojson: a UTF-8 FeatureCollection, served as application/geo+json or application/json. Each feature needs a unique string id. Point, LineString and Polygon (including holes) are supported. Coordinates are WGS84 [longitude, latitude, ellipsoidHeightMeters]; missing height means zero, which can be underground. Supply appropriate heights. Geometry properties are ignored: they cannot select external icons, HTML, styling or scripts. Placement is { "altitudeReference": "ellipsoid" }.
  • image: PNG served as image/png, at most 4096×4096 pixels, checked before decoding. Placement is { "bounds": [west, south, east, north], "height": 300, "altitudeReference": "ellipsoid" }. Bounds must increase and cannot cross the dateline. The image is a horizontal geographic rectangle at that height.
  • media: MP4/WebM video or MPEG/Ogg/WAV/WebM audio, with the matching standard MIME type. Placement is { "anchorId": "media-location" }, referring to a scene-local anchor with explicit ellipsoid height. A labelled marker locates the media; an attribution card provides native, user-operated playback controls. Media never autoplays. Codec support depends on the browser. D5 does not synchronize media time with scene time or embed third-party players.

Pack attribution always includes nonempty text and license; an optional HTTPS url opens as a source link with no opener/referrer. Importing or sharing an asset never changes its license. D5 adds no third-party content and preserves all existing Nepal content and contributor notices.

Optional byteLength specifies the exact expected byte count; optional sha256 is a lowercase hexadecimal SHA-256 digest checked before rendering. There are at most 8 packs per scene, 8 MiB per asset, and 32 MiB of selected assets per shot. GeoJSON additionally allows at most 2,000 features and 50,000 positions. Transforms, terrain-relative placement, terrain collision avoidance, arbitrary GeoJSON styles and archive extraction are not implemented. Explicit local files can be shared through JSON asset bundles.

Loading and resource ownership

The director package export provides createAssetDirectorySource and createDataPackSession. The former receives an explicit trusted HTTP(S) directory baseUrl and optional fetchImpl; it confines every relative asset path to that directory. Cross-origin directories require CORS. Requests omit credentials and referrers, reject redirects, and use cache: 'no-store'. There is no persistent pack cache, offline fallback or silent substitute. A missing, invalid, oversized or integrity-mismatched asset fails the shot's pack load, removes partial results and reports a stable error without exposing a URL. Successful loading leaves the attribution cards visible with the assets.

createApplicationTools({ sceneDataPacks: { sources } }) and new SceneDirector(viewer, style, data, { dataPacks: { sources } }) accept a registry of source functions. Each receives { path, signal, maxBytes } and returns { bytes: Uint8Array, mimeType }. Custom transports must honor the signal, bound reads and return the real MIME type. They remain application code, not scene document fields. Without registrations, referenced sources fail closed. A standalone SceneDirector also passes dataPacks.overlayHost, the world-overlay host that draws pack world text such as a media pack's label (an object with setEntries(sourceId, entries) and clearSource(sourceId)); without it a media pack fails to load. createApplicationTools passes the application's shared host.

The portable session receives format adapters separately. Each adapter receives { pack, asset, anchors, signal } and returns a resource with an idempotent dispose(). Core's scene composition supplies Cesium geometry/image rendering and text-only attribution/native media controls. The session applies a 15-second load deadline and rejects late results, even when an adapter ignores abort.

Stop, replacement, next-shot selection, scene release and destruction cancel pending work, remove owned entities/cards, stop media and revoke object URLs. Run completion releases packs with its run signal. Direct LOAD and seek retain packs until the next operation or Stop. Resources are reacquired per shot; there are no disabled pack refresh loops. getDataPackState() returns copied status and resource counts for lifecycle diagnostics.

Run node scripts/qa-director-packs.mjs against a credentialed local server to exercise the real import/load/seek/Stop path with self-authored synthetic assets. See actions and authoring/sharing for the controls built on this manifest/loading boundary.