Prepare community integration base for the weather draft

This commit is contained in:
Bilawal Sidhu committed 2026-09-15 22:31:01 -05:00
commit fa69852323
48 files changed
+5028 -900

No files matched your search

+23 -2
View File
@@ -6,6 +6,20 @@ Voice and HUD snapshots reuse the existing feedState classifier. Analyst follow-
Satellite and local infrastructure layers expose on-demand analyst records through their current factory owners. Analyst counts and ranks explicitly cover only bounded examined loaded records (default 2,000 per new layer, core satellite rows before dense extras); omitted records can change nearest/count and satellite distance is ground distance. Existing tools and result fields remain available.
Director version-5 documents add scene-local data-pack manifests and per-shot
selection. Registered sources acquire bounded, cancellable assets separately from
GeoJSON, PNG and manually played media presentation. Storage paths, attribution
and geographic placement remain distinct; Stop/replacement releases resources.
Import acquires nothing. See [data packs](DIRECTOR-DATA-PACKS.md). Existing scene
content, assets and credit remain unchanged.
Director version-4 documents add named geographic anchors and optional explicit
camera moves with easing, duration and holds. Playback and seek share one
coordinate sampler; navigation/manual input revokes authored motion and pending
holds. Anchor heights and explicit endpoints require the WGS84 ellipsoid
reference. Legacy projects retain their ordinary flights, content and edits.
See [camera directions](DIRECTOR-CAMERA.md).
Realtime voice composes separate connection, response/tool, Radio handoff, input
and audio-meter, cost, viewport-context and diagnostic owners. The existing
controller exports and session/backend contracts remain available. Tool protocol,
@@ -27,8 +41,15 @@ Director's ordered shot runner is exported independently of rendering, UI,
storage and scene content. The existing scene controller supplies an adapter for
visual/layer state, camera travel, media holds and release. Playback cancellation,
preview cleanup, saved projects and all scene assets/attribution are preserved.
Timeline extraction and a shareable scene/data-pack format are planned in
[Director](DIRECTOR.md); those follow-up capabilities are not implemented yet.
Pure authored-time/seek calculations and a playback clock now own timing,
hold deadlines and subscriptions. Stop immediately clears timers and settles
holds; stale tick callbacks cannot publish into a replacement. Registered pack
rules own presentation overrides and Nepal map fallback without changing saved
shots or content. Scene-document validation and legacy migration now have separate
owners. Invalid imports preserve the current project; unreadable saved projects
are protected from fallback writes. Version 5 is the export format, with
zero pitch, low camera heights, scope and detection edits preserved. See [the document contract](SCENE-DOCUMENT.md);
interactions remain planned in [Director](DIRECTOR.md).
Search framing and annotations request semantic map features from an explicit source. The Overpass adapter owns bounded queries, member/tag decoding and request deadlines; callers retain candidate ranking, outline caching, deferred retries and scene placement. Empty, transient and throttled outcomes remain distinct. Traffic sources return road records and installation sources return mapped records with freshness/saturation metadata, so their layers no longer decode upstream elements. ALPR already normalizes its records in the source. Default providers, footprints, road directions, exact-viewport retries and source attribution are unchanged.
+109
View File
@@ -0,0 +1,109 @@
# Director camera directions
Version 4 scene documents can name geographic anchors and describe an explicit
camera move followed by a hold. Existing camera-pose shots still use the ordinary
camera flight. Import, playback, Load, Replay and seek accept the new directions;
a visual anchor/path editor is a later authoring step.
```json
{
"version": 4,
"scenes": [{
"id": "austin",
"title": "Across Austin",
"anchors": [
{ "id": "west", "title": "West viewpoint", "lat": 30.2672,
"lon": -97.76, "alt": 6000, "altitudeReference": "ellipsoid" },
{ "id": "east", "title": "East viewpoint", "lat": 30.2672,
"lon": -97.73, "alt": 7000, "altitudeReference": "ellipsoid" }
],
"shots": [{
"id": "crossing",
"title": "Cross the city",
"durationSec": 4,
"holdSec": 2,
"camera": { "anchorId": "east", "heading": 10, "pitch": -45, "roll": 0 },
"move": {
"from": { "anchorId": "west", "heading": 350, "pitch": -45, "roll": 0 },
"easing": "cubic-in-out"
},
"visual": { "style": "normal" },
"layers": {}
}]
}]
}
```
## One owner for each authored value
An anchor is a scene-local geographic position, with a stable `id`, optional
`title`, latitude, longitude, height and explicit altitude reference. Each scene
accepts at most 1,024 anchors. IDs must be unique within that scene. References to
missing anchors fail validation before replacing a project.
The shot's `camera` is its destination. It can be an inline pose or an
`anchorId` plus orientation. The optional `move.from` uses the same pose/reference
shape. References cannot also carry inline coordinates. They do not form chains.
Heading, pitch and roll belong to each camera pose, so two shots can look in
different directions from the same geographic anchor. Omitted orientation uses
heading 0, pitch −35 and roll 0 degrees.
An explicit move requires `move.from`, `move.easing`, `durationSec` and `holdSec`.
Its duration is 0.2–86,400 seconds; the hold is 0–86,400 seconds. The destination
is not copied into another field. `linear` and `cubic-in-out` are the supported
easings. A shot without `move` retains the existing ordinary flight, even in a
version-4 file. Its destination may also reference an anchor.
Capture continues to create ordinary camera-pose shots. Update Shot stores the
current viewport as an inline destination, preserving an explicit move's start
and easing; it does not change a shared anchor and thereby move other shots.
Editing imported directions and anchors currently means editing the scene JSON.
## Coordinates and altitude
Latitude/longitude use WGS84 degrees. Orientation uses the application's Cesium
heading/pitch/roll convention in degrees: heading rotates from local north,
negative pitch looks down, and zero pitch is horizontal. Camera positions use
meters above the WGS84 ellipsoid, matching `Cartesian3.fromDegrees` and captured
camera poses. These heights are not mean-sea-level elevations or heights above
the visible surface.
Every anchor and every inline endpoint of an explicit move must say
`"altitudeReference": "ellipsoid"`. Ordinary legacy poses without that field
already use the same reference. Terrain-relative and mean-sea-level references
are rejected; no terrain request, default ground estimate or implicit conversion
is made. Authors must provide ellipsoidal heights with enough clearance for their
scene. The format does not promise collision avoidance or terrain following.
During an explicit move, latitude and altitude interpolate between endpoints.
Longitude takes the shortest signed arc across the dateline; heading and roll
also take their shortest signed arcs. An exact 180-degree tie takes the negative
arc. This is an authored coordinate interpolation, not a geodesic or a camera
flight with an automatically raised arc. Endpoints are exact, including zero
pitch. Curved paths and look-at targets are later extensions.
## Time, seeking and cancellation
Load and Replay of an explicit move start at its authored `from` pose, regardless
of the current viewport. Play uses that same start. Both live playback and seek
use `sampleCameraMove`; a seek into the hold uses the exact destination. Backward
seeks do not depend on a prior camera position. Existing scene-pack media/reveal
rules can extend holds as before.
Each active explicit move owns one animation-frame callback. Stop, replacement,
import, teardown, a navigation handoff or manual pointer/wheel input revokes that
callback and settles the move. Navigation also cancels a run during an authored
hold, so the next shot cannot retake the camera. Camera claims still respect
Cockpit's refusal. Already queued callbacks cannot move a replacement scene.
The timing diagnostic includes the active authored camera animation.
The renderer-independent `gods-eye-view/director` export provides
`resolveCameraPose(scene, camera)`, `resolveCameraMove(scene, shot)` and
`sampleCameraMove(move, progress)`. These expect validated/normalized data.
Rendering and frame ownership live in `src/scenes/cameraMotion.js`; the existing
scene controller supplies camera application and lifecycle cancellation.
Version-1/2/3 projects migrate to version 4 without converting their ordinary
shots into explicit moves. IDs, positions, durations, visual settings, packs and
source attribution survive. The bloom scale remains independent of the document
version; version-3 bloom is never interpreted as the older inverted scale.
+114
View File
@@ -0,0 +1,114 @@
# 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.
```json
{
"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, archives and local filesystem bundles are not implemented.
## 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.
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.
This stage provides the manifest/loading boundary; interactive actions and
visual authoring follow separately.
+47 -30
View File
@@ -1,7 +1,7 @@
# Director: reusable scene playback
Director is the scene playback system. The first extraction separates ordered
shot execution from the scene editor and application rendering. This document
Director is the scene playback system. Ordered shot execution, authored timing and playback clocks are separated
from the scene editor and application rendering. This document
also records the proposed next steps; the sharing format and interactions below
are a design plan, not features already available.
@@ -33,9 +33,26 @@ untrusted file validation belongs at the import boundary.
`src/scenes/playbackAdapter.js` connects this runner to the existing
`SceneDirector`. The latter still owns editor state, saved-project import/export,
camera ownership, seeking, clocks and presentation. Pack-specific layer states,
media holds and map preferences retain their current implementation. This first
slice does not make the entire scene controller renderer-independent.
camera ownership and asynchronous load/seek arbitration. Pure seek calculations
live in `src/director/timeline.js`; `src/director/clock.js` owns the run/load/shot
tickers, hold deadlines, snapshots and clock subscriptions. Stop settles pending
holds immediately, and revoked tick callbacks cannot affect a replacement clock.
`getPlaybackTimingState()` exposes copied snapshots and an active-timer count for
lifecycle diagnostics without exposing timer handles.
The `director` export also provides `sceneTimingForShot`, `sceneSeekState`,
`cameraAtProgress` and `createPlaybackClock`. Timeline functions receive duration
and hold resolvers; the clock receives timing, running-state and progress callbacks.
They import no renderer, storage, recipe or dataset.
`src/scenes/shotPresentation.js` prepares layer/seek context and resolves holds
and map preferences through a scene-pack registry. The `scenes` export provides
`createScenePackRegistry({ recipes, adapters })`; pass the result as `scenePacks`
in the SceneDirector constructor options. Trusted adapters can supply
`minimumHoldSec(states)`, `resolveVisual(shot, visual, isMapStackAvailable)` and
`cancelMotion(getLayerModule)`. Default composition registers the existing Nepal
presentation rules. These are code-level composition hooks, not executable
modules imported from scene files. Existing media-owner waits remain bounded.
All authored scenes, assets, IDs, source links, attribution and existing JSON
projects are preserved. The Nepal sequence remains the contribution introduced
@@ -45,31 +62,31 @@ and river coordinates are bundled. See the
## Next changes, in order
1. **Timeline and content separation.** Extract pure duration/seek calculations
and a clock with an explicit lifetime. Move content-specific hold, layer and
presentation rules behind registered scene-pack adapters. Keep existing
recipes and content intact. Test direct load, forward/backward seek, replay,
media timeout and Stop at every pending transition.
2. **Versioned scene document.** Build on the existing version-3 project export
and its importer. Specify a schema and migrations before changing writes.
Keep old imports and local-storage projects readable; reject unsupported
versions without replacing the current project. Include stable scene, shot,
anchor, pack and action IDs. Separate portable authored state from transient
loading state and run diagnostics. Bound document size, collection lengths,
numeric values and nesting; show errors at the affected field.
3. **Camera directions.** Define named geographic anchors and explicit
move/hold segments: start and destination, duration, easing, heading, pitch,
roll and stop duration. State coordinate units, altitude reference and
terrain-relative behavior. Support the current camera-pose shots first;
paths, look-at targets and pauses follow with deterministic seek behavior.
4. **Data packs and placement.** Define a pack manifest with format/version,
source, attribution/license and optional integrity/size metadata. Distinguish
where bytes live (relative files, a URL, or an eventual bundle) from where
features appear (geographic bounds, anchors, transforms and elevation rules).
Start with existing GeoJSON/image/media adapters. Resolve relative paths
against an explicit document base; define CORS, caching, missing-asset and
offline behavior. Fetch only through registered source adapters with bounded,
cancellable loading. Scene files carry no credentials or executable modules.
1. **Timeline and content separation — implemented.** Pure duration/seek
calculations, an owned clock and registered presentation rules preserve
existing recipes and content. Tests cover direct load, forward/backward seek,
replay, bounded media waits and cancellation at pending transitions.
2. **Versioned scene document — implemented for existing camera-pose shots.**
[The scene document](SCENE-DOCUMENT.md) preserves version-1/2/3 imports. Bounded validation
rejects malformed files before replacing current state; legacy migration
preserves IDs, pack bindings and visual edits. Unreadable saved files are
protected from fallback writes. Camera anchors, pack manifests and actions
receive stable IDs with their respective later format extensions.
3. **Camera directions — implemented for pose-to-pose moves.**
[Version 4](DIRECTOR-CAMERA.md) adds scene-local geographic anchors, explicit
start/destination poses, easing, duration and holds. Playback and seek share
the same sampler. Ellipsoidal heights are explicit; terrain-relative input
is rejected. Existing shots retain ordinary flights. Curved paths, look-at
targets and visual authoring are later extensions.
4. **Data packs and placement — implemented for bounded assets.**
[Version 5](DIRECTOR-DATA-PACKS.md) defines a pack manifest with format/version,
source, attribution/license and optional integrity/size metadata. It distinguishes
registered asset directories from geographic coordinates, image bounds and
media anchors. GeoJSON, PNG and native media adapters load with byte/time
limits and explicit ellipsoid heights. Stop and replacement release resources.
Paths resolve against a trusted directory base; missing/offline assets fail
explicitly. Bundles, transforms and terrain-relative placement remain future
extensions. Scene files carry no credentials or executable modules.
5. **Declarative interactions.** Give pickable features stable IDs and connect
clicks to a small action registry: show a text/source card, focus an anchor,
seek a shot, or change an allowed layer state. Define selection feedback,
+105
View File
@@ -0,0 +1,105 @@
# Scene document format
Scenes exports a UTF-8 JSON project. Version 5 adds [data packs](DIRECTOR-DATA-PACKS.md)
and is the write format. Versions 1, 2, 3, 4 and unversioned legacy files migrate on
import without converting their existing shots into authored moves. Unknown versions or unsupported fields are rejected with
a field path before the current project, selection or saved bytes change.
```json
{
"version": 5,
"scenes": [{
"id": "my-scene",
"title": "My scene",
"shots": [{
"id": "my-shot",
"title": "Arrival",
"durationSec": 4,
"holdSec": 1,
"camera": { "lat": 51.5, "lon": -0.12, "alt": 800,
"heading": 0, "pitch": -35, "roll": 0 },
"visual": { "style": "normal" },
"layers": { "traffic": { "enabled": true } }
}]
}]
}
```
## Fields and migration
The root requires `scenes` (an array, which may be empty). Optional root fields
are `version`, `createdAt`, `updatedAt` and `installedBuiltInSceneIds` (string IDs).
Each scene requires a `shots` array; optional fields are `id`, `title`,
`releaseLayerIds`, `appliedShotPacks` and version-4 `anchors`. A pack marker has `id`, optional numeric
`version` and `shotBindings` (original shot title to saved shot ID). These markers
retain the editor's existing pack-update and rename behavior.
Shots accept `id`, `title`, `durationSec`, `holdSec`, `camera`, `visual`, `layers`,
`sourcePackId`, `sourcePackVersion` and version-4 `move`. Scene IDs are unique within the project;
shot IDs are unique within their scene. Existing IDs and pack bindings survive
migration. Missing IDs are generated once and persisted by the next save/export.
Missing titles and optional camera/visual fields receive the editor's defaults.
Empty scenes and intentionally empty projects remain empty.
Camera latitude/longitude and heading/pitch/roll use degrees. Altitude uses
meters above the WGS84 ellipsoid. Import preserves finite heights below
100 meters and zero pitch, which previously fell through to defaults. Anchors and explicit moves require the `ellipsoid` altitude reference;
terrain-relative inputs are rejected. See the camera contract for exact semantics.
Flight durations retain the editor's minimum of 0.2 seconds and its 4-second
fallback for zero; holds may be zero.
Visual fields are `style`, `mapStack`, `styleParams`, `bloom`, `sharpen`, `hud`, and
`detection`, and `scope`. Bloom has `enabled`, `intensity`, `version`; sharpen has `enabled`,
`intensity`; HUD has `visible`, `variant`; detection has `mode`, `density`,
`allocation`, `fadePct` and `outsideOpacityPct`. Scope has `enabled`, `featherPct`.
The latter settings were written by Update Shot but previously lost during
normalization; they now survive import and capture.
Version-1/2 bloom without an explicit scale version uses the original inverted
scale and migrates once to scale 2. The scene document and bloom scale versions
are separate. Legacy numeric strings are accepted for numeric fields.
Layer entries accept a boolean shorthand or `{ "enabled": true, "params": {} }`.
Parameters and style parameters retain nested JSON data. They are interpreted by
already registered components; importing a file does not fetch its URLs, register
modules, evaluate code or apply its layers. Unsupported structural fields are
rejected instead of silently dropping potential edits. Map-stack selection
retains the existing registered-stack behavior.
## Validation limits
`gods-eye-view/director` exports `parseSceneDocument(text)`,
`validateSceneDocument(project)`, `stringifySceneDocument(project)`,
`SceneDocumentError`, `SCENE_DOCUMENT_VERSION` and `SCENE_DOCUMENT_LIMITS`.
Validation is independent of the renderer, storage and recipes. Parsing checks
UTF-8 size before JSON decoding; the file importer also checks file size before
reading it. Migration/defaults live separately in `src/scenes/project.js`.
Limits are 5 MiB, 256 scenes, 10,000 total shots, 10,000 entries per collection,
24 levels of nesting, 200,000 visited values, 65,536 characters per JSON string,
256 characters per field/ID, and 4,096 characters per title. Numeric values must
be finite. Camera limits are latitude ±90, longitude ±180, altitude −12,000 to
1 billion meters, heading/roll ±360 and pitch ±90; durations/holds are at most
86,400 seconds. Post-processing values are bounded and normalized to the existing
slider ranges. Object prototype keys are refused at every depth.
An invalid import leaves the current project and playback untouched. A valid
import cancels and settles pending playback before replacing the project. If
multiple files are read concurrently, only the newest request can replace it.
Disposal prevents a pending import from publishing.
The browser storage key remains `godsEyeView.sceneProject.v2` for compatibility;
that key's suffix is not the document version. An unreadable saved project stays
in storage. The app supplies temporary defaults and a visible warning, but blocks
saving over the original bytes until a valid file is explicitly imported. Export
can preserve temporary edits. Storage writes use the same validation before replacing saved bytes; invalid
edits and storage write failures surface an unsaved toast.
Only authored project fields belong in this file. Runtime clocks, camera flights,
loading progress and run diagnostics remain separate. Camera anchors and authored
moves arrived in version 4; data packs follow in version 5. Declarative
interactions remain a planned extension. No scene assets, source links, licenses or contributor attribution
change with this document boundary.
Version 5 additionally accepts scene `dataPacks` and shot `dataPackIds`, as
defined in [data packs](DIRECTOR-DATA-PACKS.md). Version-4 camera documents
continue to import without adding any packs.