1
0

feat: the crane grows a mast, the harbour works a shift, and the site is re-shot

**The Asset Factory verdict, and it mostly went against the vote.** Nine
candidates were thumbed up. One was taken.

TOOK the STS crane. Rebuilt in `ports.ts` from 5 unit boxes to 11 — an A-frame
mast and apex cap, a forestay to the boom, a backstay to the tail, a sill, the
truck-lane portal beam, a machinery house — still exactly ONE InstancedMesh.
What was missing is the thing that makes a gantry a gantry: on a real STS the
tallest part of a WORKING crane is the A-frame apex, not the boom, and a parked
raised boom clears its own apex by only 15-25%. Before, 56 gantries read from
altitude as 56 crosses — two coincident verticals with one bar through them and
nothing above it — so a berth flattened into a picket fence.

Proportions came from both upvoted candidates agreeing independently (hinge ~58 m
under an apex at 99-104 m), taken conservatively because Tera's packs already
author an 82 m hinge against a real 55-60.

The apex beacon came across as EMISSION: `craneLights()` returns bare positions,
`nightlights.ts` turns them into one additive Points cloud, 56 points, one draw
call, night only, no THREE.Light anywhere. 0.09 units was invisible against the
port's own cream emissive; 0.17 — half a bridge head light — is right, and the
screenshot at 0.09 is what condemned it.

REJECTED all three bridges, city-lights and both aircraft: the incumbents won on
the picture, decisively for the bridge.

TWO PARTS WERE BUILT FROM THE APPROVED CANDIDATES, PHOTOGRAPHED, AND CUT. Four
legs: 14 m of quay spacing is 0.036 units at 391 m/unit against a 0.032 member
floor, so 90% overlap. A portal X-brace: the bay is 0.115 wide by 0.38 tall, so
both diagonals come out near-vertical and add a lump at mid-leg. Both are among
the best things about the factory cranes AT THE FACTORY'S FRAMING. Neither
survives at board scale. That gap is the whole reason a factory asset is
reference geometry and not a drop-in.

Fixed a defect the rebuild exposed: the backreach started a full rail-gauge
behind the hinge, leaving a gap over the portal with the beam floating below it.
One unbroken girder now. And every inclined member goes through a `strut()` that
takes two points in the (distance-along-boom, height) plane, so the
vertical-exaggeration bug the module header warns about is no longer reachable —
it needs a length and an angle, and there is now no way to start from those.

**The harbour works a shift.** It was a frozen tableau: 19 hulls placed from the
pack's berths that never changed. Vessels now arrive through the channel, are met
by a tug, berth, work and depart — seeded, so two people see the same harbour and
a capture script shoots the same frame twice. A ship loses its wake when it ties
up, because the wake is the information.

**Every still and film re-shot.** The site was showing a Tera that no longer
existed — SHOTS_COMMIT b7f5c41, FILMS_COMMIT 2aa4049, against an engine that has
since gained fires, the whole state, ports, ships and night infrastructure. Two
frames were bad and are fixed by moving the hour, not by retouching:
`bay-relief-day` and `peninsula-day` were white lids of marine layer. Four
captions described a Tera that no longer existed and are rewritten to the
delivered frame. `california-relief-night` is measurably brighter than the frame
it replaces (canvas mean 7.91 -> 10.57) despite the state being 30% larger.

Ten budget cells pass, run twice. socal 1,422,025 -> 1,429,993 triangles against
1,700,000, 218 draws against 320. The measured delta is double the geometry
because the crane mesh casts shadow, so renderer.info counts it in both passes —
worth knowing before anyone reads that number as geometry.

