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/server/src/flights/plan.ts
T
karti e41c90fe8d 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>
2026-08-06 03:25:31 -07:00

226 lines
8.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* The simulated sky, as a plan rather than as positions.
*
* The engine's `SimulatedFlights` already evaluates a `SimRoute[]` in closed
* form against wall-clock time, so the server has nothing to simulate — it hands
* over the routes, a fixed phase origin and a seed, and every browser arrives at
* the same answer. One cacheable request replaces a poll per second, and two
* people on different machines see the same aircraft in the same places, which
* a per-client simulation cannot promise and which is the point of doing it this
* way.
*
* ### Where the coordinates came from
*
* The seven airport positions — SFO, OAK and SJC in the north, LAX, BUR, LGB and
* SNA in the south — are published FAA airport reference points, typed in by
* hand. They are US government facts in the public domain, and — as with every
* other coordinate in this repo — emphatically not derived from OpenStreetMap.
* Everything else here is a waypoint someone made up so the legs go the right
* way. See ARCHITECTURE.md §3.2 and CONTRACT.md §8.
*
* The callsigns are invented, with operator prefixes that belong to nobody. A
* repo that refuses to ship other people's logos should not ship their flight
* numbers either.
*/
import type { WireSimRoute } from "../../../src/server/wire.ts";
const SFO: [number, number] = [37.6188, -122.375];
const OAK: [number, number] = [37.7213, -122.2207];
const SJC: [number, number] = [37.3639, -121.9289];
/**
* Departures climb, arrivals descend, and a third of the traffic is just passing
* through at cruise. That mix is what makes the sky read as a working airspace
* rather than a carousel.
*/
const BAY_AREA: WireSimRoute[] = [
// Departures — out over the Pacific, north-east over the Central Valley, and
// south down the peninsula.
{ callsign: "LMB231", from: SFO, to: [37.3, -123.2], fromAlt: 20, toAlt: 10500, duration: 420 },
{ callsign: "LMB778", from: SFO, to: [38.4, -121.3], fromAlt: 20, toAlt: 11000, duration: 480 },
{ callsign: "PAC1082", from: SFO, to: [38.6, -122.9], fromAlt: 20, toAlt: 10000, duration: 460 },
{ callsign: "BAY412", from: OAK, to: [37.0, -121.2], fromAlt: 20, toAlt: 9500, duration: 400 },
{ callsign: "SIE1440", from: SJC, to: [36.6, -121.6], fromAlt: 20, toAlt: 9800, duration: 430 },
// Arrivals — the long descent over Point Reyes, the south-east downwind, and
// the two east-bay finals.
{ callsign: "GLD566", from: [38.3, -123.1], to: SFO, fromAlt: 6000, toAlt: 20, duration: 500 },
{ callsign: "LMB1889", from: [37.1, -121.6], to: SFO, fromAlt: 5500, toAlt: 20, duration: 520 },
{ callsign: "RDW915", from: [37.9, -121.3], to: OAK, fromAlt: 5200, toAlt: 20, duration: 470 },
{ callsign: "PAC331", from: [38.1, -122.3], to: SJC, fromAlt: 5800, toAlt: 20, duration: 540 },
// Overflights, level the whole way.
{
callsign: "GLD55",
from: [38.8, -122.6],
to: [36.6, -121.4],
fromAlt: 11000,
toAlt: 11000,
duration: 620,
},
{
callsign: "PAC21",
from: [37.9, -121.4],
to: [37.2, -123.4],
fromAlt: 10500,
toAlt: 10500,
duration: 700,
},
{
callsign: "RDW1205",
from: [36.5, -122.4],
to: [38.9, -122.0],
fromAlt: 10800,
toAlt: 10800,
duration: 660,
},
// Low and slow across the bay: general aviation is most of what is actually
// visible from the ground, and it is the only traffic that reads as *near*.
{
callsign: "BAY7789",
from: [37.45, -122.1],
to: [38.05, -122.45],
fromAlt: 900,
toAlt: 900,
duration: 520,
},
{
callsign: "SIE4402",
from: [37.95, -122.55],
to: [37.35, -121.85],
fromAlt: 1400,
toAlt: 1400,
duration: 560,
},
];
const LAX: [number, number] = [33.9425, -118.4081];
const BUR: [number, number] = [34.2007, -118.3585];
const LGB: [number, number] = [33.8177, -118.1516];
const SNA: [number, number] = [33.6757, -117.8682];
/**
* The Southland, which is a different shape of airspace and not a translated
* copy of the Bay Area.
*
* Almost everything here runs eastwest, because the terrain does: the basin is
* walled by the San Gabriels to the north, so departures go out over the water
* and turn, and arrivals come down the length of the valley. Four fields instead
* of three, and the two small ones matter more than they do in the north — a
* board four times the area at a third of the scale reads as empty very fast if
* everything is at cruise.
*/
const SOCAL: WireSimRoute[] = [
// Departures — the standard west-over-the-ocean climb, the north-east haul
// over the Cajon Pass, and the two valley fields going their own way.
{ callsign: "LMB604", from: LAX, to: [33.6, -119.3], fromAlt: 20, toAlt: 10500, duration: 440 },
{ callsign: "PAC712", from: LAX, to: [34.6, -117.1], fromAlt: 20, toAlt: 11500, duration: 520 },
{ callsign: "SIE288", from: BUR, to: [34.9, -118.9], fromAlt: 20, toAlt: 9800, duration: 460 },
{ callsign: "BAY1516", from: SNA, to: [33.1, -118.6], fromAlt: 20, toAlt: 9600, duration: 420 },
{ callsign: "GLD843", from: LGB, to: [34.5, -116.9], fromAlt: 20, toAlt: 10200, duration: 500 },
// Arrivals — the long straight-in from the east, the coastal descent from the
// north-west, and one down the back of the mountains into Burbank.
{ callsign: "LMB1170", from: [34.1, -116.8], to: LAX, fromAlt: 6200, toAlt: 20, duration: 560 },
{ callsign: "RDW425", from: [34.7, -119.4], to: LAX, fromAlt: 6800, toAlt: 20, duration: 600 },
{ callsign: "PAC96", from: [34.8, -117.6], to: BUR, fromAlt: 5400, toAlt: 20, duration: 480 },
{ callsign: "SIE1901", from: [33.2, -117.2], to: SNA, fromAlt: 5000, toAlt: 20, duration: 450 },
// Overflights, level the whole way: the coastal corridor and the desert one.
{
callsign: "GLD1330",
from: [34.9, -119.2],
to: [32.9, -117.0],
fromAlt: 11200,
toAlt: 11200,
duration: 690,
},
{
callsign: "RDW78",
from: [33.0, -119.1],
to: [34.9, -116.8],
fromAlt: 10600,
toAlt: 10600,
duration: 720,
},
// Low across the basin. General aviation is most of what anybody standing in
// Culver City actually sees, and it is the only traffic that reads as *near*.
{
callsign: "BAY3312",
from: [33.78, -118.42],
to: [34.16, -117.75],
fromAlt: 850,
toAlt: 850,
duration: 540,
},
{
callsign: "LMB2044",
from: [34.22, -118.72],
to: [33.72, -117.98],
fromAlt: 1300,
toAlt: 1300,
duration: 570,
},
];
/**
* The airspaces this file has actually laid out, and how close a region's centre
* has to be to get one.
*
* Degrees rather than kilometres because the comparison is a box, not a circle,
* and the radii are generous: the Bay Area's is roughly downtown to the far end
* of the bay, and the Southland's spans a basin that runs from Ventura to
* Riverside. A region centre that lands inside one of these is close enough that
* the real airports are the right answer; anything else gets spokes.
*/
const AIRSPACES: { centre: [number, number]; radius: number; routes: WireSimRoute[] }[] = [
{ centre: [37.7749, -122.4194], radius: 0.75, routes: BAY_AREA },
{ centre: [33.82, -118.05], radius: 1.0, routes: SOCAL },
];
/**
* A plan for a city this file has never heard of.
*
* A self-hoster pointing `TERA_REGIONS` (or `TERA_ORIGIN_LAT/LNG`) at somewhere
* that is neither of the two boards should get moving aircraft rather than an
* empty sky, so eight legs are laid out on evenly-spaced bearings through the
* region centre. It is not their city's real airspace and does not pretend to be
* — it is motion in the right kind of place, which is all the map ever wanted
* from this.
*/
function genericPlan(lat: number, lng: number): WireSimRoute[] {
const routes: WireSimRoute[] = [];
const span = 0.55;
for (let i = 0; i < 8; i++) {
const bearing = (i / 8) * Math.PI * 2;
const dLat = Math.cos(bearing) * span;
const dLng = (Math.sin(bearing) * span) / Math.max(0.2, Math.cos((lat * Math.PI) / 180));
const cruise = 8000 + (i % 4) * 900;
routes.push({
callsign: `LMB${100 + i * 37}`,
from: [lat - dLat, lng - dLng],
to: [lat + dLat, lng + dLng],
fromAlt: i % 3 === 0 ? 600 : cruise,
toAlt: cruise,
duration: 380 + i * 45,
});
}
return routes;
}
export function planFor(centre: { lat: number; lng: number }): WireSimRoute[] {
for (const airspace of AIRSPACES) {
const [lat, lng] = airspace.centre;
if (
Math.abs(centre.lat - lat) < airspace.radius &&
Math.abs(centre.lng - lng) < airspace.radius
) {
return airspace.routes;
}
}
return genericPlan(centre.lat, centre.lng);
}