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:
+72
-5
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user