mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-14 15:22:21 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
72d9f91ad6 | ||
|
|
fda54f6611 | ||
|
|
0760733780 | ||
|
|
6b4b9e43c8 | ||
|
|
c16bfa5abd | ||
|
|
22bdf14be1 | ||
|
|
5aed9ce064 | ||
|
|
96847d5856 | ||
|
|
5eb6515f44 |
No files matched your search
+4
-7
@@ -1,13 +1,13 @@
|
||||
# Data Sources & Attribution
|
||||
|
||||
God's Eye View's **code** is [MIT](LICENSE)-licensed. **The MIT grant covers the source code only — it does NOT extend to third-party data or visual assets.** Every third-party source keeps its own license and terms. This file documents the live and bundled data sources. The bundled 3D models are the project's own procedural fleet models, MIT-licensed with the code ([`public/models/README.md`](public/models/README.md)).
|
||||
God's Eye View's **code** is [MIT](LICENSE)-licensed. **The MIT grant covers the source code only — it does NOT extend to third-party data or visual assets.** Every third-party source keeps its own license and terms. This file documents the live and bundled data sources; bundled 3D-model provenance is recorded in [`public/models/README.md`](public/models/README.md).
|
||||
|
||||
How to read this:
|
||||
|
||||
- **The non-permissive datasets are carved out, not omitted.** Some bundled data (e.g. TeleGeography, CC BY-NC-SA) isn't MIT-compatible. Rather than hide it, we **bundle it with a clear license carve-out** so the app works out of the box — but it stays under the provider's terms.
|
||||
- **If your use doesn't fit a dataset's license, remove that dataset.** Most importantly: TeleGeography is **NonCommercial** — commercial users must delete it (or license it from TeleGeography). It's one self-contained folder.
|
||||
- **Attribution is shown in-app** and listed here. Keep it intact. The required Google/Cesium credit renders on the on-globe credit line (bottom-left, `#cesium-credits`), and every per-layer credit below is registered into the expandable **"Data attribution"** lightbox on that line (`src/data/dataCredits.js` → `viewer.creditDisplay.addStaticCredit`). Both stay visible in clean-view and recording modes.
|
||||
- **The bundled 3D models are the project's own.** Every model under `public/models/` is a procedural fleet model generated by the project maintainers and covered by the repository's MIT license; [`public/models/README.md`](public/models/README.md) describes the set.
|
||||
- **Bundled model attribution lives beside the model files.** [`public/models/README.md`](public/models/README.md) records each shipped model's creator, source, license, and modification status.
|
||||
|
||||
---
|
||||
|
||||
@@ -564,11 +564,8 @@ Global Forecast System (GFS). The `/api/wind` server-side proxy selects the
|
||||
latest available 0.25° cycle, reads its `.idx` inventory, byte-range fetches only
|
||||
the `UGRD`/`VGRD` 10 m GRIB2 messages, optionally adding `TMP` at 2 m or
|
||||
`PRMSL` at mean sea level from the same run and forecast time. It decodes the
|
||||
selected messages with ecCodes (WASM) and resamples them to a compact grid (1° by
|
||||
default) on a worker thread, so a refresh does not stall other API routes, and
|
||||
serves a manifest plus Float32 U/V and optional scalar values. The sampled wind
|
||||
of the current forecast file is kept, so choosing a color field fetches only
|
||||
that field. It is keyless, cached
|
||||
selected messages with ecCodes (WASM), resamples to a compact grid (1° by
|
||||
default), and serves a manifest plus Float32 U/V and optional scalar values. It is keyless, cached
|
||||
per cycle for an hour, and is a **forecast, not an observation**: the particles
|
||||
show model flow, not measured wind. The renderer bakes bounded curves through
|
||||
the sampled field and animates their phase on the GPU, with a canvas fallback.
|
||||
|
||||
@@ -56,6 +56,7 @@ In short: the MIT grant does not extend to any third-party data. See
|
||||
DATA_SOURCES.md for the full per-source license + attribution summary, and
|
||||
remove any dataset whose terms don't fit your use.
|
||||
|
||||
The 3D models under public/models/ are the project's procedural fleet
|
||||
models, generated from code by the project maintainers, and are covered by
|
||||
the MIT license above like the source code. See public/models/README.md.
|
||||
The 3D models under public/models/ are also third-party works and are NOT
|
||||
licensed under MIT. They remain under their individual licenses. See
|
||||
public/models/README.md for the author, source, license, modification notice,
|
||||
and attribution covering each model file.
|
||||
@@ -60,7 +60,7 @@ Start with the included data sources, then add your own. Each layer is a separat
|
||||
- **📡 Contacts:** A 250 km roster of everything near your target — step through live aircraft and drop into any cockpit.
|
||||
- **🎯 Click-to-track anything:** Camera locks on, draws a fading trail, surfaces full metadata — and a tracked fire or vessel hands you off to the nearest live camera in one click.
|
||||
- **🖊️ Voice whiteboard:** Speak annotations onto the world — real boundary polygons, marks, and routes.
|
||||
- **🛫 3D fleet:** 121 procedural models drawn life size by type — airliners, business jets, helicopters, drones, ships, buses, trams and trains — and every contact swaps from glyph to 3D model as you close in.
|
||||
- **🛫 3D hangar:** Real per-class aircraft models — 787, ATR-72, Citation, Bell 206, MQ-9 — and a tracked contact swaps from glyph to 3D model as you close in.
|
||||
- **🎨 Reskin reality:** GLSL sensor looks over the normal globe — CRT, NVG, FLIR/thermal, Noir.
|
||||
- **🟩 Detection overlay:** Screen-space bounding boxes and IDs on everything in view.
|
||||
- **🎖️ Military HUD:** Tactical heads-up display with intelligence-style telemetry.
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
- Fix the translations of the strings added since the last review (News,
|
||||
Data Library, Wildlife Sightings, Shipwrecks, Rail, the vessel and orbital
|
||||
cockpits) in all twelve languages: neutral side labels and counts no longer
|
||||
break the sentence, terms follow each glossary, and Traditional Chinese
|
||||
follows Simplified Chinese again (German, @gekh, #1698).
|
||||
@@ -1,8 +0,0 @@
|
||||
- Draw every 3D model from the project's procedural fleet set: 121 models
|
||||
(about 2 MB, MIT like the code) chosen per vehicle by type and drawn life
|
||||
size, replacing the eight third-party aircraft models. Flights, Military
|
||||
Flights and Local ADS-B pick a model by ICAO type, class and emitter
|
||||
category; Vessels, Transit and Rail now draw models too, under the same 3D
|
||||
toggle and distances, a ship at its AIS length and beam and a tram, bus or
|
||||
train in its mode or category colour. The whole set loads once when a layer
|
||||
starts (samehkhamis, #1714).
|
||||
@@ -1,4 +0,0 @@
|
||||
- The Wind server no longer blocks every other request while it decodes a
|
||||
forecast. Decoding runs on a worker thread (up to 400 ms of blocking down to
|
||||
about 4 ms), and choosing an overlay after wind has loaded fetches only the
|
||||
overlay's field (mazy1998, #1717).
|
||||
+16
-21
@@ -1706,7 +1706,7 @@ Applications supply the existing floor/snap, geoid, picking, sprite, camera,
|
||||
trail, focus, readout, context, aircraft presentation and render services.
|
||||
The factory never constructs a second application registry. Configure a source
|
||||
before initialization; replacing it while initialized is rejected. Model loads
|
||||
use the supplied asset resolver, including the up-front fleet set load. Enrichment receives
|
||||
use the supplied asset resolver, including the preload path. Enrichment receives
|
||||
an abort signal and cannot update a later lifecycle after destruction. Existing
|
||||
camera, terrain floor, trail, selection and measured model-size policies remain.
|
||||
|
||||
@@ -2420,9 +2420,8 @@ is validated against Cesium 1.138.0 and must be revalidated on upgrades.
|
||||
|
||||
`scripts/qa-anime-sky.mjs` checks asset readiness, visible Normal sky and
|
||||
Anime band coverage against a Vite dev server.
|
||||
`scripts/qa-sky-model-lighting.mjs` compares a lit fleet airliner
|
||||
(`public/models/fleet/aircraft/a320.glb`) against black and white environment
|
||||
maps in isolated scenes.
|
||||
`scripts/qa-sky-model-lighting.mjs` compares a lit `airplane.glb` against
|
||||
black and white environment maps in isolated scenes.
|
||||
|
||||
## Model atmosphere on Apple Metal
|
||||
|
||||
@@ -3607,22 +3606,20 @@ This is the current runtime/source-of-truth snapshot for the project.
|
||||
> 24.09 m aft (70 % of the model's rendered envelope, so inside it), 2.22 m
|
||||
> below centre (6 %), and 2e-9 m off the centreline.
|
||||
> - **The tracked trail attaches to REAL HULL, aft and below (2026-08-23):**
|
||||
> `FLEET_TRAIL_ANCHORS` (`src/data/fleetTrailAnchors.js`, generated by
|
||||
> `scripts/measure-fleet-trail-anchors.mjs`) holds, per fleet aircraft and
|
||||
> helicopter model and in RAW glTF coordinates (see the transform-chain entry
|
||||
> below), the point of the hull's CENTRELINE PROFILE (its centreline slice)
|
||||
> closest to the aft-belly AABB corner. It is NOT the corner: a bounding-box
|
||||
> corner is empty space (4.80 m off the nearest triangle on the airliner
|
||||
> asset this was first measured on, 6.14 m on the jet), so the trail ended in
|
||||
> mid air beside the aircraft. The head segment
|
||||
> `MODEL_TRAIL_ANCHOR_NATIVE` (`src/data/modelVisualAnchor.js`) holds, per GLB
|
||||
> and in RAW glTF coordinates (see the transform-chain entry below), the point
|
||||
> of the hull's CENTRELINE PROFILE (its y = 0 slice) closest to the aft-belly
|
||||
> AABB corner. It is NOT the corner: a bounding-box corner is empty
|
||||
> space, 4.80 m off the nearest triangle on `airplane.glb` and 6.14 m on
|
||||
> `jet.glb`, so the trail ended in mid air beside the aircraft. The head segment
|
||||
> is drawn from a point behind the aircraft to this anchor, so the anchor must
|
||||
> stay aft (83–96 % of each aft extreme) or the segment enters at the tail and
|
||||
> stops inside the fuselage. `fleetModels.test.mjs` reads the POSITION BUFFERS —
|
||||
> stops inside the fuselage. `modelScale.test.mjs` reads the POSITION BUFFERS —
|
||||
> real vertices and triangles, because accessor min/max cannot tell a corner
|
||||
> from a surface — and re-derives on-hull, aft, lowest-at-its-station,
|
||||
> on-centreline, and the construction itself. Re-measure, never re-guess.
|
||||
> - **The trail anchor rides CESIUM'S transform chain, not a hand-rolled one
|
||||
> (2026-08-23 regression fix):** `FLEET_TRAIL_ANCHORS` stores RAW
|
||||
> (2026-08-23 regression fix):** `MODEL_TRAIL_ANCHOR_NATIVE` stores RAW
|
||||
> glTF coordinates and `modelAnchorWorld()` assembles
|
||||
> `modelMatrix × components.transform × axisCorrection` — the same chain
|
||||
> `ModelSceneGraph` renders with, built from Cesium's own exported
|
||||
@@ -3657,7 +3654,7 @@ This is the current runtime/source-of-truth snapshot for the project.
|
||||
> ENVELOPE, and between them the drawn start slides along the segment so the
|
||||
> visible length grows CONTINUOUSLY from zero. Three earlier cuts are recorded
|
||||
> because their shape matters: testing segment LENGTH against the radius HID
|
||||
> real trail (58 m aft of an airliner's 34.41 m envelope gives a 33.98 m
|
||||
> real trail (58 m aft of `airplane.glb`'s 34.41 m envelope gives a 33.98 m
|
||||
> segment, suppressed, though ~23.6 m of it is open air); CLIPPING at the
|
||||
> envelope and keeping only what lay outside stopped a moving trail visibly
|
||||
> SHORT of the aircraft, since a bounding sphere encloses a lot of empty space
|
||||
@@ -4833,9 +4830,8 @@ activeCameraCardEnabled: true })` may publish it through the retained
|
||||
> - **Flights 3D/cockpit hardening:** the destination-direction cue is an
|
||||
> inline SVG rather than a remotely loaded Material Icons ligature, so a
|
||||
> blocked or late font can no longer expand the literal word `navigation`
|
||||
> across the cockpit. A grounded aircraft stands its fleet model's scaled
|
||||
> clearance (the catalog's `clearance`, measured below the model's origin)
|
||||
> above the ground.
|
||||
> across the cockpit. The grounded `airplane.glb` belly offset is calibrated
|
||||
> to the current asset's measured Y-up bounds (`0.063` native units).
|
||||
> Contact Previous/Next and Live Signals aircraft handoffs now
|
||||
> re-seed the first-person camera anchor at the selected flight immediately;
|
||||
> bounded feed-correction smoothing remains scoped to the same aircraft.
|
||||
@@ -7294,9 +7290,8 @@ pins and share links already supply complete boxes.
|
||||
normal four-samples-per-250-ms budget. Retry timestamps more than the maximum
|
||||
30-second backoff ahead of the current clock are ignored. A smaller rollback
|
||||
can retain a bounded retry delay of up to 30 seconds.
|
||||
- Commercial and military aircraft use the same high-level FLEET model regime: 2D billboards when zoomed out, optional glTF models when closer, controlled by the DISPLAY rail `3D` toggle and `Proximity` / `All` modes. Every model is one of the project's procedural fleet models (`public/models/fleet/`, MIT, 121 GLBs, about 2 MB in all; `public/models/README.md`), chosen per aircraft by `aircraftModelSpec` (`src/data/fleetModels.js`): its ICAO type's entry in `types.json`, else the model of its `classifyAircraft` class for a type the map lacks, else its ADS-B emitter category's, else the default airliner. It is drawn LIFE SIZE: the type's published length over the model's built length (`src/layers/flights/modelSpec.js`, shared by Flights, Military Flights and Local ADS-B), and a grounded aircraft stands the model's scaled clearance above the ground. `classifyAircraft` still picks the 2D icons. The whole set loads once, up front, when a layer that draws it starts (`loadFleetModelSet`, which logs `[Fleet] N/121 models (X MB) loaded in N ms`); models are built from those bytes, never fetched mid-session, and an aircraft stays its billboard until the set has loaded. Textured civilians carry a HEAVY tint, not a light one: `MODEL_COLOR_BLEND_AMOUNT` is `0.94` in BOTH layers under Cesium's `ColorBlendMode.MIX`, so the class colour supplies 94% of the surface and the model's own vertex colour ~6%; military models are flat amber, or emergency red. IR boost raises the blend to a full `1.0`. Under NVG/FLIR (map preset or Cockpit vision) models render unlit flat-white at full alpha and scene fog is disabled (fog otherwise blacks out distant models with the globe hidden); state restores on exit.
|
||||
- Vessels, Transit and Rail draw fleet models under the same DISPLAY rail `3D` toggle, at the same altitude ceiling, caps and add/keep radii as the aircraft (`FLEET_MODEL_POLICY`, `src/layers/flights/policy.js`; `createFleetModelLayer`, `src/data/fleetModelInstances.js`). A vessel's model follows its AIS ship type and is drawn at its reported length and beam (AIS static dimensions A+B and C+D, now carried on vessel rows as `length` and `beam`), standing at the sea surface, heading by true heading then course. A transit vehicle's model follows its layer mode (bus, tram, subway, rail or ferry; a vehicle of `unknown` mode keeps its icon), a train's its rail category and mode (rail, metro or tram). Neither the transit nor the rail sources carry a GTFS `route_type` or a finer mode (monorail, gondola, funicular, cable car), so the set's models for those and their `transit.elevation` lifts are not reached by any live source today. Both stand on the road or rail top they are drawn on, without the 1.5 m `GROUND_FLOOR_LIFT_M` their icons carry, and are painted in their mode or category colour where the model's `_TINT` attribute marks it. A vessel model is clipped at its waterline (one clipping plane per model, at the model origin's horizontal plane), so its hull below the water never shows through a plain globe, which Cesium does not depth-test models against. Under the NVG/FLIR styles (the Flights `irBoost` parameter) these models render unlit flat white, as aircraft models do. Each vehicle's icon stays the visual until its model is loaded, ready and placed; a model is picked as its icon is, and a vehicle drawn as its model keeps its selection card and its place in the detection overlay.
|
||||
- **Aircraft models skip Cesium's dynamic environment map (2026-10-24).** Flights, Military Flights and Local ADS-B pass `environmentMapOptions: AIRCRAFT_ENVIRONMENT_MAP_OPTIONS` (`{ enabled: false }`, `src/data/aircraftModelLighting.js`) to every drawn model. Otherwise each `Model` renders the sky around it and reads it back from the GPU (`readPixels`) when it is first placed, and again whenever it moves more than 1 km, the scene's atmosphere settings change, or (under sunlight dynamic lighting) an hour of scene time passes (`DynamicEnvironmentMapManager`, Cesium 1.138). With the class colour supplying 94% of the surface, the models are lit from Cesium's default spherical harmonics instead, with no specular environment map, so the sky's model-lighting cube map no longer reaches aircraft. `src/data/aircraftModelLighting.test.mjs` pins the option at every drawn model call; every model is built from the fleet set loaded up front, so there is no separate preload.
|
||||
- Commercial and military aircraft use the same high-level FLEET model regime: 2D billboards when zoomed out, optional glTF models when closer, controlled by the DISPLAY rail `3D` toggle and `Proximity` / `All` modes. Since 2026-08-16 (Hangar fleet) models are PER-CLASS: real CC-BY GLBs for light/bizjet/turboprop/widebody/helicopter/uav (`CLASS_MODEL_REAL` in `src/data/aircraftClass.js` — meters-baked, scale 1, per-model belly/radius; provenance in `public/models/README.md`), the shared `airplane.glb` for the remaining civilian classes, and the military layer maps weight classes (real GLBs / 747 heavies / `jet.glb` fastjets, per-model heading offsets, flat amber or emergency red). Textured civilians carry a HEAVY tint, not a light one: `MODEL_COLOR_BLEND_AMOUNT` is `0.94` in BOTH layers under Cesium's `ColorBlendMode.MIX`, so the class colour supplies 94% of the surface and the asset's own texture ~6%. The visual direction is clean light silhouettes with only a weak diffuse contribution from the approved textures, so liveries deliberately do NOT read. IR boost raises the blend to a full `1.0`. Under NVG/FLIR (map preset or Cockpit vision) models render unlit flat-white at full alpha and scene fog is disabled (fog otherwise blacks out distant models with the globe hidden); state restores on exit.
|
||||
- **Aircraft models skip Cesium's dynamic environment map (2026-10-24).** Flights, Military Flights and Local ADS-B pass `environmentMapOptions: AIRCRAFT_ENVIRONMENT_MAP_OPTIONS` (`{ enabled: false }`, `src/data/aircraftModelLighting.js`) to every drawn model. Otherwise each `Model` renders the sky around it and reads it back from the GPU (`readPixels`) when it is first placed, and again whenever it moves more than 1 km, the scene's atmosphere settings change, or (under sunlight dynamic lighting) an hour of scene time passes (`DynamicEnvironmentMapManager`, Cesium 1.138). With the class colour supplying 94% of the surface, the models are lit from Cesium's default spherical harmonics instead, with no specular environment map, so the sky's model-lighting cube map no longer reaches aircraft. `src/data/aircraftModelLighting.test.mjs` pins the option at every drawn model call; the two preload calls only warm the glTF cache and are never drawn.
|
||||
- The DISPLAY-rail `3D` toggle is the user-facing activation path for both aircraft layers. Their small approved GLBs build their render resources without Cesium's frame-spread job queue, preventing continuous Photorealistic 3D Tiles streaming from starving model readiness; model caps, tracking, camera, and fallback billboards are unchanged.
|
||||
- **The `3D` toggle DEFAULTS ON in `proximity` on a first run.** Proximity is itself the budget — models appear only below `MODEL_ALT_CEIL_M` and only for the nearest `MODEL_MAX` in view — so the default costs nothing at globe scale, and `all` remains a deliberate opt-in. A fresh boot runs NO layer-state restoration (`LayerStateCoordinator.start()` returns early with neither a share payload nor stored state), so four independent initializers decide what a first-run operator sees and must agree: `booleanOption('models3d', 'e', true)` in `src/data/layerState.js`, `_models3dEnabled = true` in BOTH flight layers, `this._models3dEnabled = true` in `src/ui/aircraftDisplay.js`, and the `active` / `visible` classes on `#models3d-toggle` / `#models3d-mode-row` in `index.html`. All four are pinned together in `src/data/layerState.test.mjs`. Explicit state still wins: because the codec omits default-valued options, `models3d: false` is now what travels in a link (`lo=…f.e.0`) and restores OFF at both aircraft layers. **Consequence for returning users:** a stored `gev:layer-state:v2` blob is a FULL options snapshot, so a session that wrote one before this change carries `models3d:false` and keeps 3D off until the operator flips it (or clears the key) — the durable snapshot is treated as the recipient's own state, by design.
|
||||
- **Consequence of the flip on the recorded tracked/fleet inversion:** the 150–800 km band where surrounding contacts draw as models while the SELECTED one is still a glyph is now what an operator sees WITHOUT arming anything. The inversion itself is unchanged and still deliberate (see `src/data/trackedModelRegime.js`); only its reachability changed.
|
||||
|
||||
@@ -0,0 +1,322 @@
|
||||
# Slowdown audit, November 2026
|
||||
|
||||
A sweep of `main` (`c02ede3bb`, 13 November 2026) for bugs that freeze the page
|
||||
or hold the frame rate down. This page lists what was found, why it happens and
|
||||
how to fix it, and names the pull request that carries each fix.
|
||||
|
||||
[PERFORMANCE.md](PERFORMANCE.md) is the measured baseline of a healthy build;
|
||||
this page is the list of things that fall outside it.
|
||||
|
||||
## How it was measured
|
||||
|
||||
- Keyless dev server, headless Chrome at 1440 x 900 on Apple silicon (Metal
|
||||
through ANGLE), default globe map.
|
||||
- Per scenario: load, a spell at rest, scripted drags and wheel zooms, then a
|
||||
settle. Long tasks were counted with a `PerformanceObserver`, the hot function
|
||||
named from a CPU profile, and `globe.getHeight`, `scene.sampleHeight`,
|
||||
`scene.pick` and friends wrapped to count calls and time.
|
||||
- A long task is one main-thread task over 50 ms. With no layers on, the
|
||||
baseline is two at load (longest about 240 ms) and none afterwards, with zero
|
||||
frames rendered while the camera is still.
|
||||
- Four profiling sessions ran on one machine at the same time, so absolute
|
||||
timings carry some noise. Ratios against the baseline are what to read.
|
||||
|
||||
Nothing here was measured on Google Photorealistic 3D Tiles, on a discrete or
|
||||
integrated PC GPU, or with keyed feeds (AISStream, FIRMS, TomTom). Those rows
|
||||
are marked "read in code".
|
||||
|
||||
## Findings and fixes
|
||||
|
||||
Worst first. "Fix" names the pull request that carries the fix.
|
||||
|
||||
### Measured
|
||||
|
||||
| # | Where | What happens | Fix |
|
||||
| ---: | --- | --- | --- |
|
||||
| 1 | Bike Share, local data layers, Transit, Rail | 18 s freeze switching Bike Share on over New York (2,519 stations); 2.7 s on Data Centers; multi-second freezes with Transit while zooming | #1688, #1689 |
|
||||
| 2 | Shipwrecks | 3 to 5 s freeze when the markers are built over loaded terrain; a share link with the layer on held the loading screen for 22.9 s in one run | #1703 |
|
||||
| 3 | Camera | Rendering stops until reload: at a whole-globe view looking straight down, pan a few times, then scroll one notch | #1704 |
|
||||
| 4 | Street Traffic | Zooming at 250 m over Manhattan: 25 long tasks in 24 s, longest 746 ms, 6.6 s in total | #1705 |
|
||||
| 5 | ALPR cameras | Depth samples inside the overlay paint, repeated on every re-enable: 240 samples and about 1 s across eight toggles. A first-sample freeze of up to 1.9 s was seen in the sweep but not on a second day | #1706 |
|
||||
| 6 | Wind | First zoom after load: up to 14 long tasks (longest 414 ms). Re-measured as one-off shader links, not a standing cost: see below | none proposed |
|
||||
| 7 | Submarine cables | About 2 s of long tasks on load, heap briefly at 1 GB, about 0.5 s again on each re-enable | #1707 (first step), #1722 (batched primitives) |
|
||||
| 8 | Live Flights at whole-globe view with detection labels | Fine on the test machine; at 4x CPU throttle, 8 fps with 143 long tasks in 15 s | #1708 (fleet pass), #1719 (overlay) |
|
||||
| 9 | Radio | 7 to 10 long tasks when the directory loads, longest 447 ms | #1709 |
|
||||
| 10 | Pointer pick | Not reproduced on a second look: see below | none needed |
|
||||
| 11 | CCTV | A still-image camera holds continuous rendering at 60 frames a second although its picture changes about every 10 s | #1710 |
|
||||
|
||||
### Read in code
|
||||
|
||||
| # | Where | What happens | Fix |
|
||||
| ---: | --- | --- | --- |
|
||||
| 12 | `/api/firms` | The whole fire set is filtered, serialised and sent uncompressed on every request; 15 to 55 MB estimated in a heavy season | #1711 |
|
||||
| 13 | AIS store | Both vessel maps are walked on every position message, and sorted whole once past the cap | #1712 |
|
||||
| 14 | Satellite clouds on the 3D Tiles map | A CPU pass over a 4096 x 2048 image, 90 to 180 ms measured on a synthetic canvas, twice in a row | #1713 (canvas path), #1721 (shader) |
|
||||
| 15 | NVG and FLIR styles | Over 100 texture reads per pixel, and 60 renders a second while the style is on. Measured afterwards: the reads cost 0.4 ms a frame at 1440 x 900 and 1.2 ms at 2560 x 1440 | #1718 |
|
||||
| 16 | Wind server | Full 0.25 degree GRIB fields decoded on the event loop. Measured afterwards: 68 ms blocked per warm refresh, about 250 ms on the first, about 400 ms when all six keys refresh together | #1717 |
|
||||
| 17 | Imported geo files and other per-feature ground clamps | Measured afterwards: imported files do not freeze; see below | none needed |
|
||||
|
||||
## Cause and fix, per finding
|
||||
|
||||
### 1. Terrain height reads
|
||||
|
||||
`globe.getHeight` casts a ray against the mesh of the tile under the point, and
|
||||
`scene.sampleHeight` renders a depth pass. Transit asked for every trail fix of
|
||||
every vehicle several times per poll; Bike Share sampled every station in one
|
||||
go. The fix keeps heights per point in one shared reader with a read budget
|
||||
(`src/services/terrainSurface.js`) and spreads the depth samples across frames.
|
||||
|
||||
### 2. Shipwrecks
|
||||
|
||||
`rebuild()` in `src/layers/shipwrecks/index.js` adds 7,958 billboards with
|
||||
`heightReference: CLAMP_TO_GROUND`. Each constructor runs
|
||||
`Billboard._updateClamping`, which intersects a ray with the terrain mesh,
|
||||
synchronously: 4.8 of the 4.9 s. The cost is only paid when terrain is loaded
|
||||
at the time the markers are built, so a cold start with the layer in the URL
|
||||
sometimes escapes it.
|
||||
|
||||
Fix: do not clamp. Wrecks are at sea and the markers already ignore the depth
|
||||
test, so place them on the ellipsoid with `HeightReference.NONE`.
|
||||
|
||||
### 3. Camera: rendering stops after pan then zoom
|
||||
|
||||
Pure Cesium; no application code is involved. Above 1,000 km,
|
||||
`ScreenSpaceCameraController` `handleZoom` rotates the camera about the cross
|
||||
product of the picked point's normal and the screen centre's normal whenever
|
||||
their dot product is between 0 and 1. With the pointer on the exact centre pixel
|
||||
the two are the same vector, yet `n · n` often rounds to `0.9999999999999999`,
|
||||
so the check passes with a zero axis. `Camera.rotate` then throws
|
||||
`DeveloperError: normalized result is not a number` from
|
||||
`Scene.initializeFrame`, outside the scene's own try/catch, so
|
||||
`scene.renderError` never fires and Cesium stops its render loop for good. The
|
||||
pans in the first reproduction only moved the camera to a pose where the
|
||||
rounding goes that way.
|
||||
|
||||
Fix: make `camera.rotate` ignore a zero or non-finite axis, and recover from any
|
||||
stopped loop by restoring the last drawn camera pose and restarting it a bounded
|
||||
number of times before showing Cesium's error panel.
|
||||
|
||||
### 4. Street Traffic road loading
|
||||
|
||||
Three costs in one task after the detail tiles arrive, in
|
||||
`src/layers/traffic/source.js`:
|
||||
|
||||
- `outsideDetailTiles` clips every coarse z12 road against every loaded detail
|
||||
tile (up to 16) for four regions.
|
||||
- The composed set is then handed on with `replace: true`, so
|
||||
`ingestion.js` parses every road again although each tile was parsed as it
|
||||
streamed.
|
||||
- `parseRoads` (`model.js`) asks `cachedGroundFloor` once per coordinate, and
|
||||
each call builds several string keys.
|
||||
|
||||
Fix: clip once per coarse tile against the detail tiles' union box and slice the
|
||||
work across frames (or do it in the vector-tile worker); reuse the roads parsed
|
||||
while streaming and parse only the clipped coarse remainder; look the floor up
|
||||
once per floor cell within a parse.
|
||||
|
||||
This is separate from the one-viewport-tile-at-a-time loading recorded in
|
||||
[KNOWN-ISSUES.md](KNOWN-ISSUES.md).
|
||||
|
||||
### 5. ALPR cameras
|
||||
|
||||
`refineAnchors` and `anchorFor` in `src/layers/alpr/overlay.js` call
|
||||
`scene.sampleHeight` from the overlay's paint, four per paint. Each is a depth
|
||||
render and a `readPixels`; the first one also compiles the pick shader. Results
|
||||
are kept on the entity, so a rebuild or a re-enable samples everything again.
|
||||
|
||||
Fix: on a terrain globe read `globe.getHeight` through the shared terrain reader
|
||||
instead of sampling; keep the answers in a map keyed by camera that outlives the
|
||||
entities; move what sampling remains out of the paint into a queue of one per
|
||||
frame.
|
||||
|
||||
### 6. Wind
|
||||
|
||||
The first reading blamed the layer's 916,476 vertices for slow depth reads
|
||||
during zoom. Measuring again did not support that: depth reads cost the same
|
||||
with and without Wind, hiding every wind primitive left pick time unchanged, and
|
||||
the stalls appear on the first zoom only, as shader programs link (seven
|
||||
programs, about 0.5 s, long tasks up to 166 ms). Later zooms had none.
|
||||
|
||||
The roughly 30 renders a second are the animation itself. It is already capped
|
||||
at 30 Hz and stops when paused, hidden, out of view or under reduced motion;
|
||||
lowering the rate would change how the layer looks. `disable()` releases the
|
||||
baked geometry on purpose, at the price of one task of about 130 ms on
|
||||
re-enable.
|
||||
|
||||
A third look, timing every program link on a preview build, settled it: Wind
|
||||
owns two shader programs, both link during load in 9 to 18 ms, and none ever
|
||||
linked during a zoom. The programs that do link on a zoom are Cesium's own
|
||||
globe-surface variants, with Wind on or off, and Cesium links them
|
||||
synchronously. No fix is proposed.
|
||||
|
||||
### 7. Submarine cables
|
||||
|
||||
`src/layers/submarineCables/ingestion.js` loads both collections through
|
||||
`Cesium.GeoJsonDataSource` with `clampToGround`. Switching the layer on is one
|
||||
task of about 1.4 s, and 1.2 s of it is Cesium reading the terrain height for
|
||||
the 1,917 ground-clamped landing markers, all created in the first frame,
|
||||
including the ones behind the globe.
|
||||
|
||||
Fix, first step: start the landing markers hidden and let the existing horizon
|
||||
sweep show the visible ones a few dozen per frame.
|
||||
|
||||
Fix, second step: draw from batched primitives in place of the entity data
|
||||
sources: one ground polyline primitive for the lines, one billboard collection
|
||||
for the landing markers, one point collection and one static polyline primitive
|
||||
for the reference stems, all kept while the layer is off. That removes the
|
||||
visualiser tasks, the stall on switch-off and on re-enable, and about 900 MB of
|
||||
heap. The first switch-on still links shaders and builds the ground-line
|
||||
geometry once.
|
||||
|
||||
### 8. Live Flights at whole-globe view
|
||||
|
||||
Two costs that scale with the 7,500 aircraft of a full poll:
|
||||
|
||||
- The fleet pass (`src/layers/flights/rendering.js`, every 80 ms) dead-reckons
|
||||
each visible aircraft and asks `cachedGroundFloor` for it, including aircraft
|
||||
at cruise altitude that can never touch the floor. Each lookup formats numbers
|
||||
to strings several times and rewrites a cache entry: 40% of the busy time.
|
||||
- The detection overlay (`src/data/detection.js` `_drawOverlay`) collects every
|
||||
detectable object and strokes every bracket on every frame.
|
||||
|
||||
Fix for the first: skip the floor path for a contact clearly above any terrain,
|
||||
make the floor-cell key a number, and stop promoting the cache entry on every
|
||||
read.
|
||||
|
||||
The second turned out smaller than it looked. The bracket strokes are already
|
||||
one path per colour, and collecting the objects is about 3 ms of a 56 ms frame
|
||||
at 4x throttle once the first fix is in. What costs is the per-object loop in
|
||||
`_drawOverlay` (projection, occlusion, alpha, twelve path calls per bracket).
|
||||
|
||||
Fix for the second: keep what a sweep built and reuse it on the next paint when
|
||||
the view and every contact are exactly what it was built from, compared value
|
||||
by value so no layer has to announce a change. Between two fleet passes most
|
||||
paints qualify, which cuts frame work by a fifth to a third on a still camera
|
||||
at full speed. At 4x throttle a frame outlasts a fleet pass, no paint
|
||||
qualifies, and the gain is a few milliseconds; the fleet pass is what
|
||||
dominates there.
|
||||
|
||||
### 9. Radio
|
||||
|
||||
`stationTags()` in `src/layers/radio/categories.js` splits and normalises a
|
||||
station's tags on every `hasTag` call, and `buildRadioCategories` runs that for
|
||||
every station against every category, twice.
|
||||
|
||||
Fix: normalise once per station at ingest and count categories from that.
|
||||
|
||||
### 10. Pointer pick
|
||||
|
||||
Three sessions saw a single `scene.pick` of 207 to 342 ms during a gesture and
|
||||
attributed it to `pickPointer` in `src/voice/pointerPick.js`. Timing every pick
|
||||
across pointer rests, drags and wheel bursts did not bear that out: of 78 picks
|
||||
with CCTV on over London all but two took 3 to 8 ms, and with five heavy layers
|
||||
on, 81 picks took 5 to 30 ms apart from the first (135 ms). `pickPointer` picks
|
||||
at most once per pointer rest.
|
||||
|
||||
The slow pick is the first pick after a layer appears, once per page load, most
|
||||
likely the pick shader compiling, and its stack is CCTV's own hover pick
|
||||
(`src/layers/cctv/hover.js`). No fix is proposed: removing the dwell pick would
|
||||
only move the one-off cost to the next click.
|
||||
|
||||
### 11. CCTV still-image cameras
|
||||
|
||||
`src/layers/cctv/projection.js` holds continuous rendering for as long as any
|
||||
projected camera is active and redraws the projection every frame.
|
||||
|
||||
Fix: hold only for video. For a still image, request one render when a new image
|
||||
lands or while a focus fade runs.
|
||||
|
||||
### 12. `/api/firms`
|
||||
|
||||
`server/providers/firms.js` builds the payload and calls `JSON.stringify` per
|
||||
request, with no kept body and no compression, and the client refetches every
|
||||
ten minutes.
|
||||
|
||||
Fix: keep the response bytes and their gzip and serve those, as the OpenSky
|
||||
provider does. The route filters to the trailing 24 hours at serve time, so the
|
||||
bytes can only be reused while that filter keeps the same records (about a
|
||||
minute at a time): bursts and several clients gain most, and every response is
|
||||
about seven times smaller.
|
||||
|
||||
### 13. AIS store
|
||||
|
||||
`server/providers/vessels/ais-store.js` calls `pruneAisStreamCache()` for every
|
||||
message; the static-data map is never pruned.
|
||||
|
||||
Fix: prune on a timer, evict in insertion order, and drop a vessel's static
|
||||
entry with the vessel.
|
||||
|
||||
### 14. Satellite clouds on the 3D Tiles map
|
||||
|
||||
`src/layers/weather/infraredImage.js` runs `getImageData`, a per-pixel power
|
||||
curve and `putImageData` over the whole canvas.
|
||||
|
||||
Fix: a 256-entry lookup table applied in place for the canvas path, which
|
||||
halves it; then, for the shell on the 3D Tiles map, the same curve in its
|
||||
fragment shader from a strength uniform, so the image is never read back and a
|
||||
strength change builds no new image.
|
||||
|
||||
### 15. NVG and FLIR styles
|
||||
|
||||
`src/styles/surveillance.js` loops 11 x 11 texture reads per pixel and
|
||||
`src/styles/thermal.js` totals 106. Timed on the GPU, those loops cost about
|
||||
0.4 ms a frame at 1440 x 900 and 1.2 ms at 2560 x 1440 on the test machine:
|
||||
real, but small there. The standing cost is that a style with animated grain
|
||||
holds continuous rendering at 60 frames a second.
|
||||
|
||||
Fix: split the bloom into a row pass and a column pass, which gives the same
|
||||
picture from a fifth to a half of the reads, and step the grain's clock at
|
||||
15 Hz, asking for one frame per step instead of holding the render loop. The
|
||||
grain then changes 15 times a second, which is visible in motion.
|
||||
|
||||
Switching on any style stage at all costs more than the bloom did (1.8 ms a
|
||||
frame at 1440 x 900 for the one-line noir style). That was not looked into.
|
||||
|
||||
### 16. Wind server
|
||||
|
||||
`server/providers/wind/decode.js` decodes about a million doubles per message
|
||||
synchronously, hourly, for six keys.
|
||||
|
||||
Fix: decode on a worker thread, and keep the sampled U and V of the last
|
||||
forecast file per model so that choosing an overlay fetches only its field.
|
||||
|
||||
### 17. Per-feature ground clamps
|
||||
|
||||
`heightReference: CLAMP_TO_GROUND` per feature is also set in
|
||||
`installations/rendering.js`, `alpr/presentation.js`, `ghostMaps/index.js`,
|
||||
`earthquakes/index.js`, `airQuality/index.js`, `news/index.js` and
|
||||
`osmPlaces/index.js`. Their counts were small in these runs (30 to 1,500) and
|
||||
none froze.
|
||||
|
||||
Imported geo files were the one unbounded case, and measuring them cleared
|
||||
them: 20,000 generated points (the import cap) finish in about 1.5 s with a
|
||||
longest task near 0.5 s, because `settleGroundPins` in
|
||||
`src/data/geoFileImport.js` already places pins with `HeightReference.NONE` and
|
||||
resolves heights 256 at a time with a yield between batches. No fix is needed.
|
||||
|
||||
## Checked and fine
|
||||
|
||||
- Start-up of a production build: viewer ready in about 0.5 s, loading screen
|
||||
gone at 1.6 s, three long tasks totalling about 300 ms.
|
||||
- Idle: no frames rendered with no layers on; every render hold was released
|
||||
when its layer went off.
|
||||
- Leaks: all 41 layers toggled three times and ten of them eight times; no
|
||||
timer, scene listener, primitive or data source grew per cycle. The heap
|
||||
levelled off near 320 MB over 7.5 minutes of toggling eleven layers.
|
||||
- At most one long task after load: Military, Satellites (including 11,903
|
||||
Starlink points), Earthquakes, News, Wildlife, GNSS, Drone Airspace, Military
|
||||
Installations, Fire Perimeters, rain radar, lightning, and satellite clouds on
|
||||
the globe map.
|
||||
- Live Flights at city scale with the same 7,500 aircraft loaded: 60 fps, no
|
||||
long tasks.
|
||||
|
||||
## Not covered
|
||||
|
||||
- Google Photorealistic 3D Tiles: nothing was run there. Depth sampling is the
|
||||
only height source on that map, so findings 4, 5 and 17 may be worse.
|
||||
- Live Vessels, FIRMS with data, TomTom traffic, Local ADS-B.
|
||||
- Frame rate on anything but one Apple silicon machine.
|
||||
- One all-layers run over Manhattan grew the heap from 346 to 638 MB in 60 s;
|
||||
whether that is retained was not established.
|
||||
- One Satellites load showed a 5.2 s long task once and never again in four more
|
||||
loads.
|
||||
@@ -6,6 +6,9 @@ specification and should not be used to predict performance on untested systems.
|
||||
The original capture artifacts are not included here, so this page records
|
||||
results rather than defining a runnable benchmark.
|
||||
|
||||
For slowdowns found since, with their causes and fixes, see
|
||||
[PERFORMANCE-AUDIT-2026-11.md](PERFORMANCE-AUDIT-2026-11.md).
|
||||
|
||||
## Test context
|
||||
|
||||
The baseline was captured on 22 August 2026 with these conditions:
|
||||
|
||||
@@ -4,7 +4,7 @@ Catalog: `src/i18n/locales/zh-Hant.json`. General rules: [TRANSLATORS.md](../TRA
|
||||
|
||||
`zh-Hant` is the Simplified Chinese catalog (`zh-CN`, credited to abiyeenzo, #914, and EDIT-Aeterna, #979) written in Traditional characters with OpenCC character conversion. Wording and terminology are the same as in `zh-CN`: change a term in [zh-CN.md](./zh-CN.md) and the `zh-CN` catalog first, then convert. Only the script differs.
|
||||
|
||||
After `s2tw` conversion, fix the characters OpenCC picks wrongly: 年曆史 → 年歷史, 下遊 → 下游, 並道 → 併道, 發佈 → 發布, 公佈 → 公布, 控制檯 → 控制台, and 周 → 週 where it means a week (1 週/秒).
|
||||
After `s2tw` conversion, fix the characters OpenCC picks wrongly: 年曆史 → 年歷史, 下遊 → 下游, 並道 → 併道, 發佈 → 發布, 公佈 → 公布.
|
||||
|
||||
## Style
|
||||
|
||||
|
||||
+17
-30
@@ -1,33 +1,20 @@
|
||||
# Bundled 3D Models
|
||||
# Bundled 3D Model Attribution
|
||||
|
||||
Every 3D model shipped in this directory is one of the project's procedural
|
||||
fleet models under [`fleet/`](fleet/): aircraft, helicopters, ships, buoys,
|
||||
transit and rail vehicles, and a few other airborne and ground objects. They
|
||||
are generated from code by the project maintainers, contain no third-party
|
||||
artwork, and are covered by the repository's [MIT license](../../LICENSE)
|
||||
like the source code.
|
||||
The model files in this directory are third-party visual assets. They are not
|
||||
covered by the repository's MIT source-code license; each remains available
|
||||
under the license listed below.
|
||||
|
||||
| Path | What it holds |
|
||||
|---|---|
|
||||
| `fleet/catalog.json` | Every model by name: its file, category, built length, beam and bounds (metres, in Cesium's Z-up model frame: x along the length with the nose toward −X, y across the beam, z up), the clearance below its origin, and its 2D icon class. |
|
||||
| `fleet/types.json` | Which model draws which vehicle, and at what length: ICAO aircraft and helicopter type codes, ADS-B emitter categories, AIS ship-type and length ranges, GTFS route types, transit modes and rail categories, with the defaults. |
|
||||
| `fleet/aircraft/`, `fleet/helicopters/`, `fleet/ships/`, `fleet/buoys/`, `fleet/transit/`, `fleet/other/` | The models, one GLB each (EXT_meshopt_compression and KHR_mesh_quantization, vertex colours, no textures). |
|
||||
| File | Original work and creator | Source | License | Project modifications |
|
||||
|---|---|---|---|---|
|
||||
| `airplane.glb` | “boeing 747” by [zairiq-123](https://sketchfab.com/zairiq-123) | [Sketchfab model](https://sketchfab.com/3d-models/boeing-747-9b16672038ba48f98e6d80a159044ed9) | [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/) | Substantially modified and optimized for God's Eye View, including geometry/material simplification and coordinate/orientation preparation. The former 24× runtime calibration is baked into the mesh; location, rotation, and scale are applied; the bounding-box centre is at the origin; and the model uses glTF +Y-up with its nose toward local −X. Geometry remains uncompressed so the aircraft asset does not compete with photogrammetry for Draco worker capacity. |
|
||||
| `jet.glb` | “Private Jet” by [Nick the Name](https://sketchfab.com/Nick_The_Name) | [Sketchfab model](https://sketchfab.com/3d-models/private-jet-cbdd1de6ced9461e950eafaa302cc82b) | [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/) | Repackaged as a glTF binary for the project's military-flight visualization. Imported hierarchy transforms are baked into the meshes; location, rotation, and scale are applied; the bounding-box centre is at the origin; and the model uses meter scale, glTF +Y-up, and the shared nose −X convention. Existing materials are preserved. |
|
||||
| `bell206.glb` | “Bell 206 JetRanger” by [terran4627](https://sketchfab.com/terran4627) | [Sketchfab model](https://sketchfab.com/3d-models/bell-206-jetranger-d2f7ba1d671549d4b26aaf834139a1dd) | [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/) | Optimized for God's Eye View: geometry/material simplification, textures resized to 256 px WebP, orientation/scale vertex-baked to real-world meters (Y-up, nose −X), origin centered. |
|
||||
| `c172.glb` | “Cessna 172” by [e737](https://sketchfab.com/e0057537) | [Sketchfab model](https://sketchfab.com/3d-models/cessna-172-64cddaee5aff470682659a8c08525046) | [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/) | Optimized for God's Eye View: geometry/material simplification, textures resized to 256 px WebP, orientation/scale vertex-baked to real-world meters (Y-up, nose −X), origin centered. |
|
||||
| `citation2.glb` | “1990 Cessna Citation, Texture Detailed, Exterior” by [BlenderCommunityHead](https://sketchfab.com/aboodgoudagad) | [Sketchfab model](https://sketchfab.com/3d-models/1990-cessna-citation-texture-detailed-exterior-a78839624fe64900a8352cb23462350a) | [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/) | Optimized for God's Eye View: geometry/material simplification, textures resized to 256 px WebP, orientation/scale vertex-baked to real-world meters (Y-up, nose −X), origin centered. |
|
||||
| `mq9.glb` | “MQ-9” by [IProZenoN](https://sketchfab.com/IProZenoN) | [Sketchfab model](https://sketchfab.com/3d-models/mq-9-fabe963feb354c5584b51f9c470c3f7e) | [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/) | Optimized for God's Eye View: geometry/material simplification, textures resized to 256 px WebP, orientation/scale vertex-baked to real-world meters (Y-up, nose −X), origin centered. |
|
||||
| `b789.glb` | “Boeing 787-9” by [Nobilis 2](https://sketchfab.com/nobilishornet2) | [Sketchfab model](https://sketchfab.com/3d-models/boeing-787-9-b6711e2e698e4e469675c1154a50b7a3) | [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/) | Optimized for God's Eye View: geometry/material simplification, textures resized to 256 px WebP, orientation/scale vertex-baked to real-world meters (Y-up, nose −X), origin centered. |
|
||||
| `atr72.glb` | “ATR 72 - 600” by [Oyan3D](https://sketchfab.com/oyan3D) | [Sketchfab model](https://sketchfab.com/3d-models/atr-72-600-1e1a7186f7444d288675262fcee44744) | [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/) | Optimized for God's Eye View: geometry/material simplification, textures removed with dominant material colors baked into PBR factors (flat “abstracted” style), orientation/scale vertex-baked to real-world meters (Y-up, nose −X), origin centered. |
|
||||
|
||||
How the layers use them:
|
||||
|
||||
- Each layer draws a vehicle with the model its type selects, scaled to the
|
||||
type's published length (a vessel to its reported AIS length and beam), so
|
||||
every model is drawn life size. Ground objects, balloons and obstacles in
|
||||
the `other` category are drawn at the size they are built.
|
||||
- An aircraft model's origin is its axis; it stands that model's scaled
|
||||
clearance above the ground. A ship's origin is its waterline, and a transit
|
||||
or rail vehicle's the road or rail top (a monorail or gondola is raised by
|
||||
its `transit.elevation` entry, for a source that names those modes).
|
||||
- Transit and rail models carry a `_TINT` vertex attribute that marks where
|
||||
the route or category colour is painted.
|
||||
- The whole set loads once, up front, when a layer that draws it starts; no
|
||||
model is fetched while a session runs.
|
||||
|
||||
`src/data/fleetModels.js` reads the set and chooses each vehicle's model;
|
||||
`src/data/fleetModels.test.mjs` checks that every model `types.json` names is
|
||||
in the catalog and on disk, and that no GLB exceeds 3 MB.
|
||||
CC BY 4.0 permits sharing and adaptation, including commercial use, provided
|
||||
appropriate credit is retained, the license is linked, and modifications are
|
||||
identified. These credits do not imply endorsement by the original creators.
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large.
Load diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loaded 100 of 228 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user