1
0

Real weather, real aircraft, a heightfield off the main thread, and instruments

Three things that were built and never connected, connected.

**The weather was already there.** `observe()` has always taken a
`WeatherObservation` and `main.ts` has always passed null, so the cloud,
precipitation, visibility and marine-layer paths in atmosphere.ts had never run
outside a test. The server already shipped NWS, met.no and Open-Meteo, all
configured off. What was actually missing was that a single TERA_ORIGIN_LAT/LNG
served one metro and lied to the other — so weather and traffic are per-region
now, derived from the city's own bounds, and the Bay Area gets its fog while
Long Beach gets its own sky. The route takes ?city= or a validated ?lat=&lng=
and refuses to become an open geocoding proxy for the planet.

**The heightfield moved to a Worker.** 2.3 s of blocked main thread at boot, and
another ~950 ms of point-in-polygon on top of it: the park mask is filled in the
worker now, and block placement samples four corners and only runs the exact
test on a cell that straddles an edge — 8 buildings differ out of 185,036.
createScene is async and takes a Stage as a consequence, and there is a
main-thread fallback because "clone it and it works" has no exception clause.

**Spaces is a chunk you fetch when you reach for the door**, not one everybody
downloads. Same for the godmode tools. The entry chunk is 722 kB rather than
772; three.js is most of what is left and splitting it is a different job.

**Godmode is an instrument panel now** rather than one slider: the date and the
season, not just the hour, so the Meeus moon and the sun's seasonal arc become
visible instead of merely correct; a weather override that says on screen when
it is lying; a frame-time and draw-call readout; and a pose editor that emits a
paste-ready Chapter block, which is the thing that makes adding New York cheap.

Two blockers the review caught:

  - Every city switch leaked 8 GPU textures — one of them a 2048x2048 shadow map
    — and ~10.5 shader programs, and deleteTexture had never been called once in
    the app's lifetime. The renderer was being built per scene; it belongs to the
    canvas, for the life of the page.
  - An upstream fetch that threw rather than returning null skipped the cache
    stamp, so the TTL — the only rate limit on outbound calls — collapsed to one
    upstream request per inbound request, and the caller got a 500.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-06 03:25:31 -07:00
parent a6f6a91813
commit e41c90fe8d
39 changed files with 8482 additions and 503 deletions
+72 -5
View File
@@ -86,12 +86,45 @@ export interface Capabilities {
debug: boolean;
}
/**
* Which of the three feeds this deployment has actually wired.
*
* A capability says what a *visitor* may have; this says what the *server* has,
* and the app needs both before it opens a socket. `can.liveData` is true for
* every member of every deployment, including the overwhelming majority that
* have `weather: "none"` — so gating on the capability alone starts a
* ten-minute weather poll against a box that will answer 404 to all of it,
* forever, on every tab that is open.
*
* Each field is `true` when `/health` named a source other than `"none"`, which
* is deliberately coarser than the string. The app does not care whether the
* weather comes from NWS or met.no; it cares whether asking is pointless.
* `flights: "sim"` counts as wired, because the server's synchronised plan is
* worth fetching even though it is not observed — `TrafficSource.live()` is the
* thing that knows the difference, and it says `false` for it.
*/
export interface Feeds {
weather: boolean;
flights: boolean;
markers: boolean;
}
export interface Access {
tier: Tier;
subject: string | null;
/** Where to send someone who is not signed in. `null` means this deployment has no door. */
signInUrl: string | null;
can: Capabilities;
/**
* What `/health` said is wired, or `null` when nothing answered — which is
* the zero-config case, and means every feed is the bundled sample.
*
* It rides along here rather than being fetched again by whoever wants it
* because this module has already paid for the round trip: `/health` is the
* first thing boot asks for, and a second identical GET a moment later to
* read a different field of the same body is a request nobody needs to make.
*/
feeds: Feeds | null;
}
/**
@@ -147,6 +180,7 @@ export function capabilitiesFor(tier: Tier): Capabilities {
export async function resolveAccess(fetcher: typeof fetch = authFetch): Promise<Access> {
const health = await getJson<{
auth?: { mode?: unknown; entryUrl?: unknown };
sources?: unknown;
}>(fetcher, "/health");
// Something is mounted at `/api/v1` and it is unwell. That is not the same
@@ -165,10 +199,11 @@ export async function resolveAccess(fetcher: typeof fetch = authFetch): Promise<
const body = health.body;
const mode = typeof body.auth?.mode === "string" ? body.auth.mode : "none";
const entryUrl = entryHref(body.auth?.entryUrl);
const feeds = feedsFrom(body.sources);
// A box with auth switched off is a self-host that chose to stay open. Same
// deal as no API at all, and for the same reason it is `member` and not `god`.
if (mode === "none") return access("member", null, null);
if (mode === "none") return access("member", null, null, feeds);
const fetched = await getJson<{
authenticated?: unknown;
@@ -211,12 +246,32 @@ export async function resolveAccess(fetcher: typeof fetch = authFetch): Promise<
*/
const signInUrl = entryUrl ?? (passwordLogin ? "/login.html" : null);
if (!authenticated) return access("anon", null, signInUrl);
return access(admin ? "god" : "member", subject, signInUrl);
if (!authenticated) return access("anon", null, signInUrl, feeds);
return access(admin ? "god" : "member", subject, signInUrl, feeds);
}
function access(tier: Tier, subject: string | null, signInUrl: string | null): Access {
return { tier, subject, signInUrl, can: capabilitiesFor(tier) };
function access(
tier: Tier,
subject: string | null,
signInUrl: string | null,
feeds: Feeds | null = null,
): Access {
return { tier, subject, signInUrl, can: capabilitiesFor(tier), feeds };
}
/**
* `/health`'s `sources` block, read as three yes/no answers.
*
* Defensively, like `admin` above and for the same reason: this field is newer
* than some servers this client will meet, and a missing one has to fall the
* safe way. Here "safe" is `false` — no feed, no request — because the bundled
* sample set is a working map and a poll against a server that never heard of
* the route is not.
*/
function feedsFrom(raw: unknown): Feeds {
const sources = (typeof raw === "object" && raw !== null ? raw : {}) as Record<string, unknown>;
const wired = (key: string) => typeof sources[key] === "string" && sources[key] !== "none";
return { weather: wired("weather"), flights: wired("flights"), markers: wired("markers") };
}
/**
@@ -291,6 +346,18 @@ async function getJson<T>(fetcher: typeof fetch, path: string): Promise<Fetched<
*/
function entryHref(raw: unknown): string | null {
if (typeof raw !== "string" || raw === "") return null;
/**
* Before `new URL`, because `new URL` is what hides this one.
*
* A protocol-relative `//evil.example/login` inherits the page's scheme, so
* `url.protocol` comes back `https:` and the check below waves it through —
* the comment above listed it among the rejected set and it was not among the
* rejected set. It is not the `javascript:` case and it is not script
* execution; it is a value an operator pasted, or an API answered with, being
* turned into a link off this origin that says "Sign in" on it. A host that
* wants to be honoured can write its scheme.
*/
if (/^\s*\/\//.test(raw)) return null;
try {
const url = new URL(raw, window.location.origin);
if (url.protocol !== "https:" && url.protocol !== "http:") return null;