1
0
This repository has been archived on 2026-08-25. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
tera/src/server/birds.ts
T
karti acf4d1a510 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>
2026-08-22 23:35:09 -07:00

401 lines
16 KiB
TypeScript

/**
* Which birds may be drawn, what the sky says when none may, and the one number
* that is wrong by six times if you compute it the obvious way.
*
* ### The empty state ships first, because it is what most people see
*
* BirdCast measures nocturnal migration and measures it **only after dark**. Of
* the 297 granules in the upstream store, 176 are daytime and hold 104 rows
* between them, against 7,719 at night. The layer is therefore absent about
* fourteen hours in every twenty-four *by construction*, before any question of
* season, and every default frame `scripts/look.mjs` takes is a daylight frame.
* A layer that only looks right during the small fraction of frames where it has
* something to say is a layer that looks broken the rest of the time.
*
* So `quiet` is not optional and is never blank. It carries a reason and a
* sentence, and the sentence is the layer:
*
* Nothing is aloft. BirdCast measures migration only after dark. Last night
* 393,290 birds crossed California heading south-east, peaking at 1,501,193
* aloft at 23:20 PDT, at a mean 726 metres.
*
* ### The six-times error
*
* `SELECT SUM(birds_crossed)` over the 58 county rows for the night of
* 2026-08-21 gives **2,360,086**. The authoritative figure, on the `US-CA` state
* row for the same night, is **393,290**. Both are correct: a bird that crosses
* four counties is counted in four of them, so the county rows are a spatial
* distribution and the state row is the crossing count. Nothing in this file
* ever sums counties into a headline, and `statewideHeadline` reads the state
* row or returns `null`.
*
* ### The state row has no coordinate, and it is enormous
*
* `counties` in the store is 59 rows, not 58: fifty-eight counties plus `US-CA`,
* `kind='state'`, with **NULL lat and lon** and, in tonight's granule, 793,141
* birds aloft against the largest county's 82,549. A per-county path that does
* not take it out places a 793,141-bird blob at 0,0 in the Gulf of Guinea — or,
* worse, at whatever a `?? 0` turns it into. It is excluded here on three
* independent grounds, because one of them is the one that will be missed.
*
* Pure: this imports nothing but types, touches no DOM and constructs no mesh.
* The gate is a statement about data, and a statement about data that lives
* inside a mesh builder is a statement nobody can test without a WebGL context.
*/
import type { MigrationCounty, MigrationField, MigrationNight, MigrationQuiet } from "../engine/types.ts";
import type { BirdsBody, BirdsSourceId, WireBirdCounty } from "./wire.ts";
// ---- The ladder -----------------------------------------------------------
/**
* The id of the row that is a state and not a county.
*
* Named rather than inlined because it is checked in more than one place and
* because the *reason* it is checked has to travel with it. See the header.
*/
export const BIRDS_STATE_ROW_ID = "US-CA";
/**
* Solar elevation above which nothing may be drawn, in degrees.
*
* Civil twilight. BirdCast's product is nocturnal, so a daytime row is not a
* small measurement — it is a measurement of something the instrument does not
* measure, and 104 of them exist in the store. This is what refuses them, and it
* refuses them whatever the feed says, because being wrong about the sun is not
* a thing this build is prepared to be.
*/
export const BIRDS_MAX_SOLAR_ELEVATION_DEG = -6;
/**
* Birds aloft below which a county is not drawn at all.
*
* A judgement, and a small one: BirdCast reports continuous fields, so a county
* with four birds over it is a rounding artefact of a forecast raster rather
* than four birds. Set low enough that a genuinely quiet county still shows.
*/
export const BIRDS_MIN_ALOFT = 25;
/** The most counties one board will draw. Fifty-eight exist; this bounds a bad day. */
export const BIRDS_COUNTY_LIMIT = 64;
// ---- Shapes ---------------------------------------------------------------
/** Everything a board needs to draw migration, and to explain an empty sky. */
export interface BirdsPromotion {
source: BirdsSourceId;
/** ISO-8601 of the last successful upstream fetch. Epoch zero when never. */
fetchedAt: string;
/** Milliseconds since `fetchedAt`, or `null` when nothing has ever answered. */
ageMs: number | null;
/** Handed straight to `MigrationLayer.setField`. `null` only when nothing answered. */
field: MigrationField | null;
/** Rows the gate refused — the state row, and any county under the floor. */
suppressed: number;
/** The panel's sentence. Never blank, and never "no data". */
message: string;
}
export interface BirdsPromoteOptions {
nowMs?: number;
/**
* The sun's elevation over California, degrees. The same number `Atmosphere`
* is working from, injected rather than recomputed — a second opinion about
* where the sun is, taken from a clock the scrubber does not own, is how a
* night board and a night layer end up disagreeing.
*/
solarElevationDeg?: number;
}
/** The answer for a board with no feed behind it at all. */
export function emptyBirdsPromotion(): BirdsPromotion {
return {
source: "none",
fetchedAt: new Date(0).toISOString(),
ageMs: null,
field: null,
suppressed: 0,
message:
"No migration feed is configured, so nothing is drawn over this board. " +
"That is a fact about this box, not about the sky.",
};
}
// ---- Exclusion ------------------------------------------------------------
/**
* Is this row a county, or is it the state pretending to be one?
*
* Three independent tests, and they are three rather than one because the one
* that gets missed is never the one you thought of. The `US-CA` row fails all
* three today; a future `US-CA-REGION-N` row with real coordinates would fail
* only the first, and a county whose Census join silently produced nulls would
* fail only the second.
*/
export function isCountyRow(row: WireBirdCounty | null | undefined): boolean {
if (row === null || row === undefined || typeof row !== "object") return false;
if (typeof row.id === "string" && row.id.trim().toUpperCase() === BIRDS_STATE_ROW_ID) return false;
if (finite(row.lat) === null || finite(row.lon) === null) return false;
if ((finite(row.areaKm2) ?? 0) <= 0) return false;
return true;
}
/**
* Every county row, in the order they arrived, with the state row and anything
* unplaceable taken out.
*
* Exported so that `birdsGate.test.ts` can assert the exclusion directly rather
* than inferring it from a rendered field, and so `server/src/birds/index.ts`
* can apply the same rule on the way out.
*/
export function countyRows(rows: readonly WireBirdCounty[]): WireBirdCounty[] {
return rows.filter((row) => isCountyRow(row));
}
// ---- The headline ---------------------------------------------------------
/**
* Last night, from the state row and from nowhere else.
*
* `null` when the body carries no state row, which is the honest answer for a
* box that has been up for less than one night. It is never reconstructed by
* summing counties; see the header.
*/
export function statewideHeadline(body: BirdsBody | null | undefined): MigrationNight | null {
const raw = body?.statewide;
if (raw === null || raw === undefined || typeof raw !== "object") return null;
const crossed = finite(raw.crossed);
const peakAloft = finite(raw.peakAloft);
if (crossed === null || peakAloft === null) return null;
return {
crossed,
peakAloft,
peakAt: typeof raw.peakAt === "string" ? raw.peakAt : "",
meanAltitude: finite(raw.meanAltitude) ?? 0,
heading: typeof raw.heading === "string" && raw.heading !== "" ? raw.heading : "",
};
}
/**
* A bearing as the words a caption uses. `130.3` is "south-east".
*
* Sixteen points would be more precise than the number deserves: the state's own
* mean direction is a circular mean over thousands of ten-minute county rows, and
* "east-south-east" claims a resolution that mean does not carry.
*/
export function headingWords(degrees: number): string {
if (!Number.isFinite(degrees)) return "";
const points = [
"north", "north-east", "east", "south-east",
"south", "south-west", "west", "north-west",
];
const index = Math.round((((degrees % 360) + 360) % 360) / 45) % 8;
return points[index] as string;
}
/**
* An ISO instant in California's own clock, as `23:20 PDT`.
*
* `Intl` rather than a fixed offset, because California is UTC-7 for most of the
* year and UTC-8 for the rest, and a caption that says PDT in January is the
* kind of wrong nobody notices for months. Falls back to the UTC form where
* `Intl` has no time-zone data at all, which is a real configuration of Node.
*/
export function californiaClock(iso: string): string {
const ms = Date.parse(iso);
if (!Number.isFinite(ms)) return "";
try {
return new Intl.DateTimeFormat("en-GB", {
timeZone: "America/Los_Angeles",
hour: "2-digit",
minute: "2-digit",
hour12: false,
timeZoneName: "short",
}).format(new Date(ms));
} catch {
return `${new Date(ms).toISOString().slice(11, 16)} UTC`;
}
}
/**
* The empty sky's sentence.
*
* Always says three things: that nothing is aloft, *why* — which is a fact about
* the instrument and not about the birds — and what last night did, so that a
* viewer who arrives at noon still learns something true. Only the third part is
* conditional, and it is missing only on a box that has not yet seen a night.
*/
export function quietMessage(
reason: MigrationQuiet["reason"],
statewide: MigrationNight | null,
): string {
const why =
reason === "daylight"
? "Nothing is aloft. BirdCast measures migration only after dark."
: reason === "off-season"
? "Nothing is aloft over California tonight. The radars are reporting and every county is quiet."
: "Nothing has answered for the sky over California yet.";
if (statewide === null) return why;
const heading = statewide.heading === "" ? "" : ` heading ${statewide.heading}`;
const peak = statewide.peakAt === "" ? "" : ` at ${californiaClock(statewide.peakAt)}`;
const altitude =
statewide.meanAltitude > 0 ? `, at a mean ${Math.round(statewide.meanAltitude)} metres` : "";
return (
`${why} Last night ${count(statewide.crossed)} birds crossed California${heading}, ` +
`peaking at ${count(statewide.peakAloft)} aloft${peak}${altitude}.`
);
}
// ---- The gate -------------------------------------------------------------
/**
* Apply the ladder to one body.
*
* Pure and total: `null`, a malformed body, or a body from a server one version
* behind all produce an honest empty sky rather than an exception. The consumer
* is a render loop.
*
* **Daylight wins over the feed.** If the sun is up the answer is `daylight`
* whatever arrived, because a daytime BirdCast row is a measurement of something
* the instrument does not measure.
*/
export function promoteBirds(
body: BirdsBody | null | undefined,
options: BirdsPromoteOptions = {},
): BirdsPromotion {
const nowMs = options.nowMs ?? Date.now();
const empty = emptyBirdsPromotion();
if (body === null || body === undefined || typeof body !== "object") return empty;
const fetchedAt = typeof body.fetchedAt === "string" ? body.fetchedAt : empty.fetchedAt;
const fetchedMs = Date.parse(fetchedAt);
const ageMs = Number.isFinite(fetchedMs) && fetchedMs > 0 ? Math.max(0, nowMs - fetchedMs) : null;
const source: BirdsSourceId = body.source === "cloud1" ? "cloud1" : "none";
const observedAt = typeof body.observedAt === "string" ? body.observedAt : "";
const statewide = statewideHeadline(body);
if (ageMs === null) {
// Nothing has ever answered. Not "the sky is empty" — "nobody has spoken".
return { ...empty, source, fetchedAt };
}
const rows = Array.isArray(body.counties) ? body.counties : [];
const placed = countyRows(rows);
const counties: MigrationCounty[] = [];
for (const row of placed) {
const aloft = finite(row.aloft) ?? 0;
if (aloft < BIRDS_MIN_ALOFT) continue;
counties.push({
id: typeof row.id === "string" ? row.id : "",
name: typeof row.name === "string" ? row.name : "",
lat: finite(row.lat) as number,
lng: finite(row.lon) as number,
areaKm2: finite(row.areaKm2) as number,
aloft,
altitude: Math.max(0, finite(row.altitude) ?? 0),
direction: finite(row.direction) ?? 0,
speed: Math.max(0, finite(row.speed) ?? 0),
});
}
counties.sort((a, b) => b.aloft - a.aloft);
const drawn = counties.slice(0, BIRDS_COUNTY_LIMIT);
const suppressed = rows.length - drawn.length;
const sun = options.solarElevationDeg;
const daylight = typeof sun === "number" && Number.isFinite(sun) && sun > BIRDS_MAX_SOLAR_ELEVATION_DEG;
let quiet: MigrationQuiet | null = null;
if (daylight) {
quiet = { reason: "daylight", message: quietMessage("daylight", statewide) };
} else if (drawn.length === 0) {
// Dark, the feed answered, and every county is quiet. Reported as the
// seasonal case rather than as a fault, because that is what it is: the
// store holds two nights and no year of history, so "off-season" is the
// honest name for "dark and nothing flying" until there is one.
const reason: MigrationQuiet["reason"] = body.quiet?.reason === "no-data" ? "no-data" : "off-season";
quiet = { reason, message: quietMessage(reason, statewide) };
}
const field: MigrationField = {
counties: quiet === null ? drawn : [],
observedAt,
statewide,
quiet,
};
return {
source,
fetchedAt,
ageMs,
field,
suppressed: quiet === null ? Math.max(0, suppressed) : rows.length,
message: quiet !== null ? quiet.message : busyMessage(drawn, statewide, observedAt),
};
}
/**
* The sentence for a night with something in it.
*
* Note what it does **not** say: how many birds are over California right now.
* The only way to get that from what crosses the wire is to add the counties up,
* and that is the six-times error. The state row's instantaneous figure is not on
* `MigrationNight`, so the honest headline available here is last night's
* crossing count, and the present tense is spent on where and how high instead.
*/
function busyMessage(
counties: readonly MigrationCounty[],
statewide: MigrationNight | null,
observedAt: string,
): string {
const mean =
counties.length === 0
? 0
: counties.reduce((sum, c) => sum + c.altitude * c.aloft, 0) /
Math.max(1, counties.reduce((sum, c) => sum + c.aloft, 0));
const bearing =
counties.length === 0 ? "" : headingWords(circularMean(counties));
const when = observedAt === "" ? "" : ` As of ${californiaClock(observedAt)}.`;
const last =
statewide === null ? "" : ` Last night ${count(statewide.crossed)} crossed the state.`;
return (
`Birds are aloft over ${counties.length} ` +
`${counties.length === 1 ? "county" : "counties"}` +
`${bearing === "" ? "" : `, drifting ${bearing}`}` +
`${mean > 0 ? `, a mean ${Math.round(mean)} metres up` : ""}.` +
`${last}${when}`
);
}
/**
* The mean direction of travel, weighted by birds aloft — **circularly**.
*
* An arithmetic mean of bearings is wrong at the wrap: 350 and 10 average to 180
* and point the whole state due south when it is flying due north. Tonight's
* rows sit in the 120-150 degree bucket and would survive a naive mean, which is
* exactly why this would ship broken and stay broken.
*/
function circularMean(counties: readonly MigrationCounty[]): number {
let x = 0;
let y = 0;
for (const county of counties) {
const weight = Math.max(0, county.aloft);
const radians = (county.direction * Math.PI) / 180;
x += weight * Math.cos(radians);
y += weight * Math.sin(radians);
}
if (x === 0 && y === 0) return 0;
return (((Math.atan2(y, x) * 180) / Math.PI) + 360) % 360;
}
// ---- Small helpers --------------------------------------------------------
function count(value: number): string {
return Math.round(value).toLocaleString("en-US");
}
function finite(value: unknown): number | null {
return typeof value === "number" && Number.isFinite(value) ? value : null;
}