Tests 1,540 -> 1,570, server 295.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-23 03:29:58 -07:00
parent e7a8aa028b
commit bcac6aa41a
15 changed files with 2429 additions and 304 deletions
+186 -49
View File
@@ -8,13 +8,11 @@ in an issue, not here.
`src/cities/california.ts` now runs 32.5042.05 N and -124.50 to -114.0 W. Four
things fall out of it that somebody has to pick up.
- **The marketing stills are frames of a board that no longer exists.** Every
`city: "california"` shot in `scripts/brand-assets/shots.mjs` was photographed
at 428 units across with a ruled crop along 38.05 N. Re-shoot with
`npm run refresh`. The `chapter` indices are all still correct — the north
chapter was added at the **end**, index 5, precisely so nothing re-points — but
`california-relief`'s caption says "428 units across at 1,919 metres to the
unit" and that number is now 554. The caption is the only edit needed.
- ~~**The marketing stills are frames of a board that no longer exists.**~~
**Done 2026-08-23.** All 21 shots and all four films were re-shot at `e7a8aa0`
plus this round's uncommitted work; `california-relief`'s caption now says 554
units and names the north. See "The imagery was re-shot" below for what that
run found, and for the two manifests that are still waiting on a clean sha.
- **`scripts/performance-budget.mjs`'s header comment is now stale in one row.**
It records `california/mobile` at 389,843 triangles; the extended board
measures 373,825. The caps in `performance-budgets.json` were rewritten
@@ -277,55 +275,194 @@ on a bridge frame.** On the deck the lamp run, both tower silhouettes and the re
light over each tower head all read clearly at 21:35, where at 20:50 there was no
light on the structure anywhere.
## Re-shoot the time-lapse films
## The imagery was re-shot on 2026-08-23 — what that run found
All 38 product stills were re-shot on 2026-08-22 against the night-infrastructure
work, so the manifest records `SHOTS_COMMIT b7f5c41` with **`SHOTS_DIRTY true`** —
that tree was not committed when the shutter opened, and the manifest says so
rather than naming a commit that would render something else. Re-run
`shots.mjs --manifest-only` once it is committed. The two **share cards** were not
re-shot and did not need to be: `capture.mjs` shoots both at 11:20 and 17:30, so
nothing that changed after dark is in them. **The films were not** — they were
last shot on 2026-08-07 at `9c9e78f`. `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.
`npm run refresh` at `e7a8aa0` + this round's uncommitted work: **21 shots x 2
frames**, both share cards, all four films, both manifests. Every run printed
`ANGLE (AMD, Vulkan … Radeon RX 6700 XT (RADV NAVI22))` and not SwiftShader; no
chapter guard and no `play` guard fired. Timings on this box, for budgeting:
build 7 s, stills 545 s, cards 26 s, films 416 s.
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;
SFO, LAX, both bridges and a freeway that reads as a road; aircraft that move,
carrying registration and type; a rebuilt LA studio; the studio device hardware; and
a new UI chrome with a first-run flow.
**Both manifests are dirty and that is the one thing still owed.**
`SHOTS_COMMIT` and `FILMS_COMMIT` are `e7a8aa0` with `SHOTS_DIRTY` /
`FILMS_DIRTY` **true**, because the tree was not committed when the shutter
opened — the port, vessel and night-light work of this round is in every frame
and in no commit. That is the manifests being honest rather than naming a sha
that would render something else. Once tera is committed:
```sh
npm run refresh -- --films-only --rough # rough cut first: ~20 s a reel, and it is
# the cheapest way to find out a camera is
# pointed at the wrong thing
npm run refresh -- --films-only # ~90 s per 180-frame film on the Radeon
node scripts/brand-assets/shots.mjs --manifest-only # no browser, no render
node scripts/brand-assets/films.mjs --manifest-only
```
Worth knowing before starting (the rest is in `~/.claude/skills/tera-capture`):
then commit lumbridge-v4 and deploy it.
- 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-soma` is 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:hero` in lumbridge-v4.
- `#onboarding-host` is in `FURNITURE.CLUTTER` now, and `#mode-dock` and
`#play-hud` are in `FURNITURE.BARE`. Every *new* overlay has to be added to one
of those two lists on the day it lands, because a frame with a stray card in it
still renders and still looks deliberate. The mode dock proved it: it shipped
inside the tera share card for a fortnight and nobody noticed.
- **The two capture scripts both serve on port 5210.** Two of them at once is
`EADDRINUSE` a minute into a run, so do not start a film while a stills pass is
going — or give one of them `--site`-style isolation first.
- Commit tera first, then re-run, so the manifest records a clean sha.
### Two new shots, and one of them needs a page
- **`harbour`** — socal chapter 5, aimed at 33.7405/-118.2565 broadside across
Terminal Island. Four crane rails at four bearings, the container yards, hulls
alongside and one under way, the Vincent Thomas across the Main Channel, and at
night a red obstruction light on every gantry apex.
- **`california-fire`** — the state board with the fire feed behind it. See the
section below; it is the only frame here that is not the keyless experience.
Both are in `shots.ts` and both are delivered as WebP. **Neither is on a page.**
Every one of the other nineteen ids is named explicitly by something in
`lumbridge-v4/apps/web/src`, so a new shot appears in the manifest and nowhere
else until somebody places it. That is a handoff, not a defect.
### The fire feed is photographable now, from a fixture
`drawsFire()` gates the whole layer on `access.feeds?.fires === true`, which
comes from `/health`. A keyless capture — which is every other frame here — can
therefore not photograph fire at all, while `tera.lumbridgecorp.com` answers
`"fires":"cloud1"` and every anonymous visitor to the deployed site does get it.
The site was about to ship an imagery set in which the most visible thing the
engine gained this round did not exist.
`shots.mjs` now has `serveFeed()` and a per-shot `feed` field. It fulfils exactly
two routes and 404s the rest of `/api/v1`, and the body is
`scripts/brand-assets/fires-2026-08-23.json` — the verbatim response from the
live feed on 23 August 2026, kept whole. **Do not trim that file.** `promote()`
counts the rows it refuses and the panel prints that number, so a fixture with
the refused rows deleted would draw the same eight fires under a sentence
claiming a gate that never ran.
Three consequences worth knowing before extending this:
- the synthetic `/health` says `auth.mode: "none"`, which resolves the visitor to
`member` and keeps **`#tier-adds`** out of the frame. That card is the sign-in
offer, it is shown only to `anon`, and it is **not** in `FURNITURE.CLUTTER`
so the day this pipeline meets a real API it will arrive in the art silently,
exactly the way `#mode-dock` did;
- `california-fire` is the only shot clocked to **2026-08-23** rather than
2026-08-06, because the panel prints the body's own `fetchedAt` and how long
ago that was. A fixture from the 23rd photographed on the 6th reads "fetched
2026-08-23 · just now";
- the hot-pixel layer draws every FIRMS detection inside `bounds`, and `bounds`
is a lat/lng **rectangle**. On the state board that puts a handful of cyan
points over open water and over Baja in the night frame. They are real
detections and the rectangle is the honest gate the layer has; it is worth
deciding whether a board wants a land test before the count in the panel is
ever quoted as a California number.
### The marine layer decided two of the day frames, and it should decide any more
`atmosphere.ts` models the Pacific marine layer on **apparent solar** time, and
the curve is 0.95 before dawn, 0.6 at nine, 0.2 at eleven, 0.4 again by four. Two
shots were on 09:10 and 09:20 — a little after eight solar, where the layer is at
about three quarters — and at a whole-board or 32 km standoff that is not weather
in the picture, it is a white lid over the entire subject. `bay-relief`'s caption
is about eighty-three named hills and four octaves of value noise, none of which
was visible; `peninsula`'s is about twenty miles of city, likewise.
Both moved to the late afternoon (17:00 and 17:10) and both frames are now
legible. The compromise is forced: the layer is thinnest at solar 11-14, which is
**12:07-15:07 on a wristwatch here** — the exact hours a heightfield has no
shadow. Around five is thin enough to see the ground and low enough that the
ranges still throw.
**Any future wide day frame on the Bay board has this constraint.** Close and low
poses do not — `fidi` at 10:10 and `crow-nav` at 09:20 are both clear, because
the camera is under the deck.
⚠️ **A 1x `--preview` does not predict the cloud in the 2x delivery.** The deck
animates on elapsed time and the two runs have different settles (3000 ms against
6000), so the puffs land somewhere else. Framing, pose and light all preview
faithfully; cloud does not. Judge cloud on the delivered frame, which is how
`peninsula`'s note lost a sentence about SFO that was true of the preview and not
of the render.
### Four captions had been falsified by engine changes, and nothing catches that
A caption is prose next to a camera pose. When the engine moves under it, the
frame still renders, still looks deliberate, and still ships. All four of these
were found by opening the delivered frame and reading its own note back:
- **`california-flight` day** ended "and the Pacific past the wingtip". Aerial
perspective now follows camera altitude, so at 1,413 m the ocean is inside the
haze rather than beyond it and there is no sea in the frame at all.
- **`california-flight` night** promised "the basin's lit ground in the corner"
and "the moon's path broken across the water". The frame is over dark coastal
mountains: no basin, no water. What actually carries it is the aircraft's own
navigation lights and the corridor's road markings.
- **`lax` day** said "the traffic overhead is the real traffic: registration and
type come off the same feed". **It cannot be.** Every frame but
`california-fire` is shot keyless, so `TrafficSource` is the bundled simulator
and not ADS-B. A caption may not borrow a fact from a deployment the shutter
never opened on — and this is the failure mode to watch for now that one shot
*does* have a server.
- **`golden-gate` day** said the towers "throw along the deck". They throw across
the water beside it, which is checkable and was checked.
### `fidi-day`'s day poster had drifted onto the wrong renderer
`poster: 0.86` was chosen as "a few minutes before sunset: the last of the low
sun down the length of Montgomery". On ACES with the world-space sky dome, 0.86
is 20:09 with the sun at **+0.4°** and the towers are unlit silhouettes — the
frame measured mean luminance **33** out of 255 against the night poster's 21.
That is not a pair, and it matters more than a poster usually would: `Film` ships
`preload="none"`, so the poster is what most readers see for most of the time the
film is on their screen. Now `0.76` — twenty past six, sun twenty degrees up,
towers lit and throwing, mean **87**.
The other three films' posters were checked the same way and are fine
(147/24, 106/21, 155/46 day against night). **Check a poster pair by measuring
both, not by reading the clock**: the fractions were all chosen on an older
renderer and this is the one that had moved.
### Smaller things the re-shoot turned up and did not fix
- **`freeway` and `drive-101` are nearly the same photograph.** Both are the
chase camera on the 101 chapter at 09:00; the only difference is where on the
leg they land — 47% against 57%. `freeway` gets there with `settle: 3000`,
which is the duration-not-position trap `drive-101` exists to document. It has
landed on 47% on two consecutive runs, so it is reproducible in practice on
this box, but it is a duration and it is measured from boot. It cannot simply
be given a `play` block: the 101 chapter is *already* in drive mode, and
`enterPlay` clicks the dock button, which would toggle it off.
- **`office-desks` slices the hardware card.** The panel is taller than the
viewport, so `Desk speaker`'s controls are below the fold and its header sits
on the frame edge. That is the exact condition `shot.hide` was invented for,
and it cannot be used here because the hardware *is* the subject.
- **`#sky-section` stays in the product stills, deliberately.** It prints "No
radar feed is configured … that is a fact about this box, not about the sky"
twice, which reads like a hole — but `tera.lumbridgecorp.com` answers
`"radar":"none"` and `"birds":"none"` today, so a real visitor sees the same two
sentences. It is not the `#tier` case (local disagreeing with deployed); it is
the product's own voice. **If either feed is ever wired, this decision has to be
taken again**, because then the local frame and the site would disagree.
- **`#sea-section` stays too**, and it is the one that earns it: the harbour is
modelled identically here and on the deployed site, and its sentence is what
keeps a frame full of ships honest about their being modelled rather than
observed.
- **`PROVENANCE.json`'s two card records now name a date they were not made on.**
`refresh.mjs` re-stamps the share cards narrowly — it substitutes the `sha256`
in the text and nothing else, which is what keeps that diff two lines instead
of a reflow — so `intakeDate` still reads `2026-08-22` for files written on the
23rd. `check-provenance` only validates the format, so nothing catches it. It
is one line in the one document whose entire job is accuracy.
## The vessel layer has two gaps that belong to other files
Both stated in code comments already; recorded here so they are not only there.
- **Pier 300 and the East Basin take no port calls.** The straight run from the
nearest point on `Port.channel` to those berths is 1.9 km and 2.9 km and
crosses Terminal Island, so `BERTH_APPROACH_REACH_METRES` (1100) gates them out
and they keep a static hull alongside rather than driving a container ship over
a container yard. The proper fix is an optional per-berth approach path on
`Berth``approach?: LatLng[]`, water-side first — which `socal.ts` could then
author for Pier 300 as the real route out through Angels Gate and north-east
across the outer harbour. `harbourCalls` would prefer it to the nearest-point
projection; about ten lines once the field exists. The field is on
`src/engine/types.ts`, which the vessel work did not own.
- **The tug's own solid is correct, cheap, and sub-pixel at every SoCal pose we
ship.** Its payoff is banked for the Bay board and for closer poses rather than
realised today.
- `engine/nightlights.ts` now imports `craneLights` from `engine/ports.ts`. No
cycle — `ports.ts` imports only three, terrain, types and world — but the two
files are coupled and want moving, and re-photographing, together.
## The GPU on this box never leaves 500 MHz, and every frame-time number here is a floor