Only catalog and the tracked satellite were saved for the layer, so a class
chip lasted until the next reload and no share link carried it. The choice
is now the satellites option `classes`: one letter per class shown
(`sitpd` by default, `0` for none), with Starlink left to `catalog`, and
the layer takes the letters back through setParams. A partial request
(`{debris: false}`) hides only what it names.
Showing only Stations and Imaging by default hid GPS, GEO comsats, Hubble
and the rest of what the layer showed before classes, for every existing
user and saved view. Every class now starts on except Starlink, which stays
off as the DENSE switch was.
The satellites layer now sorts every object into Stations, Imaging,
Telecom, Starlink, Probes or Debris, each with a chip and a live count on
the layer row. Stations and Imaging show by default; the Starlink chip is
the former DENSE catalog switch. Hidden classes keep their points, so a
toggle needs no reload, and they leave the detection overlay and the voice
position lists.
A class comes, strongest evidence first, from CelesTrak SATCAT (object type
and status, served by a new /api/celestrak-satcat/<group> proxy route and
cached for a day), the bundled UCS Satellite Database pack (operator, owner
country and purpose), name patterns for later launches, and the CelesTrak
group. The core catalog also reads the resource, weather, planet, sar and
science groups. Payloads with no evidence of life launched 20 or more years
ago are filed as debris. The UCS pack, its build script and its data credit
are added.
An application built with fewer layers no longer restores, stores or shares a
layer it does not have when a link or saved state from a build that has it
names that layer. LayerStateCoordinator drops unregistered enabled-layer ids
before normalizing, so dependent options (a tracked selection) go with them.
An application with every layer registered is unchanged.
Both reviews of the timeout found that Cesium cannot cancel a full-detail
read: each one given up kept its nine picks traversing every frame, so
stalled tiles piled up a new set every 30 s, while slow but valid answers
were dropped. Raise-only loaded reads then locked in a wrong-high height.
Back to one full-detail read at a time whose answer always applies, and
loaded reads that may adjust a river height but never take it to the sea;
a coarse probe can again lower it partway until the full read lands.
Keeps the test for another ship selected inside the double-click memory,
and corrects CURRENT-STATE: a failed read keeps the height it had.
Before the first full-detail read lands, a loaded-tile read could still
lower a river height partway (27 m to a 15 m bank). Loaded-tile reads now
only raise it; lowering is the full-detail read's to say.
That makes a full read that never lands (stalled tile requests) hold a
wrong height for the whole bridge, so one still running after 30 s is given
up for a fresh one; its late answer is dropped.
Also tests the other half of the double-click memory fix: another ship
selected within the memory is not entered through the first ship's spot.
Before the first full-detail water read lands (it can take many seconds
from cold tiles), a refresh's loaded-tile read with one low probe still
dropped a river height to the geoid. Before that landing, loaded-tile reads
may now find raised water but only a full-detail read lowers it.
CURRENT-STATE also says what the earlier fixes changed: C stays the CCTV
shortcut when the bridge cannot be entered, voice entry is refused on a
bridge, and the ridden ship's trail is hidden with its sprite.
The vessel layer draws other ships at their last AIS fix and does not
advance them, so dead-reckoning radar contacts moved the mismatch from own
ship to everyone else: a 15 kn ferry reported 90 s ago showed ~700 m ahead
of the ship out of the window. Own ship stays centred where the camera
rides; contacts go back to their last fixes, and the query drops the extra
reach and candidates (which could also cut the nearest ship in a crowd).
The radar centred on the ship's last AIS fix while the camera rode that fix
dead-reckoned up to 180 s ahead: at 20 kn about a nautical mile apart, so a
ship already passed still showed ahead. Own ship now sits where the camera
rides and each contact is dead-reckoned to the same moment; the query reaches
past the range for ships that have since moved into it.
Ships with no MMSI each get a key of their own instead of all sharing an
empty one on the scope.
A full-detail water read that sampled nothing (tiles not loaded) fell back
to the geoid, and while a full read ran, a loaded-tile read with one coarse
low probe did the same: on the Seine either dropped the eye ~27 m under the
water until the next read. An empty read is now no answer, and once a
full-detail read has answered only full-detail reads change the height.
The read sequence numbers go: only one full-detail read runs at a time,
so a late read can never be older than one already applied.
Layer display tests no longer re-check Cesium primitives in every layer:
they run on the fake engine, and one Cesium translation check per ground
kind lives in the Cesium engine's ground tests. Their harnesses are shared,
and the fake-engine, Cesium-engine and flights tests that repeated the
contract suite are gone, 340 tests in all.
The press-travel measurement is shared by the selection dispatcher and
CCTV, which loses its ScreenSpaceEventHandler shim and world-click module.
ALPR, installations and bikeshare share one selection keeper and selected
marker write. Layers with their own click rules keep their handlers.
Navara's pulse is a class like the ground pass, the ground and imagery
passes share the surface uniforms, and the colour, log-depth and occlusion
GLSL lives in one chunk module, each caller keeping its depth bias. The
ground suite runs inside the contract suite (--only=ground:), and fixture
and script names say what they test.
Behaviour is unchanged on both engines.
Every layer draws on both engines, so the per-engine availability
machinery always answered yes. The renderer manifest is now the id to
display map plus the wind flow backend; the catalog filter, the voice and
QA-probe refusals and the engine-kind checks go with it. The Navara
notice lists the same layers in the same words.
Paths that read the Cesium viewer behind an engine that is always there
are gone: the Recent Imagery viewer fallbacks, the shell's imagery-host
service (one shared host module remains), the engineless map controller,
viewer gates in voice actions, world packets and camera verbs, the
orientation controls' tracked-entity fallback, and the Bhote Koshi and
FIRMS Cesium-shaped paths. setCameraInputs, which nothing called, leaves
the contract; suspensions remain.
Smaller duplicates go too: one tracker-release helper for navigation and
location, the no-op frame latch, missing-engine guards, one name for the
injected display, flat bikeshare and installations displays, one overlay
host and binder, one name per world-overlay method, and stub-viewer
guards in the Cesium engine. Layers that still read the viewer keep the
shared init(viewer, context) entry.
Behaviour is unchanged on both engines. Viewer lines fall from 849 to
750 and engine-name literals from 32 to 27.
Remove code that nothing in the app, the runners or CI uses:
- the one-off migration compare, look and bench scripts and the vector
ground prototype they measured, with the bench tables in the docs;
- the unused Navara-named shared render modules (polygons, ground picks,
mover bank, ground ring);
- the Cesium-shaped aircraft and vessel test renderers, and the trail,
engineFromViewer and horizon-occluder helpers only they kept alive.
Their tests now run on the production displays over the fake engine;
- Navara's unread diagnostics, fallback ports, dead exports and
parameters, stale effect-chain anchors and the unread capability flags.
The QA scripts share one keyless guard and readiness wait, the session
harness reuses the strict harness's browser flags and block list, and the
harness honours QA_ANGLE and QA_RESERVED_PORTS. The bikeshare fixture
keeps only what its scenario reads. The docs name the engine picker where
it is (VISUAL PRESETS) and drop dated run results.
No behaviour changes on either engine. Navara layer renderer lines fall
from 189 to 0 and viewer lines from 891 to 849.
Prague, Warsaw, Kraków (buses and trams), Poznań, Gdańsk, Rzeszów, Vilnius,
Bucharest, Cluj-Napoca, Iași, Rome, Turin, Venice (buses and waterbuses),
Bordeaux, Montpellier, Rouen, Toulon, Le Havre, Tours, Málaga, Lisbon's city
Carris, Sendai, Johor Bahru, Kota Bharu, Adelaide, Atlanta, Denver, Edmonton,
Halifax and Victoria.
Each entry records its licence, or that none is stated and the Metro
Transit/OVapi basis it ships on. Montpellier and Toulon publish km/h and are
converted. Route ids are read as the rider-facing line; Prague, Bordeaux and
Le Havre trams and Venice waterbuses take their own mode. Adelaide needs
`Accept: */*` to get binary protobuf. Every feed was fetched through the dev
proxy on 2026-11-08.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Keyless GTFS-Realtime feed from Carris Metropolitana, documented in the
operator's public API repository. No licence is stated for the realtime
endpoint (the static GTFS is CC BY 4.0), so it is credited as a courtesy on
the same basis as the Metro Transit and OVapi feeds. The feed publishes km/h,
so a new `speedUnit` registry field lets the proxy convert to m/s. Route ids
wrap the GTFS route id in an area prefix and are read as the line number.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Describe the radial disc envelope, corridor backing and reveal control,
rectangular input pick windows and optional horizon ellipsoid. Record the
launch-pad and Transit restoration and the Street Level and CCTV callers.
Explain synchronous Transit and reveal construction and surface readiness
for classified ground materials after camera changes.
Cesium remains the appearance and interaction reference; this documentation
changes no behaviour. All eleven coupling counts remain unchanged.
With no aircraft tracked, Cockpit can ride the selected AIS vessel. Entry
needs only Live AIS Vessels and a selected vessel; C, double-click and the
entry buttons (reading BRIDGE with a ship icon) enter it, while voice stays
aircraft-only.
The eye sits on the AIS position at a representative bridge height for the
vessel's type family, looks along true heading and moves along course over
ground. The last fix is dead-reckoned for up to 180 s between the layer's
refreshes, and on rivers and lakes the waterline is read from the rendered
surface around the ship rather than the geoid.
The bridge HUD shows speed and course over ground, a straight heading
tape, window mullions, the AIS destination as a reported voyage and a
heading-up radar of nearby ships (3 to 24 NM). The arrow keys look around,
Home or 0 looks ahead again. The vessel layer hides the ridden ship's
sprite and card, ignores scene clicks while held, and returns the camera
to the vessel's map view on exit.
Describe the segment batch lifecycle, per-item picks and styles, and the
single-primitive engine implementations. Document the restored Wildlife
fill and outline and replace the stale no-fill description.
The documentation follows Cesium's stem behavior and original draped
privacy appearance. No coupling count fell or grew; all eleven metrics
remain unchanged.
Move engine request ordering and the single rollback decision into the scene
host. Run handoff, renderer release, candidate acquisition, attachment,
restoration and settling in one transaction. Pass that transaction to nested
parts so unrelated calls wait without putting nested work behind itself.
Keep the engine-switch entry point as a delegating adapter.
Route direct shell attachment and detachment through the same host and remove
the shell queue. Serialize late part registration with attachment and release.
Keep failed-attachment cleanup and renderer release inside the transaction,
including failed restoration. Replacement applications share the transition
owner with fresh parts, and retired applications release their part registry.
A shell used alone creates its own scene host.
Preserve Cesium's picker and history ordering, single recovery, retained layer
session, cockpit restoration, hidden-tab settling and parked-renderer policy.
Navara keeps the same behavior. No user-visible change is intended on either
engine. Keep the existing behavioral assertions and cover concurrent operations,
failed cleanup followed by recovery, retired transaction handles, replacement
startup failure and parked expiry during a switch.
All eleven coupling counts remain unchanged; none fell or grew. Renderer lines
remain 0 and 189, external Cesium import files 3, viewer lines 891, Navara kind
checks 1, engine-sniff calls 0, extension reads 3, ground passes 1, SDK loads 3,
screen-handler files 4 and engine-name lines 32.
Checked on the keyless production build: the engine, Director and layer
handoff switches, app-once, and the rapid, hidden-tab, context-loss,
parked-release, failure-matrix and soak scenarios pass.
Main now ships an Iceland pack that loads the full live Vegagerðin list
(about 500 views) with its CC BY 4.0 credit. The World catalog's 166
Vegagerðin rows point at the same frames under different ids, so every one
of those cameras would be drawn twice. Drop them from the World export and
its loader policy; World is now 2,230 rows and the default catalog limit
7,350 (4,000 shared slots plus 3,350 reserved).
Register Data attribution entries for Ottawa, Québec, TripCheck and MLIT,
as every other CCTV pack has. MLIT's terms ask for the source in the form
"出典:国土交通省 川の防災情報" with the page link, and ODOT asks for
"Camera courtesy of ODOT"; TripCheck partner cameras keep their owner's
name in the label.
The Houston guard test from main checked the old 4,000 default ceiling;
check the 4,000 shared slots instead, like the other pack tests.
Give each scene attachment its own tracked readout, follow subscription,
selected context, active card identity and label-subject cache. Bind layer
context publishers to that attachment and preserve the page selection slot
and existing selection and awareness event payloads. Mirror a clear to the
page only when it clears the page selection. Capture display context
services so retired callbacks cannot publish into a replacement attachment.
Route aircraft, satellite, Local ADS-B and ALPR label refreshes and annotation
card lookup to the attached readout. Remove Local ADS-B contexts before
dropping its outgoing renderer, and mirror context pruning to the page.
Carry the retained page selection through the layer session when an attachment
is released. Adopt it only if the page still selects the same record, seed the
incoming readout on initialization, and replace its retained carrier when the
new display registers its marker. Keep the original page selection timestamp
and avoid a duplicate page selection event. A clear between attachments wins,
and page teardown still clears the selection. Seed the incoming readout from
that retained record without validating the outgoing display's visibility:
FIRMS waits for camera restoration before registering its new display. Keep a
matching selected fire in the refresh set before pruning top-N contexts, so
weaker selected detections retain the page selection too.
Preserve Cesium's label text, selected-card policy, visual anchors and
follow-camera anti-jitter. Navara retains the same shared behavior. There is
no intended user-visible change on either engine. Tests cover simultaneous
follows, identical selection IDs, independent refresh and clear, stale
notifications, destruction, parked reattachment and real layer publication
on the fake and headless Cesium engines. The production aircraft tests also
cover grounded fleet and tracked models, the display floor on both sides of
the zoom boundary, follow-label refresh and cached position reads. The fire
regression exercises the application scene handoff, delayed viewport resume,
top-N pruning, unchanged selection timestamp and deliberate clear on both
engines. These fixes preserve the reference Cesium selection behavior.
All eleven coupling counts remain unchanged; none fell or grew. The counts
remain 0 and 189 renderer lines, 3 external Cesium import files, 891 viewer
lines, 1 Navara kind check, 0 engine-sniff calls, 3 extension reads, 1 ground
pass, 3 SDK loads, 4 screen-handler files and 32 engine-name lines.
Checked in the browser, keyless: the overlay baselines on both engines, the
ALPR and FIRMS fire-camera switches, and the layer handoff, Local ADS-B,
Contacts, space, infrastructure, CCTV, urban, transit, directions and
annotation engine switches pass. The tracking regression passes every check
that passes before this change.
Move the world overlay into scene.services.overlay. Each attachment owns its
sources, collision domains, paint lanes, canvases, observers, timers and
accessible action subscribers. Keep both canvases inside the engine container,
with detection beside the card root so its screen blend still reaches the
scene. Release shared font measurements only after the last host detaches.
Resolve retained layer publications against their attached engine, clear the
outgoing source before releasing its renderer, and reconnect the shell's action
subscription on attachment. Keep destroyed hosts inert and give parked engines
fresh services. Bind annotation rectangles and the existing tracked bridge to
their engine's overlay. The tracked bridge itself remains page-owned.
Preserve Cesium's projection, card placement, arbitration, fades, hit tests,
blend order and render demand. Navara keeps the same shared behaviour. No
user-visible change is intended. Exercise simultaneous hosts, either teardown,
stale handles, reattachment and a retained selected card on the fake and
headless Cesium engines. Update QA reads and package ownership for the service.
No coupling metric falls or grows: renderer lines remain 0 Cesium and 189
Navara; external Cesium import files 3; viewer lines 891; Navara kind checks 1;
engine sniff calls 0; extension reads 3; ground passes 1; SDK loads 3;
ScreenSpaceEventHandler files 4; engine-name lines 32.
Each host now takes the page's overlay ids from the host it replaces and gives
them back to a remaining host when destroyed, and the chrome's static overlay
placeholders are gone. The new hosts had left the ids on those empty
placeholders, so the voice pointer policy, the id selectors and the QA probes
that read #world-overlay-canvas missed the drawn canvas.
Checked in the browser, keyless: the overlay baselines on both engines, CCTV
v2 (58 checks), military names, and the engine, voice, ground-layer and Ghost
Maps switches pass. The transit script fails the same 25 checks as before.
Give each scene its own render governor, owner holds and recent idle requests.
Make the Cesium render backend own its request mode directly, so the governor
drives engine.render on both engines without a dependency back from Cesium.
Route layer requests through their attached engine and capture the attachment's
governor for camera motions, orbit, annotations and shell controls. Release
retained-layer holds before clearing the outgoing engine, and destroy the
governor after scene consumers have detached.
Preserve Cesium's owner-keyed holds, pre-install buffering, last-release settling
frame and one-shot requests during continuous rendering. Navara keeps the same
render policy. There is no intended visible change on either engine. Simultaneous
scenes no longer share holds, and an old captured service cannot release a
replacement attachment's hold. Cover both rules on fake and headless Cesium
engines, including an old orbit ending after reattachment.
Viewer-reference lines fall from 910 to 891, Navara-kind checks from 2 to 1,
and engine-name lines from 33 to 32. All other coupling counts stay unchanged.
Checked in the browser, keyless: qa-perf passes on both engines with the
same idle, active and release counts as before (24 checks on Cesium, 22 on
Navara).
Create pick registries and selection dispatchers for each scene attachment,
publish them through scene.services, and release their predicates and input
subscriptions before parking the renderer. Resolve layer ownership with the
attached engine so identical layer IDs in simultaneous scenes cannot overwrite
or remove one another. Re-register retained ALPR and cyclone picks on attachment,
and resolve voice pointer picks against the engine that supplied the pick.
Preserve Cesium's selection, sibling ownership, inert trails, touch expansion,
drag and long-press rules on both engines. Extract the unchanged gesture
predicates so portable picking does not acquire a native input dependency.
Exercise scene isolation, teardown and reattachment on fake and headless Cesium
engines, retaining the existing layer assertions.
No coupling count falls or grows. Cesium and Navara renderer lines remain 0 and
189; external Cesium imports 3; viewer lines 910; Navara kind checks 2; engine
sniff calls 0; extension reads 3; ground passes 1; SDK loads 3; screen-handler
files 4; engine-name lines 33.
Restrict runtime SDK imports to their engine directories, including package
subpaths, re-exports and dynamic imports. Keep three measured, reasoned
exceptions for the Bhote Koshi property-record models and reject stale
exceptions. Move the Cesium annotation renderers and both wind adapters to
their engine folders, preserving their implementations and lazy loading.
Load all 35 manifest display entries on a fake engine with an unknown kind
and no native extensions. Draw small fixtures and verify resource and
subscription cleanup before destroying the engine. Name the three entries
without display factories as skips. Update the architecture, infrastructure
lifecycle and engine integration documentation to describe the code today.
Cesium behavior is unchanged, and Navara keeps its existing behavior. The
weather comparison harness supplies the Navara flow-mesh factory and accepts
the previous backend location for comparison runs. No user-visible strings
change.
Cesium layer-renderer lines fall from 14 to 0, Navara layer-renderer lines
from 314 to 189, outside-engine Cesium import files from 5 to 3, viewer lines
from 933 to 910, extension reads from 4 to 3, and engine-name lines from 36
to 33. No coupling count grows. Targeted checks pass: 845 tests, three named
rehearsal skips. Import directions, package boundaries, formatting and syntax
checks pass.
Checked in the browser, keyless: the contract suite passes on Navara and on
Cesium apart from the camera-events check that also fails intermittently
before; Navara annotations pass across engine switches; the ground-look
comparison is pixel-identical. qa-draw-tool's hidden-line check and the wind
engine switch fail the same way before this change.
Render the Bhote Koshi event and locator through one ground and point display.
Keep Cesium's reveal paths, dashed halo, glowing core, polygon classification,
pick identities and independent point outline opacity. Add static pixel dash
masks, synchronous ground reveals after terrain bounds load, and per-point
outline colour so the shared display preserves those behaviours.
Add a ground pulse field with checked state on all three engines. Keep Cesium's
raised material disc, band equations, front widths, wake and rest timing and
reduced-motion behaviour. Navara now follows Cesium's raised pulse surface and
story styling, with ground effects composed after tone mapping. Move the wind
mesh shader into the Navara engine without changing its transparent pass.
Layer renderer lines fall from 210 to 14 for Cesium and from 794 to 314 for
Navara. Viewer lines fall from 953 to 948, extension reads from 6 to 4, and
engine-name lines from 37 to 36. No coupling count grows.
Checked in the browser, keyless: the contract suite, with its new pulse
pixel checks, passes on Navara and on Cesium apart from the camera-events
check that also fails intermittently before; the Nepal locator and Contacts
engine switches pass. The Nepal event and wind engine switches fail the same
way before this change. Side by side at the locator's overview, Cesium draws
the same pixels as before and Navara's river corridor now glows as Cesium's
does, where it was faint.
Share links read the current follow handle and displayed position through
engine.camera and restore their ENU offset with follow's swingTo option.
Cesium retains its first-frame wait, displayed-position cache, 60-degree
frame limit and range interpolation. Navara and the fake engine apply the
same swing. Cancellation, camera handoff and destruction release it; an
externally tracked Cesium entity keeps its existing handle.
Draw uses one surface with engine input, geodesic lines and point movers.
An exclusive pointer claim suppresses ambient subscriptions and deferred
picks across ownership changes. Cesium owns suspension and exact restoration
of its stock select and track actions. Camera gestures remain enabled.
Detaching releases the sketch and preview and retains shape and colour.
The separate Navara surface and Cesium data-source preview are removed.
Cesium remains the reference for clicked heights, line width and dash,
vertex size and outline, keyboard handling and completed annotations.
One deliberate visual fix is that the occluded rubber band uses the selected
colour instead of retaining the initial amber: it now identifies the same
sketch as its visible segment. Navara adopts Cesium's geodesic preview edges.
Finished annotation drapes are unchanged.
External Cesium import files fall from 7 to 5, viewer lines from 1005 to
953, and engine-name lines from 39 to 37. No coupling metric grows.
The full unit suite, import directions, package boundaries, formatting
and coupling checks pass.
Checked in the browser, keyless: the contract suite passes on Navara and on
Cesium apart from the camera-events check that also fails intermittently
before; qa-navara-draw passes; qa-draw-tool passes apart from its hidden-line
pixel check, which fails the same way before this change. Its destroy check
now expects no preview data source, since the preview has none.
Add indexed world triangles to the required globe contract on Cesium,
Navara and the fake engine. Own geometry, textures, visibility, depth tests,
pick identities and teardown inside each engine. Reused canvas images
request another frame until their new pixels upload. Move obstruction rays
and owned mesh, line and mover exclusions into the Cesium surface adapter.
Draw CCTV monitor planes and viewshed volumes through shared mesh handles.
Draw data-pack points, straight lines, raised polygons, image rectangles
and media captions through movers, lines and meshes. Delete the feature
renderers for each engine and retain decoded assets across scene rebinds.
Register the modules, dependency, format scope and reduced coupling baseline.
Cesium is the reference for geometry, colours, image placement, marker sizes,
caption offsets, picking and resource ownership. Navara now uses straight
pack lines and per-position polygon heights without edge densification.
Navara meshes draw in the transparent pass after the effects, with the
scene-depth test and the view's exposure undone, as the pack meshes did:
in the scene pass the landscape look's exposure washed a red pack image to
white. The scene-depth helper moves into the Navara engine, and the stems
helper that only its test still used is deleted. The mesh picker takes the
globe when Navara's depth read answers with the camera itself, which it
does right after another click and which hid a polygon from a quick second
click. The 256 px media caption is not pickable: its transparent square took
clicks meant for nearby pack features, and no action targets it. Annotation drapes remain on their existing
renderers because bounded building classification, animated fills and wire
cages need a separate contract extension to preserve Cesium behaviour.
Coupling falls from 344 to 210 Cesium layer-renderer lines, 1294 to 794 Navara
layer-renderer lines, 9 to 7 external Cesium import files, 1026 to 1005 viewer
lines, 9 to 6 extension reads and 42 to 39 engine-name lines. Other counts do
not grow. The full unit suite, import directions, package boundaries,
formatting and coupling checks pass. No user-visible strings change.
In the browser, keyless: the contract suite passes on Navara and on Cesium
apart from the camera-events check that also fails intermittently before
this change; CCTV v2 (58 checks), the CCTV and director engine switches pass,
with the pack image at the same pixel as before on both engines. The mesh
contract fixture now sits at 3 km, above the terrain Navara draws there. The
director interactions script starts at its view in the link so the app's
arrival flight no longer lands after the shot, and waits for the click's
asynchronous pick; its last step, the next-shot action, fails the same way
before this change.
Move Cesium viewer, map, sky, projection, trail and sonar internals into
its engine. Drive styles, bloom, sharpening and contact sonar through
engine.render. Count camera-input suspensions across all three engines
and migrate the feature callers. Preserve Cesium's effects and input
behaviour; fix transit lens clicks on Cesium and make zero sharpening on
Navara disable sharpening, as it does on Cesium.
Parse imported files into plain records and draw them through movers,
lines, ground and imagery on both engines. Follow Cesium's KML style
precedence, preserve local KMZ images and frame the drawable records.
Open overlays use imagery when the engine has no native map-overlay API.
Run every imported-display case on fake and headless Cesium engines.
The shared import path retains these known differences from Cesium's old
DataSources: wall fills, extruded prisms and gx:LatLonQuad are undrawn;
raised polygon fills drape while outlines retain altitude; GroundOverlay
rotation, altitude and RGB tint are not applied; rhumb lines become great
circles. Ground heights use the loaded surface synchronously instead of
waiting for most-detailed sampling. Supported KMZ ground overlays now
draw on Navara too. Document the limits rather than claiming full parity.
Combine batches B and C because their disjoint path manifests cannot
place the shared boundary and format files in a later commit while
keeping B independently valid. This combined commit owns the shared
docs, package boundaries, format scope, locale catalogs and coupling
baseline. Remove five obsolete import strings from all eleven catalogs.
Make the load-time source scan include new files and skip deleted paths
so the same checks work before and after recording the moves.
Coupling: Navara renderer lines fall from 1695 to 1294, Cesium import
files from 25 to 9, viewer lines from 1177 to 1026, SDK loads from 4 to 3
and engine-name lines from 62 to 42. No count grows.
The full unit suite and the boundary, format and coupling checks pass.
Browser validation remains to be run.
Browser checks to run
GOOGLE_MAPS_API_KEY= CESIUM_ION_TOKEN= npm run dev -- --port 4291
node scripts/qa-contract-suite.mjs http://localhost:4291
node scripts/qa-navara-visual-styles.mjs http://localhost:4291
node scripts/qa-navara-bloom.mjs http://localhost:4291
node scripts/qa-navara-sonar.mjs http://localhost:4291
QA_BASE_URL=http://localhost:4291 node scripts/qa-visual-effects.mjs
QA_BASE_URL=http://localhost:4291 node scripts/qa-zoom-out-guard.mjs
node scripts/qa-sky-model-lighting.mjs --url http://localhost:4291
node scripts/qa-geo-import.mjs http://localhost:4291
node scripts/qa-geo-import-regressions.mjs http://localhost:4291
node scripts/qa-geo-import-large.mjs http://localhost:4291
node scripts/qa-navara-geo-import.mjs http://localhost:4291
Use the keyless server for every check. Photoreal-only cases remain
unverified; do not enable paid tiles to run them.
Require engine.imagery for weather and wind and load the wind flow backend
from the layer manifest. Preserve Cesium's staging, frame retention, shell
ordering, wind fade and streamlines; Navara follows the same display policy.
Remove obsolete rendering modules and their three translated status keys.
Run every weather and wind display case on both the fake engine and the
headless Cesium engine, keeping the existing behavioural assertions.
Coupling: Cesium import files fall from 27 to 25, viewer lines from 1232 to
1177 and engine-name lines from 63 to 62. The explicit Cesium wind flow
backend deliberately raises renderer lines from 330 to 344 and extension
reads from 8 to 9; every other count stays unchanged.
Browser checks to run
GOOGLE_MAPS_API_KEY= CESIUM_ION_TOKEN= npm run dev -- --port 4291
node scripts/qa-contract-suite.mjs http://localhost:4291
node scripts/qa-weather-compare.mjs shoot http://localhost:4291 --out=qa-shots/weather-after
Compare weather and wind against the previous capture on both engines.
One JSON list from gagnaveita.vegagerdin.is (about 500 camera views at roughly
170 road stations). Frames are JPEG stills in a single directory on
www.vegagerdin.is; only links inside that directory are registered, and the
media proxy pins the same directory.
The list decides ids, coordinates and which frame path is proxied, so it is
fetched over https with redirects refused and the body read capped at 2 MiB;
every rejection path releases the response body. Camera ids come from the frame
file name, which is unique per view in the live feed, and repeated frames
collapse before the cap.
The feed's view description (`Skyring`) is the label. An explicit Icelandic
facing ("til vesturs", "í suður", "séð austur") sets a high-confidence heading
(264 of 499 views); a view that states none, or two different ones, keeps the
id-hash low-confidence pose. A bare road direction ("Miklabraut austur") is not
read as a facing.
IRCA publishes road camera images under CC BY 4.0 and asks that the licensor is
acknowledged without implying endorsement; the attribution is in the Data
attribution popover and DATA_SOURCES.md, and every camera carries the licence
string. Default cap is 250 with anchors at Reykjavík and four regional centres so
a cap keeps every region. CCTV_ICELAND_ENABLED=0 turns the pack off.
Verified against the live feed through fetchCctvImageFromUpstream: 499 of 499
frames returned a JPEG, all distinct, all under 20 minutes old.
Navara's ground pass cut each corridor into chunks and tested them per
screen cell, so dense corridor sets were slow (10,000 cost about 150 ms a
frame). A corridor set is now cut into pieces along its great circles,
sorted into lon/lat tiles, each with a pyramid of bins listing the
segment runs within its margin; a pixel takes its tile and the finest
bin that covers its reach and tests only those runs. At 10,000 corridors
a frame now takes 11.8 ms still (Cesium 23 ms), at 15,000 17.9 ms. A
pixel corridor's width is measured across the line, so diagonal lines no
longer draw up to 1.4 times wider.
Pixel corridors take three looks, evaluated on the GPU from a time
uniform: Cesium's PolylineGlow falloff (glow), an alpha pulse and the
annotation route's flowing dash. While a shown set pulses or flows the
engine draws continuously, as Cesium did. Traffic's jam lines take the
glow and pulse again and the Directions route its flowing dash and render
hold, so on Cesium both match the drawing before they moved to the
contract pixel for pixel. The contract suite passes on both engines
(Cesium 69/69, Navara 72/72).
src/app/layers/renderers.js now holds LAYER_MANIFEST, one entry per
layer in directory order: a display (the same render/display.js on every
engine, with the contract primitives it needs and, for CCTV and Global
Context, a Navara backend loaded by import()), a layer that draws itself
through the contract, or per-engine renderers for the layers not on a
display yet (weather, wind, Bhote Koshi, sea marks, ski pistes). A layer
is available where the engine has the primitives it needs. The Cesium
renderer table, CESIUM_BUILTIN, the registry and the Navara mode's map of
about 35 loaders go; the application loads a kind's renderers before it
builds the catalog.
The tools attach through one tree over the engine, in Cesium's order.
Each engine kind adds its own tools from one backend that reads its
extension once: the Cesium backend holds the viewer-only tools, the
Navara backend the annotation renderer, draw surface and file import
drawing.
Coupling: engine.extensions reads fall from 12 to 8, engine-name literal
lines from 73 to 66.
engine.imagery draws raster layers over the globe: Web Mercator tile
templates and single images or canvases stretched over a rectangle, with
alpha, show, a left/right split against the engine's split position and
an order. A layer's source can be replaced in place.
- Cesium puts one ImageryLayer per layer on the globe's imagery stack,
or on the shown 3D tileset's when the globe is hidden, and moves it
when the surface changes; the Recent Imagery request gate moved here.
- Navara draws them in one screen pass after tone mapping that samples up
to eight layers by geodetic position from mipmapped textures and a tile
atlas, under the other drapes and engine.ground.
- The fake engine keeps each layer's state.
The FIRMS far-zoom heat raster and Recent Imagery now draw through it, so
FIRMS' heat seam and both its backends, and Recent Imagery's Cesium and
Navara renderers and tile plan, go. Against HEAD, Cesium's pixels are
identical in all four compared scenes; Navara's orbital heat changes by a
mean of 3.8 from new mipmapping, slightly towards Cesium. The contract
suite passes on both engines (Cesium 68/68, Navara 71/71).
engine.maps.addOverlay stays a Navara-only extension for Sea Marks and
Ski Pistes until imagery has a finer tile path for oblique global views.
Navara lights the map tiles with the real sun and sky, and only the
landscape maps took the night ambient fill, so an OSM street map turned
black at local night where Cesium keeps it lit. Every base map now takes
the night fill; the landscape maps keep their orbital fill as well.
Daylight is unchanged.
This is why the strict acceptance's Navara pixel and first-frame checks
over Austin failed in evening runs: navara-hd, parked-release,
hidden-switch, context-loss, geo-import and scope saw a black frame, and
the soak and failure matrix waited for a first frame that never came.
At night with the fix all nine pass.
Earthquakes, air quality, GNSS Integrity, fire perimeters, Prohibited &
Restricted Airspace, Active Fires, S2 GhostMaps, cyclone advisories and
submarine cables each have one render/display.js on the globe contract;
their render/cesium* and render/navara* files go. Their discs, cells,
polygons and corridors are engine.ground sets, so on Navara they come from
the one ground screen pass with exact colours instead of nine hand-written
classification passes and lit SDK vector layers. Cesium's look stays the
reference:
- Earthquake and air-quality discs have no outline (Cesium drew none on
clamped ellipses); earthquake discs can now be picked on Navara too.
- Perimeters, drone zones and GhostMaps polygons outline their outer
ring only, as Cesium did.
- GNSS cells stay out of the pick pass; cyclone cones, tracks and centres
are culled by a port of Cesium's horizon occluder.
- Submarine cables are one ground corridor set, as Cesium batched them;
landing points, tips and stems are movers and lines.
- FIRMS glows are a sprite set and its cells a ground set. The far-zoom
heat raster, which no primitive draws yet, sits behind one seam,
render/heatField.js, with a Cesium and a Navara backend.
The shared Navara ground helpers that only these layers used go
(navaraGroundCells, the cell and ground geometry, the zone renderers), as
does the ground prototype script.
Coupling: layer renderer lines fall from 1636/6953 to 1011/4832
(Cesium/Navara), Navara ground passes from 7 to 5, Cesium-importing files
from 65 to 53, engine.extensions reads from 26 to 19.
engine.ground draws sets of polygons (with holes), discs, cells and
corridors draped on the surface, with fill and outline colours, order and
picks, written in bulk and committed. Every engine implements it:
- Cesium batches each set into one GroundPrimitive for fills and one
GroundPolylinePrimitive for outlines and pixel corridors, classified
against terrain and 3D tiles; sets that are not pickable stay out of the
pick pass.
- Navara draws them in one screen pass after tone mapping that finds each
pixel's ground from the scene depth and tests the items in its screen
cell; long rings are split into edge bins. Measured at Dubai against
SDK vector layers, the pass matched Cesium's frame time up to 10,000
polygons with a few megabytes instead of 70 to 146, drew exact colours
and outlines, and hid reliably across an engine switch, where vector
layers hidden with update({ show: false }) never hid. Dense corridors
remain its limit (10,000 cost 135 ms a frame).
- The fake engine keeps the same registry and CPU picks.
The contract suite checks it on both engines (Cesium 66/66, Navara 69/69).
Earthquakes and fire perimeters have unwired ground prototypes whose
drawing matches today's Cesium one (0.998 on Cesium, 0.976 on Navara).
docs/GLOBE-PRIMITIVES.md describes the primitives and when to use each.
- Radio: stations, clusters, the selection and its brackets are point
and sprite sets; clusters come from the layer's engine-neutral screen
clusterer with Cesium's EntityCluster rules, and clicks go through the
selection dispatcher. One style module holds the sizes and colours.
- Transit: vehicles are two sprite sets from an up-front atlas, rotated
with Cesium's projected-rotation maths. The selected vehicle's trail is
engine.lines in two lanes and 29 age bands, so trails are no longer
draped over terrain until the contract has ground corridors. The
Cesium contact trail renderer and its re-export go.
- CCTV: markers, wedges, the plane outline and the calibration gizmo
(rings, arrows, handles, drags through engine.input) draw on the
contract. The textured monitor plane and the viewshed volume, which no
primitive expresses yet, sit behind one seam, render/meshes.js, with a
Cesium backend and a Navara backend the Navara mode passes in.
Known gaps against Cesium: transit trails are not draped, and the
surveillance-lens click correction runs only where the engine reports
its style stage (Navara).
Coupling: layer renderer lines fall from 2638/8735 to 1636/6953
(Cesium/Navara), ScreenSpaceEventHandler files from 15 to 10, `viewer`
lines from 2014 to 1901.
Each layer now has one render/display.js on the globe contract, the same
factory on both engines; its render/cesium* and render/navara* files go.
Cesium's behaviour is the reference, and the logic that was written twice
is written once:
- AIS vessels: atlas chevrons and engine.lines trails. The display
registers the gev-trail pick claim itself and its trailing visibility
pass now also runs on Navara.
- Satellites: point banks per look, orbit rings as lines turned by their
model matrix, and selection and follow through engine.camera.follow.
The emulated _viewer is gone, and the tracked readout republishes card
text on Navara too.
- Space Missions: dots, reticle, trajectories and tactical orbits as
movers and lines. The layer keeps its own records instead of Entities
and DataSources, and camera work goes through engine.camera. Clicks go
through the selection dispatcher, and hover keeps Cesium's throttle. The
pad zone is its rim only: the contract has no surface fill yet.
- ALPR, bikeshare and OSM Places: one display and, for bikeshare, one
style module each; clicks through engine.input, no
ScreenSpaceEventHandler or EntityCluster. ALPR keeps Navara's horizon
cull, and OSM Places points sample the surface where Cesium clamped them.
Coupling: layer renderer lines fall from 4546/11106 to 2638/8735
(Cesium/Navara), `viewer` lines from 2209 to 2014, ScreenSpaceEventHandler
files from 20 to 15.
In the app the world overlay draws on a canvas of its own above the
globe, so letting every canvas take the pointer sent the suite's clicks
there. Only the engine's canvas takes it now. Without makeCanvas the
pick check's sprite atlas was a plain object no real engine draws, so its
sprites could not be picked; the page now hands the suite real 2D
canvases. --only=prefix,... runs a subset of the checks. With both, Cesium
passes 63 of 63 checks and Navara 66 of 66.