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:
+52
-3
@@ -27,8 +27,8 @@
|
||||
* without data that exercises it.
|
||||
*/
|
||||
|
||||
import type { SimRoute } from "../engine/flights.ts";
|
||||
import type { Marker, MarkerPalette } from "../engine/types.ts";
|
||||
import { regionOf, syntheticRoutes, type SimRoute } from "../engine/flights.ts";
|
||||
import type { City, Marker, MarkerPalette } from "../engine/types.ts";
|
||||
|
||||
/**
|
||||
* A small pipeline, as colours.
|
||||
@@ -287,7 +287,8 @@ export const SAMPLE_MARKERS: Marker[] = [
|
||||
];
|
||||
|
||||
/**
|
||||
* Sample traffic, for when the API is not there to send a flight plan.
|
||||
* Sample traffic over the Bay Area, for when the API is not there to send a
|
||||
* flight plan.
|
||||
*
|
||||
* The corridors are roughly the real ones — arrivals down the peninsula from
|
||||
* the north, departures turning out over the Pacific, a slow light aircraft
|
||||
@@ -296,6 +297,11 @@ export const SAMPLE_MARKERS: Marker[] = [
|
||||
* these prefixes, which keeps a demo from looking like a feed of actual
|
||||
* traffic. Nothing here is observed, and `flights.ts` explains at length why
|
||||
* this project ships a simulator instead of a client for somebody's live data.
|
||||
*
|
||||
* The unqualified name is a leftover and is kept because the app imports it.
|
||||
* Every leg in it is over San Francisco, which is only the right answer for one
|
||||
* of the two cities in this build; `sampleRoutesFor` is the entry point that
|
||||
* knows the difference.
|
||||
*/
|
||||
export const SAMPLE_ROUTES: SimRoute[] = [
|
||||
{ callsign: "NIMBUS 4", from: [37.95, -122.36], to: [37.66, -122.4], fromAlt: 2400, toAlt: 500, duration: 190 },
|
||||
@@ -306,3 +312,46 @@ export const SAMPLE_ROUTES: SimRoute[] = [
|
||||
{ callsign: "KESTREL 5", from: [37.83, -122.56], to: [37.7, -122.22], fromAlt: 1100, toAlt: 1300, duration: 300 },
|
||||
{ callsign: "NIMBUS 40", from: [37.96, -122.48], to: [37.63, -122.36], fromAlt: 3100, toAlt: 600, duration: 205 },
|
||||
];
|
||||
|
||||
/**
|
||||
* Sample traffic over the Los Angeles basin.
|
||||
*
|
||||
* The same idea as `SAMPLE_ROUTES` and it exists because that one was being
|
||||
* flown over both cities: the SoCal board would come up with a sky whose every
|
||||
* aircraft was nearly six hundred kilometres north of it, off the edge of the world
|
||||
* and therefore invisible. A city that renders an empty sky looks like a city
|
||||
* whose flight layer failed.
|
||||
*
|
||||
* Again the geography is roughly right and the callsigns are invented. LAX runs
|
||||
* west almost always, so the arrivals here come in from the east over the
|
||||
* basin and the departures go out over the water before turning; Burbank sits
|
||||
* up the valley behind the hills, and the light aircraft is following the coast
|
||||
* because in this basin that is what they do.
|
||||
*/
|
||||
export const SAMPLE_SOCAL_ROUTES: SimRoute[] = [
|
||||
{ callsign: "CONDOR 6", from: [34.02, -117.45], to: [33.945, -118.36], fromAlt: 3500, toAlt: 400, duration: 330 },
|
||||
{ callsign: "CONDOR 21", from: [33.99, -117.29], to: [33.94, -118.33], fromAlt: 4100, toAlt: 450, duration: 360 },
|
||||
{ callsign: "AVOCET 12", from: [33.945, -118.42], to: [34.15, -118.84], fromAlt: 500, toAlt: 5200, duration: 190 },
|
||||
{ callsign: "AVOCET 30", from: [33.68, -117.87], to: [33.34, -118.4], fromAlt: 600, toAlt: 4800, duration: 210 },
|
||||
{ callsign: "CURLEW 3", from: [33.36, -117.3], to: [33.69, -117.86], fromAlt: 4200, toAlt: 500, duration: 235 },
|
||||
{ callsign: "TOWHEE 9", from: [34.33, -118.82], to: [34.2, -118.36], fromAlt: 3000, toAlt: 450, duration: 175 },
|
||||
{ callsign: "CONDOR 44", from: [34.36, -118.66], to: [33.32, -117.28], fromAlt: 9200, toAlt: 9800, duration: 300 },
|
||||
{ callsign: "SANDPIPER 4", from: [33.6, -118.02], to: [34.03, -118.62], fromAlt: 900, toAlt: 1100, duration: 330 },
|
||||
];
|
||||
|
||||
/**
|
||||
* The right sample sky for a city, and something defensible for a city nobody
|
||||
* has drawn one for.
|
||||
*
|
||||
* Keyed on `city.id` rather than on position because the hand-placed corridors
|
||||
* are the whole value here: knowing that arrivals come down the peninsula and
|
||||
* that LAX departs to the west is knowledge about two named places, and there
|
||||
* is no way to derive it from a bounding box. What *can* be derived is legs
|
||||
* that are at least in the right region, which is what `syntheticRoutes` does
|
||||
* and what any third city gets until somebody sits down with a chart.
|
||||
*/
|
||||
export function sampleRoutesFor(city: Pick<City, "id" | "center" | "bounds">): SimRoute[] {
|
||||
if (city.id === "sf") return SAMPLE_ROUTES;
|
||||
if (city.id === "socal") return SAMPLE_SOCAL_ROUTES;
|
||||
return syntheticRoutes(regionOf(city));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user