**The aeroplanes were stuck because the wire could not describe motion.** `WireAircraft` carried position, altitude and heading and nothing else, so the client could only interpolate between the last two observations: every aircraft replayed a segment it had already flown, arrived at the newest known point, and sat still until the next poll landed five to fifteen seconds later. The feed had the missing numbers the whole time and the server threw them away. Sampled live from `api.adsb.lol/v2/point` while writing this — `gs` ground speed, `track`, `baro_rate`, plus `r` registration and `t` type designator. They are on the wire now in SI, aircraft dead-reckon along their own track and correct toward the truth when a fix lands, and the click card an anonymous visitor gets says "B739 · N68834". That last part is the enrichment FR24 was wanted for, obtained from an ODbL feed we may actually republish. **SFO and LAX exist.** A new `engine/airports.ts` composes an airport from runways, taxiways, aprons and terminal masses, with markings drawn on a canvas rather than modelled; the pattern of the runways is what the eye recognises from altitude, long before any building does. SFO is the two crossing pairs on the bay fill; LAX is the four parallels either side of the terminal horseshoe, plus the Southland fields under the traffic that actually flies there. **The Golden Gate and the Bay Bridge are those bridges.** One kit in `engine/bridges.ts`, because a suspension bridge is a repeated tower, a catenary main cable, a series of hangers and a deck — so both are configurations rather than two private implementations. The Bay Bridge carries the real 2013 topology: two suspension towers west of Yerba Buena, one east, then the piered causeway. The freeway stopped being a wireframe overlay and became a road, with shoulders, a median, and lane markings as texture. **And the board got faster while all of that landed.** California went from 728,744 triangles and 562 draw calls to 391,169 and 371 — headroom from 2.8% to 47.8%. The Bay Area board is 506,550 triangles lighter than before this work. Two things paid for it: - `transmission: 0.08` on the aircraft cockpit glass. three.js runs a full transmission backdrop pass whenever any rendered material has transmission above zero, re-drawing the entire opaque scene into a second target every frame — so the city was rendering terrain, every block and every freeway piece TWICE. Measured by patching only that number in a copy of the built bundle: 703,267 tris / 562 draws with it, 398,608 / 371 without. The material was already `transparent: true, opacity: 0.86`, so it was buying nothing. - Flatness-adaptive terrain LOD, which collapses runs of lattice cells wherever the height and colour agree with the quad replacing them. The coastline is provably untouched — a patch collapses only when every point is on land and agrees about `park` — and a test asserts the drawn footprint matches the cell-by-cell area to 1e-6. `createTerrain` got *faster*: the vertices it stops emitting cost more than the flatness scan costs to run. **The budget now watches the boards this was built on.** There was no `bay-area` or `socal` cell — so SFO, LAX and both bridges all landed in frames nothing measured, which is how a cap you do not have looks from the inside. Both are in the matrix now with caps set from measurement, and the rationale lives in the harness because JSON cannot hold a comment. Two known defects ship with this, both recorded in TODO.md rather than hidden: - `bay-area.desktop` drops about one frame in twenty (p50 16.7, p95 33.3). It is desktop-only and not fill rate — mobile runs the same 2.26 M triangles at a comparable pixel count and holds 16.7 flat — which points at the 2048 shadow map desktop uses against handheld's 1024. Measured at the commit before this work with the same harness: identical p95 33.3. Pre-existing, and invisible until the cell existed. - The aeroplane glyph is still about 1.5x the Golden Gate's main span at chapter zoom, down from 2.5x. `GLYPH_MAX_SCALE` is 52 because the raw scale at the far end of the California orbit is 51.0 at a 60-degree field of view, and 26 — tried first — put the glyph at 0.0123 of the frame against the 0.012 where the wings stop resolving. The real fix is to clamp against the camera's focus distance rather than the aircraft's, which is a signature change. Tests 1020 -> 1137. Typecheck, build, eight budget cells, no-binaries, provenance, zero-config boot, dependency licences, arena source hashes and the UI smoke across two viewports and two access tiers all pass. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
5.3 KiB
Open work on Tera
Short, and only things that are decided but not done. Anything speculative belongs in an issue, not here.
Re-shoot the time-lapse films
The 18 product stills and both share cards were re-shot on 2026-08-22 at 2b2dd5c
and are live. The films were not. films.ts in lumbridge-v4 records the tera
commit each reel was shot at, so a stale reel is visually stale and no caption edit
fixes it — check that commit against tera HEAD before assuming a reel is current.
What the reels predate: ACES tone mapping and the runtime PMREM environment rig; a
sea that reflects, with a swell normal map, Fresnel and sun glitter, in place of a
flat MeshLambertMaterial that had no specular term at all; a world-space sky dome
replacing the screen-space gradient, which at dusk painted the sunset band along the
bottom of the picture, under the board; terrain that casts shadows; a California
board with the Basin and Range, Death Valley, the Salton Sea and San Diego on it;
aircraft you can actually see; a rebuilt LA studio; the studio device hardware; and
a new UI chrome with a first-run flow.
npm run build
node scripts/brand-assets/films.mjs --frames 24 # rough cut first: ~20 s, and it is
# the cheapest way to find out a
# camera is pointed at the wrong thing
node scripts/brand-assets/films.mjs # ~90 s per 180-frame film on the Radeon
Worth knowing before starting (the rest is in ~/.claude/skills/tera-capture):
- Check the run prints the Radeon and not SwiftShader. The software path is ~15x slower — 22 minutes a film rather than 90 seconds — and it reports success.
hero-somais a different animal:chrome: "bare", midnight to midnight, and a two-stage encode (a CRF 18 master, then 1440w CRF 28 and 960w CRF 30 delivered).- The hero camera is worth reconsidering. Whole-board was tried and rejected because the edge of the terrain plate showed against the sky. That seam no longer exists: the sea now runs eighteen board spans and ends past the fog's far plane.
- After tuning the hero, run
npm run check:heroin lumbridge-v4. #onboarding-hostis inFURNITURE.CLUTTERnow. Every new overlay has to be added there too, because a frame with a stray card in it still renders and still looks deliberate.- Commit tera first, then re-run, so the manifest records a clean sha.
The Bay Area board drops a frame in twenty, on desktop only
bay-area.desktop.p95FrameIntervalMs carries a 33.4 ms allowance and that is a
recorded defect, not a target. The board renders a median frame in 16.7 ms and
drops roughly one frame in twenty: p50 16.7, p95 33.3, and 443–456 frame samples
in a window where every other cell returns 480.
It is desktop-only, and it is not fill rate: the mobile cell runs the same
2.26 M triangles at a comparable pixel count — 1.32 MP against desktop's 1.30 —
and holds 16.7 ms flat. The obvious suspect is the shadow map, which stage.ts
sizes 2048 on desktop and 1024 on handheld, over what is now the heaviest
shadow-casting scene in the product.
It is not a regression, and this was checked rather than assumed. Measured at
the commit before the airports and bridges landed, with the same harness:
p95 33.3, p50 16.7, 443 samples, 2,771,606 triangles. After that work:
p95 33.3, p50 16.7, 456 samples, 2,265,056 triangles — the board got
506,550 triangles lighter while gaining SFO, both bridges and a surfaced
freeway. The stutter was simply invisible until bay-area became a measured
cell, which it had never been.
The allowance is there so the cell still guards the numbers that are healthy — triangles, draw calls, and the mobile frame time — rather than sitting permanently red and therefore permanently ignored. Fix the stutter and put the cap back to 16.7. Start with the desktop shadow-map size and the shadow frustum over the SF board; a 2048 map over 2.26 M triangles of casters is the first thing to rule in or out.
The aeroplane glyph is still larger than the Golden Gate
GLYPH_MAX_SCALE in src/engine/flights.ts is 52 and that is a mitigation, not
a cure. The glyph has a screen-space floor — never smaller than legible — which
scales by the distance to the aircraft, when what makes it look wrong is how
far the camera is from what it is looking at. At a whole-board pose those are
the same thing; at the Golden Gate chapter the bridge is two units from the camera
and the traffic is two thousand, so the floor fires hard on the aeroplane and not
at all on the bridge.
A ceiling of 52 was chosen because the raw scale at 1,160 units — the far end of
the orbit over the California corridor — is 51.0 at a 60-degree field of view, so
anything lower shrinks aeroplanes at a pose people actually use. (26 was tried
first and put the glyph at 0.0123 of the frame, against the 0.012 at which
flights.ts says the wings stop resolving.) 52 takes the worst case from about
two and a half times the bridge's main span down to about one and a half.
The complete fix is to clamp against the camera's focus distance rather than the
aircraft's, so the glyph collapses toward its authored size whenever the viewer
has zoomed in on something near, at any aircraft range. That is a signature change
through glyphScale, tick and their callers.