feat: the state becomes California, and the port fills with ships
**Stage 1 of one California.** The owner's complaint had two halves and this is
the first: the state board was a CROPPED SLAB. `california.ts` stopped at 38.05 N,
so the board disagreed with its own minimap about the shape of California in a
single frame, and Bug Fire's 93,733 acres burned off-frame while the panel said
all clear. Bounds now run 32.50-42.05 N / -124.50 to -114.0 W — Cape Mendocino,
the ruled Oregon parallel, the 120th-meridian corner into the Nevada diagonal.
**And it got cheaper.** 391,169 triangles to 375,351, while gaining the North
Coast, the Sacramento Valley, the Klamath knot, the Cascade arc, Shasta at 4,320 m
and Lassen at 3,190 m. Extending the bounds alone would have doubled the lattice
to 168,813 points and blown the mobile cap; coarsening cellLat 0.022 -> 0.0312 and
cellLng 0.027 -> 0.0383 holds it at ~83,800. The cell as a FRACTION of the board
moves 0.0030 -> 0.0033 — unchanged in frame — because the camera retreats to frame
whatever it is given. That argument was already written in the pack's own comment.
The second half — three boards becoming one world you zoom through — is NOT here.
Merging at Bay density would be 34.04M triangles, 13x the highest budget, and
merging at SoCal density would downgrade San Francisco from 40 m lots to 164 m.
Both delete the board every marketing still is shot from. `sf.ts` and `socal.ts`
are untouched by design.
**Aerial perspective, which the state board could not have had before.** The old
fog started at 1.15 board spans = 944 km, on a board whose longest diagonal is
820 km — so no pixel could ever be fogged. Fog now responds to camera altitude,
clamped to the authored pair as a ceiling.
`Atmosphere.aerial(env, view)` is a second pure method returning `{ near, far }`
and **deliberately no colour**. That is structural, not stylistic: it is why a
future camera-dependent term cannot reach `environmentKey()`'s colour fingerprint
and start rebuilding the PMREM cubemap on every camera step. Coarsening the
fingerprint instead would have hidden one instance and armed the mechanism. A
mutation-tested seam guard fails if anyone merges the two paths back together.
**The port.** Terminal Island rendered as a bare tan polygon with generic white
blocks while the chapter text called it the busiest port complex in the
hemisphere. Now six container yards drawn as canvas atlases, 56 gantry cranes at
varied boom angles, the 13 km San Pedro breakwater, the dredged channel. Five
buckets merging ACROSS ports the way airports.ts merges across fields, so a
second complex costs no extra draws: +11 draws and +4,377 triangles for all of it.
At vertical exaggeration 3.4 a 130 m gantry is 1.132 units tall against a 400 m
ship's 1.024 long — the crane is the taller object, and it is what makes a port
read as a port from altitude.
**Ships, and the wake carries the information.** Moored hulls have no foam,
verified at three terminals; a tug under way in the Main Channel trails a clean
Kelvin V. One hull geometry, one InstancedMesh, orientation from the BERTH rather
than the wire. The AIS gate strips sog 102.3, heading 511 and cog 360 — all mean
"not available" — with an explicit test that cog 358.7 SURVIVES, because a naive
range check on cog eats real headings near north.
"Empty or full" is not in AIS position reports and is not invented per ship. The
honest answer is at port level and is a better story: 348,691 of 460,467 boxes
left Los Angeles empty in July 2026, corroborated by FBX01 $7,491 inbound against
FBX02 $347 outbound.
**Radar and birds ship dark, and say why.** California is 0.47% wet and migration
is nocturnal and seasonal, so both layers have nothing to say on most days. The
panel reads "No radar feed is configured, so this board draws no weather. That is
a fact about this box, not about the sky."
Also recorded, and it matters beyond this commit: **the GPU on amd-server never
leaves 500 MHz of a possible 2725**, traced across 80 seconds of sustained load.
`bay-area/desktop` is fragment-bound at that clock and sits on the vsync deadline,
so a trivial change in fragment work flips it between 16.8 and 33.3 with geometry
identical to the digit. Every frame-time number measured on this box is a floor.
Two investigations reached two different wrong conclusions from single-run
comparisons before this was traced. Geometry is the gate; frame time is advisory.
No cap was raised.
Tests 1,340 -> 1,540, server 280 -> 295.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+259
@@ -704,3 +704,262 @@ entered from California than from the Southland, because the two rectangles
|
||||
contain different fires. `smokeCaption`'s sentence is worded for exactly that —
|
||||
"drawn from the fires currently on the board" — and the alternative, a statewide
|
||||
query per building, is a second source of truth about the same sky.
|
||||
|
||||
---
|
||||
|
||||
## 12. The state board is the state, and what that cost
|
||||
|
||||
The default board — the first frame an anonymous visitor sees — used to stop at
|
||||
38.05 N. The minimap in the corner of the same frame drew the whole of
|
||||
California from the same pack, so one screenshot contained a picture of the
|
||||
state and a picture of two thirds of the state, disagreeing about the shape of
|
||||
the one silhouette in this product that everybody already knows.
|
||||
|
||||
`bounds` is now 32.50–42.05 N and -124.50 to -114.0 W: the Mexican border, the
|
||||
Oregon line, Cape Mendocino with eight kilometres of ocean west of it, and the
|
||||
Colorado past Parker. All four edges are the state's own.
|
||||
|
||||
### 12.1 The price was paid in the cell, not in the bounds
|
||||
|
||||
Extending north and west at the old 0.022° × 0.027° spacing takes the lattice
|
||||
from **84,924 points to 168,813** — 2.02× — and the terrain mesh with it,
|
||||
against a mobile budget that had 70,000 triangles spare and two more layers
|
||||
landing on the same board in the same round. Extending the bounds alone does not
|
||||
fit and was never going to.
|
||||
|
||||
Coarsening the cell by 1.42× in each axis puts it back. The argument is the one
|
||||
`california.ts` already made when the board grew east and it is worth stating
|
||||
once more here, because it is counterintuitive: **what the eye sees is the cell
|
||||
as a fraction of the board, not the cell in metres**, because the camera
|
||||
retreats to frame whatever it is given.
|
||||
|
||||
| board | cell | span | cell / span |
|
||||
| --- | --- | --- | --- |
|
||||
| the corridor, before the east | 0.020° | 284 u | 0.0041 |
|
||||
| the southern two thirds | 0.022° | 428 u | 0.0030 |
|
||||
| the whole state | 0.0312° | 554 u | 0.0033 |
|
||||
|
||||
The ground cell went from 2,449 m to 3,473 m — 42% coarser on the earth — and
|
||||
*finer* in the frame than the board two revisions ago. Measured after: 85,008
|
||||
lattice points against 84,924, and 71,876 terrain triangles against 87,074.
|
||||
|
||||
`verticalExaggeration` went 13 → 15 in the same change, and for the same kind of
|
||||
reason. Relief in the frame is peak-units over board *span*: at 13 the extended
|
||||
board is 6.4% where the old one was 8.3%, and 15 puts it at 7.4%, which is
|
||||
Southern California's 7.5% almost exactly. Buildings share the exaggeration and
|
||||
get *smaller* in frame, not larger — a 250 m tower is 0.0035 of a span where it
|
||||
was 0.0040 — so the "bed of nails" objection the old comment raises about
|
||||
pushing to 20 does not apply at 15 on a board this size.
|
||||
|
||||
### 12.2 Fog is a function of camera altitude. Almost nothing else became metric
|
||||
|
||||
An investigation proposed converting every span-derived constant in the engine
|
||||
to physical metres, on the grounds that the three boards disagree by 8× once
|
||||
converted and San Francisco is the one that is right. **The diagnosis is
|
||||
correct and the prescription is not**, and the arithmetic is worth keeping:
|
||||
86 km of clear-day visibility is 0.91 spans on the Bay Area's 1,003-unit board
|
||||
and **0.085 spans on the extended state board**, where the camera orbits out to
|
||||
1,108 units. Literal metre fog buries California in haze 47 units from the lens
|
||||
and there is no pose on that board from which the state is visible at all.
|
||||
|
||||
So exactly two things changed, and the rule for deciding which is stated here so
|
||||
the next person does not have to re-derive it:
|
||||
|
||||
- **Fog near and far** are now a function of camera altitude —
|
||||
`aerialReach()` in `atmosphere.ts` — clamped so the pair the board was
|
||||
authored with is the ceiling and is never exceeded. It saturates at any
|
||||
whole-board pose, which is what leaves every existing marketing still
|
||||
untouched *by construction rather than by measurement*: the Bay Area's opening
|
||||
chapter sits 40.6 km up and the curve reaches its ceiling by 6.7 km.
|
||||
- **Cloud base altitude** was checked and did not move. It was already
|
||||
`BASE_ALTITUDE_M = 1350` passed through `world.metres()`, which is a physical
|
||||
metre constant respecting each pack's own exaggeration. Nothing to convert.
|
||||
|
||||
Everything else stays a span, and the distinction is not "physical vs lazy" — it
|
||||
is **whether the constant describes the air or describes the composition**:
|
||||
|
||||
| constant | stays a span, because |
|
||||
| --- | --- |
|
||||
| `clouds.ts` `TILE_SPANS` (2.2) and the 14×14 cell layout | tuned over 190 photographed frames; a cell-ownership chain, not a distance |
|
||||
| `satellites.ts` dome radius | the file says outright that it is arbitrary — it is where the dome looks right |
|
||||
| `fires.ts` `MARK_SPAN_FRACTION` | a glyph sized to be legible, like the aeroplane's 0.42-unit clamp |
|
||||
| `terrain.ts` `SWELL_TILE_SPANS` (1/34) | a physically-scaled sea has no visible surface at all; the file argues it at length |
|
||||
| camera `far`, `shadowExtent`, orbit limits, minimap layout | properties of a board, not of an atmosphere |
|
||||
|
||||
The one number a physical model got wrong on its own is worth recording, because
|
||||
it was found by taking a photograph rather than by thinking. A camera parked
|
||||
223 km from a mountain and 8 km above the ground is, physically, looking at
|
||||
something it cannot see — the air supports 231 km and the subject is at 223 of
|
||||
it — and the frame came back as a white rectangle with a faint cone in it. A
|
||||
board is a **map**, and a map is looked at from outside the atmosphere it
|
||||
depicts, which is the same argument `minVisibilityM` was already making. So the
|
||||
fog is floored at **6× the camera's own stand-off** (`AERIAL_SUBJECT_CLEARANCE`),
|
||||
which with `main.ts`'s 1.15/3.9 ratio puts the near plane at 1.77 stand-offs:
|
||||
nothing closer than about 1.8× the camera's distance to its subject is fogged at
|
||||
all, and everything past that hazes out toward six.
|
||||
|
||||
Six rather than four is set by one measurement, not by taste, and it is what
|
||||
makes "leaves the existing boards untouched by construction" true rather than
|
||||
approximately true. California's opening pose is 67.6 km up and Southern
|
||||
California's 17.0 km, so both saturate on the air term alone. The Bay Area's is
|
||||
11.3 km up against a 12.4 km saturation altitude — 324 km of air against 369 km
|
||||
of authored reach — and it is the stand-off term that carries it over. At a
|
||||
clearance of 2.4 that board renders at **88%** of its authored reach and the far
|
||||
corner picks up haze it has never had, which would have been a silent change to
|
||||
every still shot from the board that carries most of the product's imagery.
|
||||
`aerialPerspective.test.ts` asserts all three against the deployed formula, not
|
||||
against `cityDaylight`'s narrower one, because the narrower one is not what any
|
||||
board on the page uses.
|
||||
|
||||
### 12.3 What the north is made of
|
||||
|
||||
The added land is authored, not permitted. Hand-traced by house rule (§3.2): the
|
||||
North Coast from Bodega Head to the Oregon line with Cape Mendocino at -124.41,
|
||||
the 120th meridian and the corner at Lake Tahoe, the Klamath knot as four chains
|
||||
at four bearings because the Klamaths genuinely do not run north-south, the
|
||||
southern Cascades, the northern Sierra tapering out into the Cascade arc, the
|
||||
Warner Mountains alone in the north-east corner, and the Sacramento Valley as a
|
||||
chain rather than a circle.
|
||||
|
||||
Two failures were made and photographed on the way, both of them re-runs of
|
||||
mistakes this pack already documents:
|
||||
|
||||
- **The northern Sierra shipped as a row of separate domes.** Six hand-placed
|
||||
bells 0.35° apart on a 0.24–0.26 radius is 1.4 radii, and a chain only reads
|
||||
as a ridge below about 0.9. `ridge()` computes the spacing; the peaks that
|
||||
are written by hand are the ones somebody has checked.
|
||||
- **Mount Shasta rendered as a 4,320 m cone of pine.** `groundColor` answers
|
||||
`inPark` **first**, so a park envelope paints its ground green at any altitude
|
||||
and the `alpine` stop is unreachable inside one. The Cascade forest is now two
|
||||
polygons with the mountain in the gap between them — which is also true on the
|
||||
ground, since the Shasta Valley west of the cone is treeless grassland.
|
||||
|
||||
No new inland water. Clear Lake, Shasta Lake and Lake Tahoe are all legible at
|
||||
this scale and all three were rejected for the same reason: `createWater` puts
|
||||
every `inlandWater` polygon at y = 0.05, which is sea level, and those three sit
|
||||
at 400 m, 320 m and 1,897 m. At an exaggeration of 15 a lake plate at sea level
|
||||
under ground standing 3 to 15 units above it is a hole, not a lake. The Salton
|
||||
Sea works because it really is below sea level. Each polygon is also its own
|
||||
draw call, and the California mobile cell is the tightest in the project.
|
||||
|
||||
## 13. Four layers, one seam, and two gates each
|
||||
|
||||
The port kit, the ships, the reflectivity raster and the migration field arrived
|
||||
as four independent workstreams and reach the board through one seam:
|
||||
`SceneOptions` carries four optional factories — `ports`, `vessels`, `precip`,
|
||||
`migration` — and `createScene` builds, lights, ticks and disposes each of them
|
||||
exactly as it does `fires`. Every one of those five touch points is a line
|
||||
somebody can delete without breaking a compile, so
|
||||
`src/test/integration/layerSeams.test.ts` asserts all five from the source, at
|
||||
both ends of the seam: the factory is supplied by `main.ts` and it is consumed by
|
||||
`scene.ts`.
|
||||
|
||||
**A layer that is not supplied costs nothing.** Not "draws nothing" — is never
|
||||
visited: no group, no material, no geometry, no draw call. That is the whole
|
||||
reason the slots are optional rather than a `visible` flag, and it is what the
|
||||
budget shows. The California mobile cell measures **370 draws and 373,825
|
||||
triangles** with the two sky layers wired and no feed behind them, which is the
|
||||
number it measured before they existed.
|
||||
|
||||
### 13.1 The two gates
|
||||
|
||||
Each layer answers two questions, and they are different questions:
|
||||
|
||||
| Layer | Board gate | Deployment gate |
|
||||
|---|---|---|
|
||||
| `ports` | the pack declares `city.ports` | none — a quay is authored, not fetched |
|
||||
| `vessels` | the pack declares `city.ports` | none this round; the hulls are modelled |
|
||||
| `precip` | `boardCarriesRaster(bounds)` | `/health` `sources.radar` |
|
||||
| `migration` | `boardCarriesRaster(bounds)` | `/health` `sources.birds` |
|
||||
|
||||
The **board** gate is geometry. `boardCarriesRaster` asks whether a rectangle can
|
||||
be described by a quarter-degree cell — twelve cells on the short side, which is
|
||||
three degrees — and it answers true for California (9.55° × 10.50°) and false for
|
||||
the Southland (1.08° × 1.66°) and the Bay (0.85° × 0.89°). That is the same
|
||||
answer an `id === "california"` would have given and it is a fact about the map
|
||||
rather than about a name. It gates the birds as well as the rain because both
|
||||
feeds are statewide instruments quantised to the same cell: NEXRAD's composite
|
||||
and BirdCast's fifty-eight counties. A metro board would show three county discs
|
||||
and part of a fourth, which is a picture of the sampling grid rather than of the
|
||||
migration.
|
||||
|
||||
The **deployment** gate is `access.feeds`, read once from `/health`'s `sources`
|
||||
block at boot — the same field `drawsFire` reads. `sources.radar` and
|
||||
`sources.birds` are published by `server/src/routes/health.ts` off the config, so
|
||||
"why is there no rain on this board" is answered by the box rather than by its
|
||||
env file. Both are **optional** on `Feeds`, unlike every other feed there, because
|
||||
they are newer than some servers this client will meet and `undefined` has to
|
||||
mean *do not ask*.
|
||||
|
||||
### 13.2 The quiet day is the designed case
|
||||
|
||||
This repo's default is `none` for radar and `none` for birds, and no AIS licence
|
||||
has been read, so **the empty state is what nearly every visitor sees**. It is
|
||||
never blank. Each gate owns a sentence, each sentence is always complete, and
|
||||
each says what is being withheld as well as what is being shown:
|
||||
|
||||
- no feed at all — *"No radar feed is configured, so this board draws no
|
||||
weather. That is a fact about this box, not about the sky."*
|
||||
- a feed that answered with nothing — *"Nothing is falling on this board. All 16
|
||||
radars reporting. Last scan 5 minutes old."*
|
||||
- an instrument that does not measure in daylight — *"Nothing is aloft. BirdCast
|
||||
measures migration only after dark. Last night 393,290 birds crossed
|
||||
California heading south-east…"*
|
||||
- a harbour with modelled hulls — *"…19 hulls: 6 making way, 13 at rest, 16
|
||||
alongside a berth. No hull is labelled laden or in ballast: that is a port
|
||||
figure, not a ship one."*
|
||||
|
||||
They are printed into `#sea-section` and `#sky-section`, which are `index.html`
|
||||
elements written by `main.ts` rather than by `mount.ts` — the arrangement
|
||||
`#fire-section` and `#presence-host` already have, and for the same reason: the
|
||||
content is a *board's* instrument reading, it is rebuilt per board, and the
|
||||
section is hidden outright on a board that has neither a harbour nor a statewide
|
||||
raster. Both sit below **Go**, so the studio's own call to action stays above the
|
||||
fold on a phone.
|
||||
|
||||
### 13.3 The harbour is refreshed as a new fix, never nudged
|
||||
|
||||
`modelHarbour` stands in for a feed this deployment does not have, and the feed's
|
||||
shape sets the cadence. Upstream listens for thirty seconds every fifteen
|
||||
minutes; a hull under way moves about five kilometres between two reports;
|
||||
`engine/vessels.ts` dead-reckons along the reported course for exactly 900
|
||||
seconds and then stops. `main.ts` rebuilds the modelled body on that same
|
||||
interval off the once-a-minute clock, which is not a smoothing trick — it is the
|
||||
feed's own behaviour, and the small jump a moving hull makes when a new body
|
||||
lands is the jump a real fix makes. Nothing anywhere splines between two fixes,
|
||||
because the chord between them is not a path anything took.
|
||||
|
||||
Two clocks, deliberately different:
|
||||
|
||||
- the **modelled harbour** is built for `currentInstant()`, so a scrubbed sky and
|
||||
the ships under it describe the same moment, and `promoteVessels` is handed the
|
||||
same number so the body's age is what it really is: zero;
|
||||
- the **sky promotions** take `Date.now()`, because `fetchedAt` is a real
|
||||
timestamp and "last scan 5 minutes old" has to stay true when somebody drags
|
||||
the clock to midnight.
|
||||
|
||||
The migration layer is given `env.sun.elevation` — the same number the rig is
|
||||
lit by — rather than an ephemeris of its own. `LightingState.hemisphere.intensity`
|
||||
is **not** a day/night signal: it measures 1.33 at 21° below the horizon against
|
||||
0.95 at noon, because `atmosphere.ts` raises the fill to compensate a moonlit
|
||||
scene. A layer that read it that way drew nothing at midnight while passing a
|
||||
test written against invented numbers.
|
||||
|
||||
### 13.4 What the boards cost after wiring
|
||||
|
||||
Measured on this box, against the pre-round baseline:
|
||||
|
||||
| Cell | Before | After | Cap |
|
||||
|---|---|---|---|
|
||||
| california · mobile | 368 draws / 389,843 tri | 370 / 373,825 | 415 / 430,000 |
|
||||
| socal · desktop | 205 / 1,417,648 | 216 / 1,422,025 | 320 / 1,700,000 |
|
||||
| socal · mobile | 137 / 765,596 | 148 / 771,797 | 170 / 900,000 |
|
||||
| bay-area · desktop | 206 / 2,264,956 | 209 / 2,264,956 | 320 / 2,600,000 |
|
||||
|
||||
The whole port complex and its fleet — two ports, a thirteen-kilometre
|
||||
breakwater, six container yards, fifty-six gantries and nineteen hulls with
|
||||
wakes — costs **eleven draw calls and four to six thousand triangles**, and the
|
||||
same eleven on both viewports. That is what
|
||||
instancing across buckets buys, and it is the `airports.ts` argument repeated:
|
||||
the draw count is a function of how many *kinds* of surface exist, not of how
|
||||
many terminals.
|
||||
|
||||
Reference in New Issue
Block a user