/** * Southern California — Los Angeles, Orange County and Riverside, as one Tera * city pack. * * Pure data, and traced by hand from scratch for the same reason San Francisco * was: OpenStreetMap is ODbL, ODbL is share-alike, and a share-alike obligation * cannot live inside an Apache-2.0 repo without infecting it. Every coastline, * ridge and district boundary below is original expression. See * ARCHITECTURE.md §3.2. * * **This is not San Francisco with more rows.** SF is 0.20° × 0.36°, a city you * can hold in one frame at 45 m cells. The frame that actually holds Malibu, * Catalina, the San Gabriel crest and downtown Riverside is 1.08° × 1.66° — a * little over twenty-five times the area. ARCHITECTURE.md §5 estimated fourteen * from a tighter box; the argument only gets stronger with the real one. A * uniform 45 m lattice over this would be close to nine million points and a * mesh nobody can load, so the pack declares seven `focusRegions` at 80 m and * lets the basin between them run at 480 m. That is the whole reason those two * fields exist. * * The second thing that does not transfer is scale. The engine's camera is * capped at 340 units from its target and its fog closes at 460, so a city has * to fit inside roughly the same scene footprint whatever its size on the * ground. San Francisco gets 94 m to the scene unit; Southern California gets * 391. Everything downstream follows from that one number: a building lot is * 164 m rather than 40, a "building" is really a city block, and the towers are * small because at this remove they genuinely are. LA's story from above is not * its skyline. It is a basin ninety kilometres across with a three-kilometre * wall along the north side of it, and that is what this file is arranged to * show. */ import type { Airport } from "../engine/airports.ts"; import type { Bridge, City, District, FocusRegion, Hill, Landmark, LatLng, Port, } from "../engine/types.ts"; // ---- Coastlines ----------------------------------------------------------- /** * The mainland, traced west to east along the shore and then closed off-frame. * * The order of the coast is the order of the drive: down the Malibu shelf, * around the curve of Santa Monica Bay, out onto the Palos Verdes headland, in * through the harbour, along the Long Beach and Orange County strand, and off * at San Mateo Point where the county line is. * * Two features carry the whole silhouette. **Santa Monica Bay** is a genuine * arc — the shore turns roughly sixty degrees between the Malibu shelf, which * runs almost due east, and the South Bay strand, which runs almost due south — * and getting that curve wrong makes the map read as anywhere. **Palos Verdes** * is the blunt headland that closes the bay's south end; without it Los Angeles * has no southern edge at all and the harbour makes no sense. * * The last three vertices are deliberately outside `bounds`. The world's * coastal falloff ramps relief to zero near *any* polygon edge, including an * artificial one, so a boundary drawn on the frame line would leave a flattened * band of basin along the north and east of the map. Pushed off-frame, the * falloff lands on lattice points that are never sampled. */ export const SOUTHLAND: LatLng[] = [ // North-west, off-frame [34.4, -119.02], // The Malibu shelf, west -> east. The mountains come straight down to the // water here, which is why there is one road and no city. [34.06, -118.98], // the Ventura county line, at Leo Carrillo [34.038, -118.93], [34.023, -118.87], // Nicholas Canyon [34.017, -118.828], // Zuma [33.996, -118.806], // Point Dume — the only headland on this stretch [34.01, -118.79], // Paradise Cove [34.026, -118.76], [34.034, -118.72], [34.036, -118.678], // Malibu Pier and the lagoon [34.039, -118.635], [34.04, -118.585], // Topanga Canyon meets the sea [34.038, -118.56], [34.037, -118.525], // Will Rogers // Santa Monica Bay. The shore swings from east-west to north-south over // about twenty kilometres; this is the curve the eye recognises. [34.028, -118.51], [34.009, -118.498], // Santa Monica Pier [33.99, -118.482], [33.977, -118.472], // Venice Pier [33.965, -118.458], [33.958, -118.452], // the Marina and Ballona Creek mouth [33.945, -118.44], // Dockweiler, directly under LAX's departures [33.928, -118.433], [33.905, -118.421], // El Segundo [33.884, -118.411], // Manhattan Beach Pier [33.862, -118.403], // Hermosa Pier [33.844, -118.393], // Redondo and King Harbor [33.822, -118.392], // The Palos Verdes peninsula: uplifted marine terraces, a blunt nose to the // south-west, and cliffs the whole way round. [33.806, -118.396], // Malaga Cove — the terraces begin [33.79, -118.406], [33.771, -118.412], // Bluff Cove [33.752, -118.416], [33.742, -118.41], // Point Vicente [33.735, -118.39], [33.733, -118.365], // Portuguese Bend [33.727, -118.34], [33.718, -118.318], // Royal Palms [33.708, -118.3], [33.705, -118.294], // Point Fermin, the southern tip of the mainland // The Port of Los Angeles and Long Beach. The trace runs up the main channel // to Wilmington and back down the far side, which leaves the outer harbour as // open water with Terminal Island sitting in the middle of it. [33.712, -118.282], // Cabrillo Beach [33.726, -118.278], [33.746, -118.276], // the San Pedro waterfront [33.762, -118.274], [33.774, -118.27], // the head of the main channel, at Wilmington [33.778, -118.25], [33.776, -118.232], // west Long Beach and the Dominguez Channel [33.766, -118.222], [33.76, -118.213], // the Long Beach container terminals [33.766, -118.198], // Queensway [33.762, -118.186], [33.76, -118.17], [33.759, -118.15], [33.757, -118.135], // Belmont Shore [33.748, -118.12], [33.742, -118.112], // the mouth of Alamitos Bay [33.74, -118.1], // Seal Beach // The Orange County strand: forty kilometres of almost unbroken sand, then // the coast turns and climbs into the San Joaquin Hills. [33.734, -118.078], [33.722, -118.068], // Surfside and Sunset Beach [33.706, -118.058], [33.69, -118.044], // Bolsa Chica [33.672, -118.02], [33.656, -118.0], // Huntington Beach Pier [33.64, -117.978], [33.63, -117.96], // the Santa Ana River mouth [33.618, -117.942], [33.608, -117.929], // Newport Pier [33.598, -117.9], [33.593, -117.881], // the harbour entrance, off the end of the Balboa peninsula [33.59, -117.872], // Corona del Mar [33.583, -117.855], [33.57, -117.833], // Crystal Cove [33.556, -117.806], [33.542, -117.783], // Laguna Beach, where the hills reach the water [33.526, -117.766], [33.51, -117.753], // Aliso Beach [33.494, -117.732], [33.488, -117.725], // Salt Creek [33.47, -117.712], [33.462, -117.706], // Dana Point — the last headland on this map [33.46, -117.69], // Doheny, at the mouth of San Juan Creek [33.446, -117.667], [33.428, -117.63], [33.418, -117.615], // the San Clemente pier [33.4, -117.598], [33.386, -117.593], // San Mateo Point, the San Diego county line // Off-frame, closing round the east and north. Camp Pendleton, the high // desert and San Bernardino are all past the edge of this board. [33.24, -117.5], [33.2, -117.16], [34.4, -117.14], ]; /** * Terminal Island: dredge spoil, container cranes and a federal prison, sitting * between San Pedro and Long Beach. * * ### Why this outline is thirty-one points and not six * * It used to be six, and its own comment said what those six were for: "the * harbour reads as a harbour only if there is something in it for the two * bridges to land on." A hexagon is enough to land a bridge on and it is not * enough to be a port, because **the recognisable thing about this island is not * its outline, it is the comb cut into it** — the West Basin and the East Basin * opening north off the Cerritos Channel, Fish Harbor opening south, the Pier * 400 fill hung off a causeway in the south-east, and a quay along the wall of * every one of them. With six points there is nowhere for a quay to be that is * both on land and on the water, which is the one thing a quay has to be. * * Traced by hand, like every other coordinate in this file, and per * ARCHITECTURE §3.2 that means it is eyeball-accurate original expression rather * than a copy of anybody's dataset. `ports.sqlite` cannot help: its seven rows * all sit on an exact arc-minute grid, up to 1.3 km — 3.3 scene units here — * from the water they claim to be on. See `engine/ports.ts`. * * ### What the shape has to satisfy * * - **The two bridges still land on it.** The Vincent Thomas's east abutment * `[33.7535, -118.258]` and the Long Beach Gateway's west abutment * `[33.752, -118.232]` are both inside this ring, and both of their mainland * ends are still outside it. `socalPorts.test.ts` asserts all four. * - **It does not touch the mainland.** The narrowest water left between the two * is 425 m of Main Channel at the Vincent Thomas and about 500 m of Back * Channel off Pier T, which is what those channels really are. * - **Every authored quay vertex lies inside it.** That is the assertion that * stops a quay floating on open water or being buried in the fill behind it, * and it is why the basins are cut 900-1,000 m deep rather than token * notches: a quay wall wants a kilometre of straight water frontage. * * Five and a half kilometres east to west, six north to south, which at 391 m to * the scene unit is about 14 by 15 units on a 393-unit board. */ export const TERMINAL_ISLAND: LatLng[] = [ // The north shore, along the Cerritos (Back) Channel, west to east, with the // two basins cut southward into it. [33.7672, -118.2665], // the north-west corner, at the mouth of the West Basin [33.759, -118.2618], // the West Basin, west wall [33.7602, -118.2555], // the head of the West Basin [33.769, -118.2582], // back out to the Cerritos Channel [33.7688, -118.247], // the Badger Avenue rail bridge [33.758, -118.2452], // the East Basin, west wall [33.7588, -118.2382], // the head of the East Basin [33.7672, -118.2378], // back out [33.7635, -118.2295], // under the Long Beach International Gateway [33.7595, -118.221], // Pier T, north-west [33.7548, -118.2125], // Pier T, north-east, at the Middle Harbor slip // The east end, on Queensway Bay. [33.747, -118.2105], [33.743, -118.216], // The south shore, east to west, on the outer harbour. [33.7405, -118.2245], [33.7398, -118.233], // The causeway down to the Pier 400 fill, and the fill itself. The neck is // 556 m across, which is a road, two rail tracks and their shoulders. [33.7345, -118.2352], // the causeway, east side [33.729, -118.2372], [33.7285, -118.23], // Pier 400, north-east [33.7155, -118.233], // Pier 400, south-east [33.715, -118.2495], // Pier 400, south-west [33.729, -118.252], // Pier 400, north-west [33.7288, -118.2432], [33.7343, -118.2412], // the causeway, west side [33.738, -118.244], // Fish Harbor, cut in from the south. The cannery basin, and the one part of // this island that predates the container. [33.7378, -118.256], [33.735, -118.2572], [33.7352, -118.264], [33.7398, -118.2652], [33.742, -118.2698], // the south-west corner, at Reservation Point // The west shore, up the Main Channel. [33.7505, -118.2708], // under the Vincent Thomas [33.759, -118.2692], ]; /** * Santa Catalina, thirty-five kilometres offshore. * * It earns its place twice over: it is the one thing in the south-west quarter * of the frame that is not empty water, and on the days you can actually see it * from the mainland it is the reason anyone believes the basin has a horizon. * Long and thin, north-west to south-east, pinched almost in two at the isthmus * above Two Harbors. */ export const CATALINA: LatLng[] = [ [33.475, -118.6], // the West End [33.462, -118.565], [33.4425, -118.5], // the isthmus at Two Harbors [33.428, -118.462], [33.408, -118.428], [33.39, -118.395], // Long Point [33.362, -118.348], [33.3425, -118.328], // Avalon [33.318, -118.305], // the East End [33.308, -118.322], [33.332, -118.362], [33.36, -118.408], [33.388, -118.452], [33.412, -118.492], [33.432, -118.535], [33.455, -118.592], ]; /** Everything the buildings may stand on. */ export const LANDMASSES = [SOUTHLAND, TERMINAL_ISLAND, CATALINA]; // ---- Parks and open space ------------------------------------------------- /** * Open space does two jobs here. It paints the ranges green, and — because * `blocks.ts` refuses to build inside a park — it is what keeps the procedural * scatter off the mountains without needing a slope test in the engine. * * These polygons are drawn to the *shape of the wild land*, not to any agency's * boundary. The Angeles National Forest polygon is really "the San Gabriels", * and its southern edge is the range front: the line where the suburbs stop * dead and the mountain starts, which in this metro is a line you can see from * space. */ /** The San Gabriels. The south edge is the range front, Sylmar to Cajon. */ export const ANGELES_FOREST: LatLng[] = [ [34.38, -118.52], [34.38, -117.32], [34.22, -117.38], [34.18, -117.45], [34.155, -117.57], [34.145, -117.7], [34.16, -117.79], [34.17, -117.9], [34.175, -117.99], [34.185, -118.05], [34.21, -118.13], [34.235, -118.2], [34.27, -118.3], [34.305, -118.4], [34.32, -118.47], ]; /** The Santa Susanas, closing the San Fernando Valley off to the north-west. */ export const SANTA_SUSANA: LatLng[] = [ [34.33, -118.72], [34.33, -118.56], [34.25, -118.57], [34.24, -118.7], ]; /** * The Santa Monica Mountains, Malibu to Griffith Park. * * A single east-west band forty kilometres long and rarely more than eight * wide. It matters structurally: this is the wall that separates the coastal * plain from the San Fernando Valley, and every crossing of it — Sepulveda, * Cahuenga, Topanga — is a pass with a freeway or a boulevard in it. */ export const SANTA_MONICA_MOUNTAINS: LatLng[] = [ [34.132, -118.93], [34.135, -118.7], [34.138, -118.56], [34.132, -118.5], [34.125, -118.455], [34.118, -118.42], [34.108, -118.38], [34.092, -118.345], [34.08, -118.36], [34.076, -118.425], [34.072, -118.472], [34.062, -118.525], [34.043, -118.6], [34.04, -118.7], [34.045, -118.82], [34.05, -118.93], ]; /** Griffith Park — the east end of the Santa Monicas, inside the city. */ export const GRIFFITH_PARK: LatLng[] = [ [34.15, -118.32], [34.148, -118.28], [34.11, -118.28], [34.105, -118.32], ]; /** Elysian Park, the ridge Dodger Stadium sits on top of. */ export const ELYSIAN_PARK: LatLng[] = [ [34.09, -118.25], [34.089, -118.232], [34.07, -118.235], [34.072, -118.252], ]; export const EXPOSITION_PARK: LatLng[] = [ [34.021, -118.292], [34.0205, -118.279], [34.01, -118.28], [34.011, -118.293], ]; /** * The Baldwin Hills: a low dome of oil derricks and scrub between Culver City * and the airport, and the only relief on the whole coastal plain. */ export const BALDWIN_HILLS: LatLng[] = [ [34.013, -118.39], [34.012, -118.35], [33.988, -118.354], [33.99, -118.393], ]; /** The Sepulveda Basin — a flood-control bowl doubling as the Valley's park. */ export const SEPULVEDA_BASIN: LatLng[] = [ [34.185, -118.505], [34.184, -118.46], [34.16, -118.462], [34.162, -118.506], ]; export const HANSEN_DAM: LatLng[] = [ [34.28, -118.4], [34.279, -118.365], [34.255, -118.367], [34.257, -118.402], ]; /** The Arroyo Seco, running south out of the range through Pasadena. */ export const ARROYO_SECO: LatLng[] = [ [34.2, -118.185], [34.199, -118.16], [34.125, -118.168], [34.126, -118.19], ]; /** The Puente Hills — the ridge that divides the basin from the inland valleys. */ export const PUENTE_HILLS: LatLng[] = [ [33.995, -118.06], [33.99, -117.86], [33.945, -117.87], [33.95, -118.065], ]; export const SAN_JOSE_HILLS: LatLng[] = [ [34.055, -117.88], [34.05, -117.77], [34.005, -117.78], [34.01, -117.89], ]; export const CHINO_HILLS: LatLng[] = [ [33.97, -117.78], [33.96, -117.63], [33.86, -117.66], [33.88, -117.8], ]; /** * The Santa Ana Mountains — Cleveland National Forest, and the reason Orange * County ends where it does. Traced down the western flank and back up the * eastern one, so the band follows the ridge instead of boxing it. */ export const SANTA_ANA_MOUNTAINS: LatLng[] = [ [33.9, -117.68], [33.8, -117.63], [33.7, -117.585], [33.61, -117.52], [33.53, -117.47], [33.49, -117.36], [33.59, -117.39], [33.69, -117.43], [33.79, -117.48], [33.89, -117.545], ]; /** The San Joaquin Hills, which is why Laguna is a cove town and not a grid. */ export const SAN_JOAQUIN_HILLS: LatLng[] = [ [33.63, -117.85], [33.62, -117.74], [33.55, -117.72], [33.54, -117.81], [33.58, -117.85], ]; /** Loma Ridge and the Irvine Ranch open space, along the back of Irvine. */ export const LOMA_RIDGE: LatLng[] = [ [33.79, -117.76], [33.78, -117.66], [33.72, -117.69], [33.73, -117.79], ]; /** The seaward slope of Palos Verdes, above the terraces. */ export const PALOS_VERDES_OPEN: LatLng[] = [ [33.77, -118.405], [33.762, -118.36], [33.73, -118.3355], [33.715, -118.36], [33.735, -118.4], ]; /** Catalina's interior, which is conservancy land nearly end to end. */ export const CATALINA_INTERIOR: LatLng[] = [ [33.47, -118.59], [33.44, -118.5], [33.39, -118.42], [33.34, -118.34], [33.33, -118.355], [33.38, -118.44], [33.43, -118.52], [33.455, -118.595], ]; /** Mount Rubidoux and Fairmount Park, downtown Riverside's green edge. */ export const RUBIDOUX: LatLng[] = [ [33.995, -117.398], [33.993, -117.378], [33.975, -117.38], [33.977, -117.4], ]; /** Box Springs Mountain, the brown lump east of Riverside. */ export const BOX_SPRINGS: LatLng[] = [ [33.97, -117.3], [33.965, -117.24], [33.915, -117.25], [33.92, -117.31], ]; export const JURUPA_HILLS: LatLng[] = [ [34.015, -117.49], [34.01, -117.42], [33.985, -117.425], [33.99, -117.495], ]; export const EL_DORADO_PARK: LatLng[] = [ [33.81, -118.09], [33.809, -118.075], [33.79, -118.076], [33.791, -118.091], ]; export const PARKS = [ ANGELES_FOREST, SANTA_SUSANA, SANTA_MONICA_MOUNTAINS, GRIFFITH_PARK, ELYSIAN_PARK, EXPOSITION_PARK, BALDWIN_HILLS, SEPULVEDA_BASIN, HANSEN_DAM, ARROYO_SECO, PUENTE_HILLS, SAN_JOSE_HILLS, CHINO_HILLS, SANTA_ANA_MOUNTAINS, SAN_JOAQUIN_HILLS, LOMA_RIDGE, PALOS_VERDES_OPEN, CATALINA_INTERIOR, RUBIDOUX, BOX_SPRINGS, JURUPA_HILLS, EL_DORADO_PARK, ]; // ---- Rivers and inland water ---------------------------------------------- /** * The Los Angeles River, from the Glendale Narrows to the sea. * * Two compromises are baked into this polygon and both are worth stating. * * The channel is drawn about four times its true width. At 391 m to the scene * unit the real thing is narrower than a single coarse terrain cell, and a * feature narrower than the lattice does not render as a thin line — it renders * as a dotted one, appearing only where a cell corner happens to land inside * it. Five hundred metres is the smallest width that guarantees every lattice * row crossing the river has a point inside it. * * And it is only traced from the Narrows down. The engine has no river * primitive, so inland water sits at sea level and the terrain around it does * not, which means a channel reads as a trench as deep as the local ground is * high. Below downtown the plain is under a hundred metres and the trench looks * like a floodplain, which is fair. Through the San Fernando Valley the ground * is over two hundred, and the same trick would have cut a canyon across the * Valley floor. The Valley reach is a soft-bottom wash anyway; leaving it out * costs the map less than drawing it wrong. */ export const LA_RIVER: LatLng[] = [ // east bank, north -> south [34.125, -118.267], [34.1, -118.242], [34.075, -118.227], [34.05, -118.222], [34.02, -118.212], [33.99, -118.202], [33.96, -118.192], [33.92, -118.187], [33.88, -118.187], [33.84, -118.192], [33.8, -118.195], [33.775, -118.202], [33.76, -118.202], // west bank, south -> north [33.76, -118.208], [33.775, -118.208], [33.8, -118.201], [33.84, -118.198], [33.88, -118.193], [33.92, -118.193], [33.96, -118.198], [33.99, -118.208], [34.02, -118.218], [34.05, -118.228], [34.075, -118.233], [34.1, -118.248], [34.125, -118.273], ]; /** * The Santa Ana River, out of the Prado basin and across Orange County. * * It is on the map because it is the organising line of the whole county: the * ranchos were surveyed off it, the cities sit on it, and it explains why the * grid on one side of Anaheim does not match the grid on the other. */ export const SANTA_ANA_RIVER: LatLng[] = [ [33.945, -117.545], [33.895, -117.62], [33.878, -117.69], [33.868, -117.77], [33.852, -117.83], [33.81, -117.875], [33.762, -117.895], [33.71, -117.925], [33.665, -117.95], [33.633, -117.963], [33.627, -117.957], [33.66, -117.944], [33.705, -117.919], [33.757, -117.889], [33.805, -117.869], [33.847, -117.824], [33.863, -117.764], [33.873, -117.684], [33.89, -117.614], [33.94, -117.539], ]; /** Upper Newport Bay and the harbour — Orange County's one real estuary. */ export const NEWPORT_BAY: LatLng[] = [ [33.665, -117.888], [33.66, -117.879], [33.63, -117.883], [33.615, -117.89], [33.598, -117.89], [33.596, -117.899], [33.612, -117.908], [33.625, -117.908], [33.642, -117.896], [33.66, -117.896], ]; export const ALAMITOS_BAY: LatLng[] = [ [33.748, -118.118], [33.746, -118.105], [33.738, -118.106], [33.74, -118.12], ]; export const MARINA_DEL_REY: LatLng[] = [ [33.98, -118.452], [33.979, -118.438], [33.97, -118.439], [33.971, -118.453], ]; export const BALLONA_WETLANDS: LatLng[] = [ [33.967, -118.44], [33.966, -118.418], [33.956, -118.419], [33.957, -118.441], ]; export const BOLSA_CHICA: LatLng[] = [ [33.705, -118.06], [33.702, -118.04], [33.685, -118.045], [33.688, -118.064], ]; /** Silver Lake Reservoir. Small, but a chapter is named after it. */ export const SILVER_LAKE: LatLng[] = [ [34.098, -118.273], [34.097, -118.267], [34.086, -118.268], [34.087, -118.274], ]; export const SEPULVEDA_LAKE: LatLng[] = [ [34.176, -118.488], [34.175, -118.477], [34.168, -118.478], [34.169, -118.489], ]; export const PUDDINGSTONE: LatLng[] = [ [34.093, -117.815], [34.092, -117.802], [34.085, -117.803], [34.086, -117.816], ]; export const SANTIAGO_RESERVOIR: LatLng[] = [ [33.77, -117.725], [33.768, -117.705], [33.745, -117.71], [33.748, -117.73], ]; export const PRADO_BASIN: LatLng[] = [ [33.9, -117.66], [33.895, -117.63], [33.87, -117.635], [33.875, -117.665], ]; export const LAKE_MATHEWS: LatLng[] = [ [33.87, -117.46], [33.868, -117.42], [33.838, -117.425], [33.842, -117.465], ]; export const LAKE_ELSINORE: LatLng[] = [ [33.7, -117.39], [33.69, -117.335], [33.64, -117.32], [33.63, -117.355], [33.66, -117.395], ]; export const INLAND_WATER = [ LA_RIVER, SANTA_ANA_RIVER, NEWPORT_BAY, ALAMITOS_BAY, MARINA_DEL_REY, BALLONA_WETLANDS, BOLSA_CHICA, SILVER_LAKE, SEPULVEDA_LAKE, PUDDINGSTONE, SANTIAGO_RESERVOIR, PRADO_BASIN, LAKE_MATHEWS, LAKE_ELSINORE, ]; // ---- Relief --------------------------------------------------------------- /** * The mountains, and the reason Los Angeles is a basin at all. * * San Francisco's relief is hills every four blocks. Southern California's is * the opposite shape: a flat floor a hundred kilometres wide with ranges around * the rim. Read clockwise from the north-west, the rim is the Santa Susanas, * the San Gabriels — three thousand metres and effectively a wall — the San * Bernardino front off the east edge of the frame, the Santa Anas behind Orange * County, and the San Joaquin Hills coming back to the sea at Laguna. Inside * the rim, only four things break the floor: the Santa Monica Mountains running * east-west through the middle of the city, the Verdugos, the Puente Hills, and * Palos Verdes out on its own. * * **Spacing is a constraint, not an accident.** `World.elevationAt` combines * overlapping peaks as `tallest + 35% of the rest`, which is what stops a ridge * having a notch in the middle of it — but it also means two summits closer * together than their radii will read taller than either. The San Gabriel crest * is therefore laid out as well-separated peaks with generous radii: neighbours * still overlap enough to build a continuous wall, but no summit is inflated by * more than about fifteen per cent. Where you see a peak missing that ought to * be there — Cahuenga next to Mount Lee, Ontario next to Baldy — it was left * out on purpose, because including it would have grown a mountain that is not * there. * * The five entries at the end are not hills. They are the basins themselves, * declared as very broad, very low domes so the map keeps the tilt that Los * Angeles actually has: the beach is at sea level, downtown is at ninety * metres, the Valley is at two hundred and Riverside is at two hundred and * sixty. Being broad, they contribute almost nothing to the summits above them. */ export const HILLS: Hill[] = [ // ---- The San Gabriels: the wall ---- { name: "Mount Gleason", lat: 34.335, lng: -118.185, elevation: 1901, radius: 0.105, }, { name: "Mount Lukens", lat: 34.278, lng: -118.243, elevation: 1547, radius: 0.085, }, { name: "Josephine Peak", lat: 34.268, lng: -118.148, elevation: 1710, radius: 0.075, }, { name: "Mount Wilson", lat: 34.226, lng: -118.062, elevation: 1742, radius: 0.09, }, { name: "Mount Waterman", lat: 34.328, lng: -117.94, elevation: 2440, radius: 0.105, }, { name: "Mount Islip", lat: 34.315, lng: -117.85, elevation: 2469, radius: 0.085, }, { name: "Mount Baden-Powell", lat: 34.356, lng: -117.765, elevation: 2867, radius: 0.095, }, // Mount Baldy is the high point of the whole map and the thing you look for // from anywhere in the basin on a clear day. { name: "Mount Baldy", lat: 34.289, lng: -117.646, elevation: 3068, radius: 0.13, }, { name: "Cucamonga Peak", lat: 34.221, lng: -117.59, elevation: 2670, radius: 0.095, }, { name: "Cajon Shoulder", lat: 34.235, lng: -117.42, elevation: 1500, radius: 0.085, }, // The front-range foothills, so the wall has a toe. Without these the range // starts abruptly in mid-air above Pasadena, which is exactly wrong: the // whole drama of the San Gabriel front is how little runway it takes. { name: "Altadena Front", lat: 34.202, lng: -118.13, elevation: 900, radius: 0.05, }, { name: "Monrovia Peak", lat: 34.213, lng: -117.98, elevation: 1600, radius: 0.065, }, { name: "Glendora Ridge", lat: 34.18, lng: -117.83, elevation: 1100, radius: 0.06, }, { name: "Claremont Front", lat: 34.172, lng: -117.68, elevation: 1000, radius: 0.055, }, { name: "Oat Mountain", lat: 34.305, lng: -118.615, elevation: 1128, radius: 0.07, }, { name: "Santa Susana Knolls", lat: 34.268, lng: -118.66, elevation: 640, radius: 0.045, }, // ---- The Verdugos and the San Rafaels ---- // A compact ridge standing alone in the middle of the metro, which is why // Glendale and Burbank are two cities and not one. { name: "Verdugo Peak", lat: 34.228, lng: -118.285, elevation: 940, radius: 0.048, }, { // Moved north-east, from 34.205/-118.33 with a 0.04 radius, when Burbank // Airport went onto the board and stood on a hillside. A 700 m peak whose // falloff is 4.4 km across, sited half a kilometre north of runway 08/26, // put 478 m of mountain on the 26 threshold and 191 m on the 08 threshold — // a nine-degree slope across a field that is, in life, flat. It also had // downtown Burbank sitting 165 m up a ramp. The ridge crest above Burbank // really is at about 34.22, and this is where it belongs; the change reads // as the Verdugos ending in the right place rather than leaning on the // Valley floor. `socalAirports.test.ts` holds every field to the relief it // may stand on, so this cannot quietly come back. name: "Mount Thom", lat: 34.221, lng: -118.318, elevation: 720, radius: 0.036, }, { name: "San Rafael Hills", lat: 34.17, lng: -118.215, elevation: 500, radius: 0.04, }, // ---- The Santa Monica Mountains ---- { name: "Castro Peak", lat: 34.073, lng: -118.755, elevation: 787, radius: 0.048, }, { name: "Saddle Peak", lat: 34.086, lng: -118.648, elevation: 878, radius: 0.045, }, { name: "Topanga Ridge", lat: 34.093, lng: -118.598, elevation: 700, radius: 0.04, }, { name: "Temescal Peak", lat: 34.09, lng: -118.545, elevation: 692, radius: 0.042, }, // Held west of the pass and kept tight. The Sepulveda Pass is the gap the 405 // uses to get from the Westside to the Valley, and a hill spilling into it // would close the only door in a forty-kilometre wall. { name: "San Vicente Mountain", lat: 34.108, lng: -118.5, elevation: 590, radius: 0.03, }, { name: "Getty Ridge", lat: 34.081, lng: -118.477, elevation: 280, radius: 0.024, }, { name: "Stone Canyon", lat: 34.104, lng: -118.44, elevation: 380, radius: 0.03, }, { name: "Franklin Canyon", lat: 34.115, lng: -118.41, elevation: 420, radius: 0.03, }, // Mount Lee carries the Hollywood sign on its south face. Cahuenga Peak is // nine hundredths of a degree away and is deliberately absent: summed in, the // pair would have made an eight-hundred-metre mountain over Hollywood. { name: "Mount Lee", lat: 34.134, lng: -118.321, elevation: 517, radius: 0.03, }, { name: "Mount Hollywood", lat: 34.128, lng: -118.3, elevation: 500, radius: 0.032, }, { name: "Elysian Hills", lat: 34.083, lng: -118.24, elevation: 160, radius: 0.022, }, // ---- Inside the basin ---- { name: "Baldwin Hills", lat: 34.0, lng: -118.372, elevation: 156, radius: 0.03, }, { name: "Repetto Hills", lat: 34.03, lng: -118.12, elevation: 180, radius: 0.032, }, { name: "Dominguez Hills", lat: 33.865, lng: -118.243, elevation: 65, radius: 0.018, }, // Signal Hill is tiny and it is here anyway: a bare oil-derrick knob rising // straight out of flat Long Beach, and one of the few points in the south of // the basin you can orient off. { name: "Signal Hill", lat: 33.804, lng: -118.167, elevation: 111, radius: 0.013, }, // ---- Palos Verdes ---- { name: "San Pedro Hill", lat: 33.748, lng: -118.352, elevation: 448, radius: 0.035, }, { name: "Palos Verdes Bluff", lat: 33.766, lng: -118.398, elevation: 240, radius: 0.022, }, { name: "Point Fermin Rise", lat: 33.716, lng: -118.302, elevation: 130, radius: 0.018, }, // ---- The Puente, San Jose and Chino hills ---- { name: "Whittier Hills", lat: 33.975, lng: -118.03, elevation: 400, radius: 0.038, }, { name: "Workman Hill", lat: 33.96, lng: -117.9, elevation: 430, radius: 0.042, }, { name: "San Jose Hills", lat: 34.03, lng: -117.83, elevation: 470, radius: 0.038, }, { name: "Chino Hills", lat: 33.925, lng: -117.72, elevation: 500, radius: 0.055, }, // ---- The Santa Anas ---- { name: "Sierra Peak", lat: 33.878, lng: -117.635, elevation: 1120, radius: 0.055, }, { name: "Pleasants Peak", lat: 33.795, lng: -117.578, elevation: 1200, radius: 0.05, }, { name: "Santiago Peak", lat: 33.71, lng: -117.532, elevation: 1734, radius: 0.075, }, { name: "Trabuco Peak", lat: 33.66, lng: -117.49, elevation: 1370, radius: 0.055, }, { name: "Ortega Ridge", lat: 33.6, lng: -117.44, elevation: 1100, radius: 0.055, }, { name: "Loma Ridge", lat: 33.76, lng: -117.72, elevation: 480, radius: 0.045, }, { name: "Anaheim Hills", lat: 33.85, lng: -117.74, elevation: 350, radius: 0.04, }, // ---- The San Joaquin Hills ---- { name: "Signal Peak", lat: 33.605, lng: -117.815, elevation: 320, radius: 0.038, }, { name: "Laguna Ridge", lat: 33.56, lng: -117.76, elevation: 300, radius: 0.032, }, { name: "San Onofre Hills", lat: 33.43, lng: -117.57, elevation: 280, radius: 0.04, }, // ---- The Inland Empire ---- { name: "Box Springs Mountain", lat: 33.94, lng: -117.27, elevation: 1030, radius: 0.045, }, { name: "Jurupa Hills", lat: 34.0, lng: -117.46, elevation: 550, radius: 0.035, }, { name: "Mount Rubidoux", lat: 33.984, lng: -117.386, elevation: 395, radius: 0.014, }, { name: "Sycamore Canyon", lat: 33.93, lng: -117.32, elevation: 480, radius: 0.025, }, { name: "La Sierra Hills", lat: 33.9, lng: -117.47, elevation: 400, radius: 0.03, }, { name: "Norco Hills", lat: 33.92, lng: -117.52, elevation: 350, radius: 0.03, }, { name: "Slover Mountain", lat: 34.055, lng: -117.33, elevation: 400, radius: 0.02, }, // ---- Catalina ---- { name: "Mount Orizaba", lat: 33.383, lng: -118.418, elevation: 648, radius: 0.042, }, { name: "Silver Peak", lat: 33.455, lng: -118.56, elevation: 486, radius: 0.03, }, { name: "Avalon Ridge", lat: 33.352, lng: -118.345, elevation: 400, radius: 0.022, }, // ---- The floors ---- // Not mountains. Broad low domes that give each basin the elevation it really // has, so the map keeps its inland tilt instead of rendering ninety // kilometres of dead flat at sea level. { name: "Los Angeles Plain", lat: 34.03, lng: -118.23, elevation: 95, radius: 0.16, }, { name: "San Fernando Valley Floor", lat: 34.195, lng: -118.45, elevation: 220, radius: 0.18, }, { name: "San Gabriel Valley Floor", lat: 34.08, lng: -117.94, elevation: 140, radius: 0.18, }, { name: "Inland Empire Floor", lat: 33.95, lng: -117.4, elevation: 260, radius: 0.17, }, { name: "Orange County Plain", lat: 33.76, lng: -117.88, elevation: 45, radius: 0.14, }, ]; // ---- Streets and freeways ------------------------------------------------- /** * In San Francisco the line that had to be drawn first was Market Street. Here * it is the freeways, all of them, because in this metro they are the only * lines long enough to tie two hundred square kilometres of identical grid * together. Nobody navigates Los Angeles by neighbourhood; they navigate it by * which freeway they are on. * * Widths are smaller than San Francisco's for the same paths because they are * in scene units and a scene unit here is four times as long: 0.14 is a * fifty-metre freeway and 0.1 a thirty-seven-metre boulevard, which is about * right for both. */ /** I-405, Sylmar to El Toro, through the Sepulveda Pass. */ export const I405: LatLng[] = [ [34.282, -118.468], [34.24, -118.472], [34.2, -118.47], [34.16, -118.468], [34.13, -118.472], [34.1, -118.472], // the Sepulveda Pass [34.07, -118.456], [34.04, -118.43], [34.01, -118.403], [33.98, -118.39], // Moved east from -118.386 when LAX went onto the board: at that longitude the // freeway ran across the 25R touchdown zone, and the real 405 passes about // three kilometres east of the airport, not through it. [33.945, -118.3765], // past LAX [33.91, -118.372], [33.875, -118.35], [33.85, -118.315], [33.834, -118.272], [33.826, -118.23], [33.82, -118.19], [33.8, -118.13], [33.775, -118.075], [33.745, -118.01], [33.72, -117.955], [33.69, -117.9], // Added when John Wayne went onto the board: without it this leg cut the // corner and drew a freeway straight across runway 02L/20R. The real 405 // passes about a kilometre north-west of the field and meets the 55 beyond it. [33.6885, -117.87], [33.678, -117.845], [33.66, -117.78], [33.63, -117.7], ]; /** I-5, Sylmar to San Clemente. The one road that crosses the whole board. */ export const I5: LatLng[] = [ [34.32, -118.46], [34.27, -118.42], [34.23, -118.39], // These two replace a single vertex at 34.19/-118.36, which ran the Golden // State diagonally across Burbank's runway 08/26. The real 5 comes down the // far side of Hollywood Way, north-east of the field — which is why the // airport's north-east corner is cut off the way it is, and why `BUR`'s 08/26 // stops 700 m short of the freeway. [34.222, -118.368], [34.196, -118.338], [34.16, -118.335], [34.13, -118.28], [34.105, -118.25], [34.08, -118.235], [34.055, -118.225], [34.035, -118.205], [34.01, -118.17], [33.98, -118.13], [33.94, -118.09], [33.9, -118.06], [33.87, -118.025], [33.84, -117.98], [33.8, -117.92], [33.76, -117.87], [33.72, -117.82], [33.68, -117.78], [33.63, -117.7], [33.58, -117.66], [33.52, -117.63], [33.46, -117.63], [33.42, -117.61], [33.39, -117.59], ]; /** US-101, Woodland Hills to downtown, over the Cahuenga Pass. */ export const US101: LatLng[] = [ [34.165, -118.62], [34.16, -118.56], [34.155, -118.5], [34.15, -118.44], [34.145, -118.39], [34.138, -118.355], [34.125, -118.34], // the Cahuenga Pass [34.105, -118.33], [34.095, -118.31], [34.085, -118.29], [34.075, -118.265], [34.06, -118.24], ]; /** I-10, the pier at Santa Monica to Colton. */ export const I10: LatLng[] = [ [34.018, -118.493], [34.025, -118.46], [34.03, -118.42], [34.033, -118.38], [34.038, -118.34], [34.04, -118.3], [34.038, -118.265], [34.04, -118.235], [34.045, -118.2], [34.052, -118.15], [34.06, -118.1], [34.065, -118.04], [34.068, -117.96], [34.065, -117.88], [34.06, -117.8], [34.062, -117.7], [34.065, -117.6], [34.068, -117.5], [34.07, -117.4], [34.072, -117.3], ]; /** I-110, the Arroyo Seco Parkway down to the harbour. */ export const I110: LatLng[] = [ [34.135, -118.165], [34.115, -118.19], [34.098, -118.213], [34.08, -118.228], [34.065, -118.257], [34.045, -118.267], [34.02, -118.276], [33.99, -118.281], [33.95, -118.283], [33.91, -118.283], [33.87, -118.284], [33.83, -118.287], [33.8, -118.29], [33.77, -118.29], [33.745, -118.287], ]; /** I-210, the Foothill Freeway, running the whole length of the range front. */ export const I210: LatLng[] = [ [34.3, -118.45], [34.27, -118.38], [34.25, -118.32], [34.235, -118.25], [34.21, -118.19], [34.175, -118.14], [34.15, -118.09], [34.135, -118.03], [34.13, -117.95], [34.125, -117.87], [34.115, -117.8], [34.108, -117.72], [34.105, -117.64], [34.11, -117.56], [34.115, -117.46], [34.118, -117.38], [34.115, -117.3], ]; /** SR-91, Torrance to Riverside. The commute the Inland Empire was built on. */ export const SR91: LatLng[] = [ [33.87, -118.38], [33.87, -118.32], [33.868, -118.26], [33.865, -118.2], [33.862, -118.14], [33.86, -118.07], [33.858, -118.0], [33.86, -117.93], [33.862, -117.86], [33.865, -117.79], [33.87, -117.72], [33.875, -117.64], [33.89, -117.56], // the Santa Ana Canyon [33.92, -117.49], [33.945, -117.44], [33.96, -117.38], [33.965, -117.32], ]; /** SR-60, downtown to Riverside the inland way, over the Puente Hills. */ export const SR60: LatLng[] = [ [34.04, -118.22], [34.033, -118.18], [34.028, -118.13], [34.02, -118.07], [34.015, -118.0], [34.01, -117.93], [33.995, -117.86], [33.98, -117.8], [33.97, -117.72], [33.955, -117.64], [33.945, -117.56], [33.94, -117.48], [33.94, -117.4], [33.945, -117.32], ]; /** SR-57, Anaheim to Pomona. */ export const SR57: LatLng[] = [ [33.79, -117.88], [33.82, -117.885], [33.86, -117.885], [33.9, -117.88], [33.94, -117.875], [33.98, -117.86], [34.02, -117.84], [34.06, -117.83], ]; /** I-605, along the San Gabriel River. */ export const I605: LatLng[] = [ [34.14, -117.99], [34.1, -118.0], [34.05, -118.04], [34.0, -118.07], [33.95, -118.09], [33.9, -118.105], [33.85, -118.11], [33.8, -118.105], [33.77, -118.1], ]; /** I-105, the Century Freeway, LAX to Norwalk. */ export const I105: LatLng[] = [ [33.928, -118.39], [33.927, -118.34], [33.926, -118.29], [33.925, -118.24], [33.924, -118.19], [33.922, -118.14], [33.92, -118.09], ]; /** I-15, Lake Elsinore to the mouth of Cajon Pass. */ export const I15: LatLng[] = [ [33.72, -117.46], [33.78, -117.49], [33.84, -117.52], [33.9, -117.53], [33.96, -117.54], [34.02, -117.55], [34.08, -117.55], [34.14, -117.51], [34.2, -117.46], [34.26, -117.44], ]; /** * SR-1, Pacific Coast Highway. It hugs the shore from Malibu to Redondo, cuts * inland across the neck of the Palos Verdes peninsula because there is no room * to go round it, and picks the coast back up in Long Beach. */ export const PCH: LatLng[] = [ [34.043, -118.87], [34.03, -118.83], [34.0, -118.805], [34.03, -118.75], [34.036, -118.68], [34.039, -118.6], [34.037, -118.53], [34.018, -118.5], [33.995, -118.483], [33.97, -118.462], [33.942, -118.44], [33.92, -118.43], [33.89, -118.415], [33.86, -118.4], [33.84, -118.392], [33.81, -118.39], [33.79, -118.36], [33.78, -118.32], [33.775, -118.29], [33.78, -118.24], [33.775, -118.2], [33.77, -118.16], [33.76, -118.12], [33.745, -118.1], [33.725, -118.07], [33.7, -118.05], [33.67, -118.01], [33.64, -117.97], [33.62, -117.93], [33.6, -117.88], [33.58, -117.84], [33.55, -117.79], [33.52, -117.75], [33.48, -117.72], [33.46, -117.69], [33.43, -117.63], ]; /** * Wilshire Boulevard, downtown to the pier. Twenty-six kilometres, four grids, * and the only street that connects every part of the Westside to the core. */ export const WILSHIRE: LatLng[] = [ [34.048, -118.256], [34.057, -118.276], [34.061, -118.3], [34.062, -118.33], [34.063, -118.36], [34.067, -118.39], [34.067, -118.415], [34.06, -118.44], [34.053, -118.455], [34.043, -118.47], [34.03, -118.483], [34.018, -118.493], ]; /** Sunset Boulevard, Echo Park to the sea, along the foot of the hills. */ export const SUNSET: LatLng[] = [ [34.062, -118.238], [34.078, -118.26], [34.085, -118.285], [34.098, -118.31], [34.098, -118.34], [34.095, -118.37], [34.09, -118.39], [34.085, -118.415], [34.078, -118.44], [34.07, -118.47], [34.06, -118.5], [34.045, -118.52], [34.038, -118.53], ]; /** Ventura Boulevard, running the south edge of the Valley under the hills. */ export const VENTURA_BLVD: LatLng[] = [ [34.156, -118.64], [34.155, -118.58], [34.152, -118.52], [34.15, -118.46], [34.148, -118.4], [34.142, -118.37], ]; /** Colorado Boulevard. Dead straight and due east-west, unlike downtown. */ export const COLORADO_BLVD: LatLng[] = [ [34.146, -118.198], [34.146, -118.165], [34.1465, -118.135], [34.147, -118.105], [34.147, -118.07], ]; /** Katella Avenue — one rung of Orange County's mile grid, past the parks. */ export const KATELLA: LatLng[] = [ [33.803, -118.01], [33.803, -117.96], [33.8025, -117.92], [33.802, -117.88], [33.802, -117.84], [33.8015, -117.79], ]; /** * ## The runways are no longer roads * * `LAX_RUNWAYS_NORTH` and `LAX_RUNWAYS_SOUTH` used to live here: two hand-typed * two-point paths lying on **33.9535 and 33.9405 due east–west**, handed to * `createRoads` as `kind: "street"`, because a pale strip on flat ground was as * close as the road builder could get to an airport. Both numbers were wrong in * the same way. LAX's runways are not due east–west — they run **82.9° true**, * which over three and a half kilometres is four hundred metres of drift the * pair did not have — and there are four of them, not two. `AIRPORTS` below * draws the real ones, with the paint on them, the fill under them and the * horseshoe between them. * * **The two cannot both be present.** A road ribbon drapes 0.14 units above the * terrain — fifty-five metres at this board's scale — while a runway quad sits * flush on it, so a board carrying both floats a dark stripe over every runway * in Westchester. The Bay Area pack hit this first and photographed it. * * `runwayCentreline()` in `engine/airports.ts` reproduces a runway as a * two-point path, if anything ever wants one as a line again. */ export const ROADS: City["roads"] = [ { path: I405, width: 0.14, kind: "freeway" }, { path: I5, width: 0.14, kind: "freeway" }, { path: US101, width: 0.13, kind: "freeway" }, { path: I10, width: 0.14, kind: "freeway" }, { path: I110, width: 0.13, kind: "freeway" }, { path: I210, width: 0.13, kind: "freeway" }, { path: SR91, width: 0.13, kind: "freeway" }, { path: SR60, width: 0.12, kind: "freeway" }, { path: SR57, width: 0.11, kind: "freeway" }, { path: I605, width: 0.12, kind: "freeway" }, { path: I105, width: 0.11, kind: "freeway" }, { path: I15, width: 0.13, kind: "freeway" }, { path: PCH, width: 0.1, kind: "street" }, { path: WILSHIRE, width: 0.09, kind: "street" }, { path: SUNSET, width: 0.08, kind: "street" }, { path: VENTURA_BLVD, width: 0.08, kind: "street" }, { path: COLORADO_BLVD, width: 0.08, kind: "street" }, { path: KATELLA, width: 0.08, kind: "street" }, ]; // ---- Bridges -------------------------------------------------------------- /** * Two harbour crossings, and they are the only bridges on this map that are * worth the geometry — nothing else in the metro spans water rather than * freeway. * * A caveat for whoever renders these. `bridges.ts` now sizes members in metres * over metres-per-unit rather than in the fixed scene-unit constants that were * tuned at San Francisco's 94 m per unit, so these are no longer four times too * heavy — but the legibility floor under that arithmetic still is a floor, and * at 391 m per unit it is what makes this pair read a little chunkier than life. * They are kept because the port is one of the three or four silhouettes that * say Southern California from above. */ /** The Vincent Thomas, over the main channel. Green, and suspension. */ export const VINCENT_THOMAS: Bridge = { name: "Vincent Thomas Bridge", path: [ [33.748, -118.285], [33.75, -118.276], [33.7515, -118.268], [33.7535, -118.258], ], towers: [ [33.75, -118.276], [33.7515, -118.268], ], towerHeight: 111, deckHeight: 56, sag: 0.5, color: 0x3f7d55, }; /** * The Long Beach International Gateway, over the back channel. Cable-stayed * rather than suspension, so the sag is a third of the Vincent Thomas's — the * cables here run straight to the deck instead of hanging from a catenary. */ export const LONG_BEACH_GATEWAY: Bridge = { name: "Long Beach International Gateway", path: [ [33.752, -118.232], [33.7555, -118.222], [33.759, -118.213], [33.762, -118.204], ], towers: [ [33.7555, -118.222], [33.759, -118.213], ], towerHeight: 157, deckHeight: 62, sag: 0.3, color: 0xdfe3e6, }; export const BRIDGES = [VINCENT_THOMAS, LONG_BEACH_GATEWAY]; // ---- Ports ---------------------------------------------------------------- /** * San Pedro Bay: Los Angeles and Long Beach, one basin, two ports. * * Together they are the busiest container complex in the western hemisphere, and * until this block existed the Harbour chapter said so over a picture of nothing * at all. `engine/ports.ts` draws all of it in four draw calls; this is the data * it draws. * * ### Everything below is hand-traced, and the store cannot help * * ARCHITECTURE §3.2 applies here exactly as it does to the coastline. Beyond * that, the upstream `ports` table is unusable for placement even if the licence * allowed it: all seven of its rows sit on an exact arc-minute grid — `lat*60` * and `lon*60` are whole integers for every one — and one arc-minute at this * latitude is 1,852 m of latitude and 1,540 m of longitude, so a quay placed * from those columns lands as much as 3.3 scene units from the water. Its * `channel_depth_ft` is worse: a binned WPI code that reports Los Angeles as * fourteen feet deep against a real dredged channel near fifty-three. * `socalPorts.test.ts` asserts that neither anchor below is on an arc-minute. * * The one column of that table which *is* load-bearing is `harbor_type`: USLAX * and USLGB are both `CB`, coastal breakwater, and they share the federal * breakwater declared on `LOS_ANGELES` below. Oakland is `CN`, coastal natural, * and when the Bay board gets this kit it must not be given one. * * ### The empty boxes are the story, and they are a fact about a port * * The owner asked whether the ships are empty or full. They cannot be: there is * no draught column in the vessel store, the AIS static message that would carry * one is absent for most hulls most of the time, and a per-hull laden state * would be an invention. The same question answered at the level where the data * is real is far better anyway — in July 2026, **348,691 of the 460,467 * containers that left Los Angeles left empty**, which is 75.7 per cent, and a * second collector explains it from the other side: a box costs $7,491 to bring * east across the Pacific and $347 to send back. Nobody pays to repatriate an * empty, so three quarters of them go home with nothing in them. * * That number is drawn, not just written: `Yard.emptyShare` is the proportion of * stacks the yard atlas paints in the empty palette. **It is the empty share of * the month's outbound boxes, not a census of what is standing in the yard * today** — nobody counts that — and it is applied here because the export * stacks are the large majority of what an American west-coast yard holds. * * ### Why Long Beach carries no `throughput` record * * Its export split is known and is nearly identical to LA's: 341,806 empty * against 104,843 loaded, 76.5 per cent. Its *import* halves were never read. * `PortThroughput` requires all four counts, and a record with two real numbers * and two plausible ones is precisely the failure the fire layer nearly shipped, * so Long Beach gets no record rather than half of one. Its yards still carry * the 0.765 that is measured. */ /** * The federal breakwater — three arms, two gates, 13.06 km of rubble. * * San Pedro (3.46 km) from the shore below Cabrillo out to the Angels Gate * light; the Middle Breakwater (5.61 km); and the Long Beach arm (3.99 km) * running east toward Alamitos Bay. The 589 m gap between the first two is * Angels Gate, the main entrance, and the 703 m between the second and third is * Queens Gate. * * This is the object that makes the whole board's south-west corner read as a * harbour rather than a bay: 13.06 km is 33.4 scene units on a 393-unit board, * about nine per cent of its width, and it is the only part of this port that is * legible from the whole-board pose. It is drawn wider than life — see * `BREAKWATER_BASE_M` and its floor in `engine/ports.ts` — for the reason the * LA River polygon is drawn four times its true width a few hundred lines above: * a feature narrower than a lattice cell does not render as a thin line, it * renders as a dotted one. */ const SAN_PEDRO_BREAKWATER: LatLng[][] = [ [ [33.7065, -118.2885], // rooted off Cabrillo Beach [33.7048, -118.274], [33.707, -118.262], [33.7083, -118.2517], // the Angels Gate light ], [ [33.7095, -118.2455], // the Middle Breakwater, west end [33.712, -118.227], [33.7145, -118.206], [33.7165, -118.1855], // Queens Gate, west side ], [ [33.7175, -118.178], // the Long Beach arm, west end [33.719, -118.156], [33.72, -118.135], ], ]; /** * The Port of Los Angeles. * * Four container terminals on the west and south of Terminal Island, forty * gantries between them, and the Main Channel running up from Angels Gate past * the Vincent Thomas to the turning basin at Wilmington. * * The crane bearings are the whole of the recognition and they are all * different: Pier 400 leans west over the outer harbour, Pier 300 south, the * East Basin west into its slip and the West Basin east into its own. A port * where every boom points the same way reads as a fence. */ export const LOS_ANGELES: Port = { id: "USLAX", name: "Port of Los Angeles", // The middle of Terminal Island, hand-placed. Deliberately not // `ports.sqlite`'s 33.75 / -118.25, which is an arc-minute rounding. lat: 33.7508, lng: -118.2604, harborType: "CB", breakwater: SAN_PEDRO_BREAKWATER, channel: [ [33.698, -118.247], // the approach, outside the breakwater [33.709, -118.2486], // through Angels Gate [33.72, -118.258], [33.732, -118.267], [33.743, -118.2731], [33.751, -118.2732], // under the Vincent Thomas [33.762, -118.2711], [33.7688, -118.269], // the turning basin at the head ], /** * Quay polygons, **water edge first**. * * That ordering is a contract with `engine/ports.ts`, which takes the first * two vertices as the wall and drops the skirt and the revetment toe from * them. A polygon traced the other way round hangs its wall off the back of * the terminal, where nothing can see it and the water edge is a bare cut. */ quays: [ { id: "pier-400", deckHeight: 4, polygon: [ [33.7284, -118.2516], [33.7157, -118.2493], [33.7158, -118.2481], [33.7286, -118.2503], ], }, { id: "pier-300", deckHeight: 4, polygon: [ [33.7382, -118.2448], [33.738, -118.2552], [33.7391, -118.2553], [33.7393, -118.2448], ], }, { id: "east-basin", deckHeight: 4, polygon: [ [33.7594, -118.2379], [33.7666, -118.2376], [33.7665, -118.2363], [33.7594, -118.2366], ], }, { id: "west-basin", deckHeight: 4, polygon: [ [33.7603, -118.2629], [33.7655, -118.2658], [33.7651, -118.267], [33.7598, -118.264], ], }, ], /** * Berths, for the vessel layer that will lie hulls along them. * * `bearing` is the bow of a ship alongside, and it is authored here rather * than read off the wire because the wire cannot answer it: of 150 vessels in * the store sitting under half a knot, only 75 report a usable heading and 21 * report neither heading nor course. A berth has one answer and it never * changes. */ berths: [ { id: "lax-401", lat: 33.7268, lng: -118.2518, bearing: 171.6, maxLength: 400, quayId: "pier-400" }, { id: "lax-402", lat: 33.7236, lng: -118.2512, bearing: 171.6, maxLength: 400, quayId: "pier-400" }, { id: "lax-403", lat: 33.7204, lng: -118.2507, bearing: 171.6, maxLength: 400, quayId: "pier-400" }, { id: "lax-404", lat: 33.7172, lng: -118.2501, bearing: 171.6, maxLength: 400, quayId: "pier-400" }, { id: "lax-306", lat: 33.7378, lng: -118.2474, bearing: 268.9, maxLength: 366, quayId: "pier-300" }, { id: "lax-305", lat: 33.7377, lng: -118.2526, bearing: 268.9, maxLength: 366, quayId: "pier-300" }, { id: "lax-226", lat: 33.7612, lng: -118.2383, bearing: 2.3, maxLength: 335, quayId: "east-basin" }, { id: "lax-232", lat: 33.7648, lng: -118.2381, bearing: 2.3, maxLength: 335, quayId: "east-basin" }, { id: "lax-136", lat: 33.7618, lng: -118.2632, bearing: 334.9, maxLength: 366, quayId: "west-basin" }, { id: "lax-142", lat: 33.7644, lng: -118.2646, bearing: 334.9, maxLength: 366, quayId: "west-basin" }, ], /** * Crane rows. Forty gantries in four records. * * `height` is rail to the top of the portal beam; the raised boom tip stands * about half as high again, which at this board's 3.4x exaggeration is 1.13 * scene units — taller than a 400 m ship is long. `idleFraction` is taken from * the far end of each rail by `craneStations`, so a partly-worked berth looks * like a block of booms down over a ship and the rest stood off, which is what * one looks like. */ cranes: [ { id: "pier-400", from: [33.7284, -118.2514], to: [33.7157, -118.2492], count: 18, bearing: 261.6, height: 82, outreach: 72, idleFraction: 0.17, }, { id: "pier-300", from: [33.7384, -118.2448], to: [33.7382, -118.2553], count: 8, bearing: 178.9, height: 78, outreach: 68, idleFraction: 0.38, }, { id: "east-basin", from: [33.7594, -118.2377], to: [33.7666, -118.2374], count: 6, bearing: 272.3, height: 74, outreach: 61, idleFraction: 0.5, }, { id: "west-basin", from: [33.7602, -118.263], to: [33.7655, -118.266], count: 8, bearing: 64.9, height: 78, outreach: 68, idleFraction: 0.25, }, ], /** * The yards. `emptyShare` is 0.757 on every one of them — 348,691 of 460,467 * — and it is the number the atlas paints, not a number in a caption. */ yards: [ { id: "pier-400", lat: 33.7223, lng: -118.2433, length: 1420, width: 1130, bearing: 172, emptyShare: 0.757 }, { id: "pier-300", lat: 33.7412, lng: -118.252, length: 1210, width: 600, bearing: 90, emptyShare: 0.757 }, { id: "east-basin", lat: 33.761, lng: -118.2351, length: 820, width: 480, bearing: 2, emptyShare: 0.757 }, { id: "west-basin", lat: 33.753, lng: -118.2649, length: 1260, width: 570, bearing: 350, emptyShare: 0.757 }, /** * The on-dock rail yard in the middle of the island, and **the one rectangle * here with no `emptyShare` on it**. * * Nobody publishes what is standing in it. `emptyShare` absent is what the * type means by unknown, and `yardAtlas` draws an unknown yard in one flat * colour rather than in a plausible-looking mix — so the board carries a * visible difference between a number that was measured and a number that * was not, which is the whole discipline this product is trying to keep. */ { id: "rail-yard", lat: 33.7498, lng: -118.2502, length: 1150, width: 470, bearing: 350 }, ], /** July 2026. `asOf` is the month these counts describe and is never "now". */ throughput: { asOf: "2026-07", loadedExport: 111_776, emptyExport: 348_691, loadedImport: 499_552, emptyImport: 446, }, /** * The explanation, from a different collector entirely. * * No timestamp, deliberately: the store's `observed_at` is our own read clock, * Freightos publishes none, and a card that renders it as "as of" is lying * about a precision nobody has. */ rates: [ { id: "FBX01", lane: "China / East Asia to North America West Coast", usdPerFeu: 7_491 }, { id: "FBX02", lane: "North America West Coast to China / East Asia", usdPerFeu: 347 }, ], }; /** * The Port of Long Beach — Pier T, on the east end of Terminal Island. * * The former Naval Station, and the half of the island that is in a different * city. It is here as much for what it proves as for what it shows: it shares * every mesh with Los Angeles, so the second port on this board costs no extra * draw call at all. See `createPorts`. * * No `breakwater` of its own — the arms on `LOS_ANGELES` are one federal * structure across the whole bay and drawing them twice would double the * geometry for an identical picture. No `throughput`, for the reason given at * the head of this block. */ export const LONG_BEACH: Port = { id: "USLGB", name: "Port of Long Beach", lat: 33.7529, lng: -118.2181, harborType: "CB", channel: [ [33.7235, -118.1885], // in through Queens Gate [33.736, -118.1955], [33.746, -118.203], [33.753, -118.206], [33.758, -118.214], [33.7637, -118.223], // under the Long Beach International Gateway [33.7709, -118.233], // and away west up the Back Channel ], quays: [ { id: "pier-t", deckHeight: 4, polygon: [ [33.759, -118.2205], [33.755, -118.2133], [33.7541, -118.214], [33.7581, -118.2212], ], }, { id: "pier-t-east", deckHeight: 4, polygon: [ [33.7541, -118.2126], [33.7476, -118.2109], [33.7473, -118.2122], [33.7539, -118.2139], ], }, ], berths: [ { id: "lgb-t132", lat: 33.7586, lng: -118.219, bearing: 123.6, maxLength: 400, quayId: "pier-t" }, { id: "lgb-t136", lat: 33.7573, lng: -118.2166, bearing: 123.6, maxLength: 400, quayId: "pier-t" }, { id: "lgb-t140", lat: 33.756, lng: -118.2142, bearing: 123.6, maxLength: 400, quayId: "pier-t" }, { id: "lgb-s101", lat: 33.7526, lng: -118.2117, bearing: 168, maxLength: 335, quayId: "pier-t-east" }, { id: "lgb-s105", lat: 33.7493, lng: -118.2109, bearing: 168, maxLength: 335, quayId: "pier-t-east" }, ], cranes: [ { id: "pier-t", from: [33.7588, -118.2206], to: [33.7548, -118.2134], count: 10, bearing: 33.6, height: 84, outreach: 74, idleFraction: 0.2, }, { id: "pier-t-east", from: [33.7541, -118.2128], to: [33.7475, -118.2111], count: 6, bearing: 78, height: 76, outreach: 64, // The quiet frontage. Five of six booms up is what an east-facing berth // with nothing alongside looks like, and it is the cheapest way this board // has of saying that a port is not uniformly busy. idleFraction: 0.83, }, ], yards: [ { id: "pier-t", lat: 33.753, lng: -118.2214, length: 1210, width: 710, bearing: 124, emptyShare: 0.765 }, { id: "pier-t-east", lat: 33.7484, lng: -118.2132, length: 480, width: 240, bearing: 168, emptyShare: 0.765 }, ], }; export const PORTS = [LOS_ANGELES, LONG_BEACH]; // ---- Airports ------------------------------------------------------------- /** * The Southland fields, and why these six. * * ## The headings, first, because they are the whole of the recognition * * A runway designator is **magnetic** and rounded to the nearest ten degrees. * Los Angeles's declination is about 11.8° east, so a runway painted "25" is * pointing somewhere near 262° true and one painted "16" near 172°. Building * from the painted numbers lays a whole airport twelve degrees out of true — * over LAX's longest runway that is seven hundred metres of drift — so every * `heading` below is a **true** bearing and every one of them is checked against * its designator in `socalAirports.test.ts`. * * Only LAX gets its bearing from a surveyed figure. The other five are * `designator × 10 + 11.8°`, which is accurate to about half of the five degrees * the rounding already allows and is invisible at 391 m to the scene unit. That * is stated rather than hidden: it is the difference between a number that was * looked up and a number that was derived, and the next person deserves to know * which is which. * * ## Six, and the ones that were left out * * The live ADS-B layer over this board carries a hundred and sixty-odd aircraft * in the middle of a weekday. Sampled at 02:40 Pacific — which is what the feed * would give me while this was written, and is therefore a thin sample rather * than a survey — twenty-two aircraft were airborne over the basin and six of * the eleven flying below eight thousand feet near any field were in LAX's * pattern, with Van Nuys and Burbank next. That ordering matches the annual * operations counts, which is what actually decided the list: LAX at ~700,000 * movements, Van Nuys at ~220,000 (the busiest general-aviation field in the * world), John Wayne and Long Beach around ~300,000 each with their flight * schools, Burbank ~130,000, Ontario ~70,000 but the region's freight door. * * Deliberately absent, and all of them real airports: **Santa Monica**, whose * single 3,500 ft strip disappears into the Westside grid at this scale; * **Chino**, nine kilometres from Ontario, which would read as a smudge beside * it; **Torrance**, **Hawthorne**, **Fullerton**, **El Monte** and **Whiteman**, * which are one short runway each; and **March Air Reserve Base**, whose * 13,300 ft runway is the second longest in Southern California but sits three * kilometres from the eastern edge of the board with thirty thousand movements a * year. An airport nobody flies into is scenery, and scenery costs triangles. * * ## Every one of them is a hole cut in a district * * `blocks.ts` has never heard of an airport. It scatters lots across a district * polygon and the only thing that keeps houses off a runway is the polygon * stopping short. Four of these — LAX, Van Nuys, John Wayne and the western half * of Burbank — sit on a district edge and are cut out with a notch. Long Beach * and Ontario sit in the middle of continuously built ground, so each is a hole * reached by a **narrow corridor** to the nearest district edge: Cherry Avenue * north out of Long Beach, Haven Avenue south out of Ontario. The corridor * costs one column of lots, which at 164 m to the lot reads as the six-lane * arterial that is genuinely there. `socalAirports.test.ts` sweeps the whole of * every field against every district and every park, because checking the * corners is what lets a runway keep a housing tract in the middle of it. */ /** * Los Angeles International: four parallels in two pairs, either side of the * horseshoe. * * From the altitude this board is looked at, LAX **is** that pattern — two long * bars, a gap with buildings in it, two more long bars — and it is as * recognisable as the Hollywood sign. Everything below is placed as a metre * offset from the airport reference point at 33.9425, −118.4081 and converted, * rather than typed as four independent thresholds, because four hand-typed * pairs of coordinates will not be consistent with each other and the * consistency is the shape. * * ### The bearing, and how the numbers check out * * All four runways are on **82.9° true**. That single number is why the whole * field is drawn from one frame, and it survives two independent checks. * Subtract the 11.8° east declination and it is 71.1° magnetic, which rounds to * **07** — and the south pair is 07L/25R and 07R/25L. The FAA does not allow * four parallels to share a number, so the north pair takes the next one down * and is 06L/24R and 06R/24L, which is why LAX has runways called both 24 and * 25 lying exactly parallel to each other. Any reading that makes the 24s a * different bearing from the 25s is wrong about LAX. * * ### The relative geometry * * Lateral offsets are from the reference point, positive to the south: * * - **06L/24R** at −853 m, 8,926 ft (2,721 m) long. **06R/24L** 213 m — 700 ft * — south of it, 10,285 ft (3,135 m). * - **07L/25R** at +610 m, 12,091 ft (3,685 m) and the longest on the field. * **07R/25L** 244 m — 800 ft — south of it, 11,095 ft (3,382 m). * * That leaves 1,250 m of airport between 24L and 25R, and the horseshoe is what * fills it: the Tom Bradley International Terminal closing the west end across * the axis, Terminals 1–3 as the north arm and 4–8 as the south arm, the parking * structures in the court. `gates` puts the stands on the **outside** of both * arms, which is where LAX's are — the court holds roadway and cars and nothing * that needs a wingspan. * * Terminal heights are the real ones. The board exaggerates its vertical 3.4× * and makes a 17 m concourse stand fifty-eight metres tall; trimming that would * put the airport on a different vertical scale from every house in Westchester * behind it, and the eye notices the mismatch long before it notices a tall * terminal. * * No `tower` is declared: this pack draws LAX's as a labelled `Landmark`, * because `label: true` is what puts the airport on the minimap and * `minimap.ts` reads `city.landmarks` rather than `city.airports`. */ export const LAX: Airport = { id: "KLAX", name: "Los Angeles International", lat: 33.9425, lng: -118.4081, // 125 ft. Carried because it is a fact about the place; the kit grades the // field onto the terrain rather than lifting it to this. See // `engine/airports.ts`. elevation: 38, /** * The property, and it is **square to Westchester rather than to the * runways**, which is the detail that makes LAX look like LAX from above: a * cardinal rectangle with a pattern seven degrees off it inside. Westchester * Parkway is the north fence, Imperial Highway the south, Aviation Boulevard * the east, and the dunes above Dockweiler the west. */ field: [ [33.9545, -118.433], [33.9545, -118.382], [33.931, -118.382], [33.931, -118.433], ], runways: [ // 06L [33.94845, -118.42526] -> 24R [33.95147, -118.39602] { id: "06L/24R", lat: 33.94996, lng: -118.41064, heading: 82.9, length: 2721, width: 46, designators: ["06L", "24R"] }, // 06R [33.94636, -118.42685] -> 24L [33.94984, -118.39317] { id: "06R/24L", lat: 33.9481, lng: -118.41001, heading: 82.9, length: 3135, width: 46, designators: ["06R", "24L"] }, // 07L [33.93515, -118.42571] -> 25R [33.93925, -118.38611] { id: "07L/25R", lat: 33.9372, lng: -118.40591, heading: 82.9, length: 3685, width: 61, designators: ["07L", "25R"] }, // 07R [33.93311, -118.42417] -> 25L [33.93687, -118.38783] { id: "07R/25L", lat: 33.93499, lng: -118.406, heading: 82.9, length: 3382, width: 61, designators: ["07R", "25L"] }, ], /** * The four outer parallels, B and C on the north complex and D and E on the * south. * * Typed as coordinates rather than computed here, because a city pack is data * and `airports.ts` imports three.js. `parallelTaxiway()` produced them and * `socalAirports.test.ts` asserts they are still what it produces, so the * derivation is checked without the pack having to run it. */ taxiways: [ { id: "B", path: [[33.94989, -118.42449], [33.95271, -118.39719]] }, { id: "C", path: [[33.94521, -118.4257], [33.94849, -118.39395]] }, { id: "D", path: [[33.9365, -118.42493], [33.94039, -118.38727]] }, { id: "E", path: [[33.93188, -118.423], [33.93543, -118.3886]] }, ], aprons: [ { id: "terminal", polygon: [[33.94524, -118.41833], [33.94709, -118.4005], [33.9396, -118.39937], [33.93776, -118.41721]] }, // The Imperial Cargo Complex, on the south side under the 25L approach. { id: "cargo", polygon: [[33.93628, -118.39298], [33.937, -118.386], [33.9337, -118.3855], [33.93298, -118.39248]] }, { id: "maintenance", polygon: [[33.94571, -118.43051], [33.94631, -118.42471], [33.94354, -118.4243], [33.94294, -118.4301]] }, ], terminals: [ { id: "tbit", lat: 33.94192, lng: -118.41369, length: 560, width: 130, height: 30, heading: 352.9, gates: { count: 8, side: -1 } }, { id: "north-arm", lat: 33.94517, lng: -118.4085, length: 850, width: 85, height: 17, heading: 82.9, gates: { count: 8, side: -1 } }, { id: "south-arm", lat: 33.93989, lng: -118.40705, length: 950, width: 85, height: 17, heading: 82.9, gates: { count: 9, side: 1 } }, // The central terminal area's parking structures, as three blocks rather // than one. A single 700 m mass filled the court, and a filled court is not // a horseshoe — the U only reads because there is a gap with something // smaller in it. { id: "parking-west", lat: 33.94221, lng: -118.41089, length: 230, width: 120, height: 20, heading: 82.9 }, { id: "parking-centre", lat: 33.94246, lng: -118.40853, length: 230, width: 120, height: 20, heading: 82.9 }, { id: "parking-east", lat: 33.9427, lng: -118.40617, length: 230, width: 120, height: 20, heading: 82.9 }, // The west maintenance base, square to the runways rather than to the // horseshoe, which is what stops it reading as more of the same building. { id: "maintenance", lat: 33.94456, lng: -118.42761, length: 280, width: 130, height: 26, heading: 82.9 }, { id: "cargo", lat: 33.93492, lng: -118.3895, length: 400, width: 110, height: 14, heading: 82.9, gates: { count: 4, side: -1 } }, ], }; /** * Hollywood Burbank, in the gap between the Verdugos and the Valley floor. * * Two runways crossing at seventy degrees, which is the shape here: 15/33 is the * long one running down out of the Verdugo gap, 08/26 is the short one along the * north fence, and they cross west of the terminal. Everything at Burbank is * small — 6,886 ft and 5,802 ft, a terminal that is genuinely two storeys — and * that is the point of drawing it beside LAX rather than instead of it. * * The bearings are the designators plus the 11.8° east declination: 161.8° and * 91.8° true. See the section comment. */ export const BUR: Airport = { id: "KBUR", name: "Hollywood Burbank", lat: 34.2007, lng: -118.3585, elevation: 237, /** * Held inside 34.190–34.2115 and −118.3735 to −118.349 on purpose: that is the * gap `van-nuys` and `burbank` were reshaped to leave, and a field that * crossed into either would have tract houses on the runway. */ /** * Both diagonals are the fence, not tidiness. The **north-east** cut is * Hollywood Way and the Golden State beyond it: I-5 passes about 700 m * north-east of the 26 threshold, and a square corner there put a freeway * ribbon across the runway. The **south-west** cut is the Burbank industrial * quarter, which is city and not airport, and every square metre of field that * is not holding a runway up is a square metre of plate standing proud of the * ground at the low end — see `Mount Thom` in `HILLS` for what that cost here. */ field: [ [34.2108, -118.3715], [34.2108, -118.361], [34.205, -118.3505], [34.1915, -118.3505], [34.1915, -118.36], [34.2, -118.3715], ], runways: [ // 15 [34.20993, -118.3638] -> 33 [34.19201, -118.35668] { id: "15/33", lat: 34.20097, lng: -118.36024, heading: 161.8, length: 2099, width: 46, designators: ["15", "33"] }, // 08 [34.20526, -118.37082] -> 26 [34.20476, -118.35162] { id: "08/26", lat: 34.20501, lng: -118.36122, heading: 91.8, length: 1769, width: 46, designators: ["08", "26"] }, ], taxiways: [ { id: "A", path: [[34.20955, -118.36205], [34.19317, -118.35554]] }, { id: "C", path: [[34.20407, -118.37], [34.20362, -118.35253]] }, ], aprons: [{ id: "terminal", polygon: [[34.20032, -118.35469], [34.19716, -118.35343], [34.19643, -118.35612], [34.19959, -118.35737]] }], // Terminals A and B as one frontage east of 15/33, where Hollywood Way runs, // with the stands facing back at the runway. terminals: [ { id: "ab", lat: 34.1985, lng: -118.35524, length: 340, width: 70, height: 12, heading: 161.8, gates: { count: 6, side: 1 } }, { id: "cargo", lat: 34.20366, lng: -118.35383, length: 260, width: 80, height: 13, heading: 91.8 }, ], }; /** * Van Nuys: two parallels down the middle of the Valley, and no airline at all. * * It is on this board because it is the busiest general-aviation airport in the * world and because the aircraft over the Valley are largely its — not because * anything about it is famous. So it is drawn as what it is: a long thin field * with an 8,000 ft runway, a 4,000 ft one beside it, and hangar rows down the * east side instead of a terminal. No `gates` anywhere on it, because the kit * parks airliners and nothing that lives here is one. * * The north fence is pulled in to 34.227 — Van Nuys really reaches Roscoe at * 34.232 — because `north-valley` starts at 34.2316 at this longitude and a * field that crossed it would have houses on runway 16R. */ export const VNY: Airport = { id: "KVNY", name: "Van Nuys", lat: 34.2098, lng: -118.4899, elevation: 244, // Trimmed in at the north and west from 34.227/-118.499 — Van Nuys really does // reach Roscoe — because the Valley floor rises about a metre in a hundred // across this field and the kit grades a plate to the highest ground it // covers. Every metre of field that is not holding a runway up is a metre of // lip standing proud at the low end. What is left spans 33 m. field: [ [34.2235, -118.4955], [34.2235, -118.481], [34.1975, -118.481], [34.1975, -118.4955], ], runways: [ // 16R [34.22064, -118.49298] -> 34L [34.19896, -118.4892] { id: "16R/34L", lat: 34.2098, lng: -118.49109, heading: 171.8, length: 2439, width: 46, designators: ["16R", "34L"] }, // 16L [34.2121, -118.48971] -> 34R [34.20122, -118.48781] { id: "16L/34R", lat: 34.20666, lng: -118.48876, heading: 171.8, length: 1223, width: 23, designators: ["16L", "34R"] }, ], taxiways: [{ id: "A", path: [[34.22011, -118.49135], [34.19985, -118.48782]] }], /** * The east ramp runs the whole length of the field, Saticoy to Sherman Way, * which is what Van Nuys's east side is. It is drawn that long for a second * reason as well: `airports.ts` grades the field to the highest of the * airport's own authored coordinates, and an apron corner is one of them. The * Valley floor's high point inside this fence is under the middle of this * ramp, so a short ramp graded the plate to ground lower than the ground it * covers. See the note on `FIELD_LIFT` in the section comment. */ aprons: [{ id: "east-ramp", polygon: [[34.21511, -118.48797], [34.19991, -118.48532], [34.2004, -118.48124], [34.2156, -118.48389]] }], terminals: [ { id: "east-hangars", lat: 34.20872, lng: -118.48523, length: 780, width: 90, height: 14, heading: 171.8 }, { id: "west-hangars", lat: 34.21411, lng: -118.49446, length: 420, width: 80, height: 13, heading: 171.8 }, ], }; /** * Long Beach, and the one field on this board that is a genuine X. * * 12/30 runs 10,003 ft south-east across the whole property and the 08s cross * it near their western ends, which is what gives Long Beach the crossed-strip * plan that reads from any altitude. The terminal is the small 1941 one on the * south-west side; the very large building on the north fence is the old * Douglas plant, which is a real 420 m shed and the largest single mass on the * field. * * Bearings are the designators plus declination: 131.8° and 91.8° true. */ export const LGB: Airport = { id: "KLGB", name: "Long Beach", lat: 33.8177, lng: -118.1516, elevation: 18, /** * The south-west corner is cut off, and that is not tidiness: **Signal Hill** * is 111 m of real oil-field hill 1.9 km south-west of the airport, and a * rectangle reaching -118.169 at 33.8055 put its flank inside the field. The * kit grades a field to the highest ground it covers, so that one corner * lifted the whole plate a hundred metres and stood Long Beach Airport on a * table. Cut back, the field spans 21 m of relief and lies flat. */ field: [ [33.8305, -118.1665], [33.8305, -118.1375], [33.8065, -118.1375], [33.8065, -118.148], [33.816, -118.1665], ], runways: [ // 12 [33.82683, -118.16389] -> 30 [33.80857, -118.13931] { id: "12/30", lat: 33.8177, lng: -118.1516, heading: 131.8, length: 3049, width: 61, designators: ["12", "30"] }, // 08L [33.823, -118.16018] -> 26R [33.82246, -118.13978] { id: "08L/26R", lat: 33.82273, lng: -118.14998, heading: 91.8, length: 1887, width: 46, designators: ["08L", "26R"] }, // 08R [33.82089, -118.15891] -> 26L [33.82043, -118.14105] { id: "08R/26L", lat: 33.82066, lng: -118.14998, heading: 91.8, length: 1653, width: 46, designators: ["08R", "26L"] }, ], taxiways: [ { id: "D", path: [[33.82529, -118.16409], [33.80823, -118.14113]] }, { id: "B", path: [[33.82414, -118.15927], [33.82365, -118.1406]] }, ], aprons: [{ id: "terminal", polygon: [[33.81745, -118.15694], [33.81356, -118.1517], [33.81041, -118.15509], [33.8143, -118.16033]] }], terminals: [ { id: "terminal", lat: 33.81303, lng: -118.15722, length: 260, width: 60, height: 12, heading: 131.8, gates: { count: 5, side: -1 } }, { id: "douglas", lat: 33.82803, lng: -118.14836, length: 420, width: 160, height: 20, heading: 91.8 }, ], }; /** * John Wayne, pointing north-east at the hills, which is the whole reason * anyone in Newport Beach has an opinion about it. * * 02L/20R is 5,701 ft with the short 02R/20L general-aviation strip beside it, * and the Riley terminal on the south-east side along MacArthur with the stands * facing back across at the runway. On 31.8° true — the designators plus * declination. */ export const SNA: Airport = { id: "KSNA", name: "John Wayne", lat: 33.6757, lng: -117.8682, elevation: 17, /** * Square to the runways rather than to the compass, which is the one field on * this board that is: John Wayne is a diagonal parcel wedged between MacArthur * Boulevard and the 405, and a cardinal rectangle around it left two-thirds of * the plate as empty green with the runways pushed into one corner. */ field: [ [33.66833, -117.87686], [33.68513, -117.86435], [33.68073, -117.85582], [33.66393, -117.86833], ], runways: [ // 02L [33.66907, -117.87379] -> 20R [33.68233, -117.86391] { id: "02L/20R", lat: 33.6757, lng: -117.86885, heading: 31.8, length: 1738, width: 46, designators: ["02L", "20R"] }, // 02R [33.67081, -117.8687] -> 20L [33.67753, -117.8637] { id: "02R/20L", lat: 33.67417, lng: -117.8662, heading: 31.8, length: 880, width: 23, designators: ["02R", "20L"] }, ], taxiways: [{ id: "A", path: [[33.66901, -117.87205], [33.68106, -117.86308]] }], aprons: [{ id: "terminal", polygon: [[33.6756, -117.86637], [33.67988, -117.86318], [33.67855, -117.86061], [33.67428, -117.8638]] }], terminals: [ { id: "riley", lat: 33.67866, lng: -117.86356, length: 420, width: 85, height: 16, heading: 31.8, gates: { count: 6, side: -1 } }, ], }; /** * Ontario, the freight door, out where the basin runs into the Inland Empire. * * Two long parallels 560 m apart with the passenger terminals and the cargo * ramp between them — which is the layout, and the reason Ontario looks like a * much bigger airport than its passenger numbers suggest. 12,198 ft and * 10,200 ft on 91.8° true. * * It is the only field on this board that had to be reached by a corridor cut * south to the district edge rather than notched from one; see the section * comment. */ export const ONT: Airport = { id: "KONT", name: "Ontario International", lat: 34.056, lng: -117.6012, elevation: 288, field: [ [34.063, -117.625], [34.063, -117.577], [34.049, -117.577], [34.049, -117.625], ], runways: [ // 08L [34.05904, -117.62135] -> 26R [34.058, -117.58105] { id: "08L/26R", lat: 34.05852, lng: -117.6012, heading: 91.8, length: 3718, width: 61, designators: ["08L", "26R"] }, // 08R [34.05392, -117.61642] -> 26L [34.05304, -117.58272] { id: "08R/26L", lat: 34.05348, lng: -117.59957, heading: 91.8, length: 3109, width: 46, designators: ["08R", "26L"] }, ], taxiways: [ { id: "A", path: [[34.05776, -117.62031], [34.05677, -117.58218]] }, { id: "B", path: [[34.05515, -117.61528], [34.05433, -117.58376]] }, ], aprons: [{ id: "terminal", polygon: [[34.05779, -117.60764], [34.05748, -117.59572], [34.05406, -117.59585], [34.05437, -117.60777]] }], terminals: [ { id: "t2-t4", lat: 34.056, lng: -117.60228, length: 700, width: 110, height: 16, heading: 91.8, gates: { count: 8, side: -1 } }, { id: "cargo", lat: 34.05474, lng: -117.5871, length: 500, width: 130, height: 16, heading: 91.8, gates: { count: 5, side: 1 } }, ], }; /** Every airport on this board, biggest first. */ export const AIRPORTS: Airport[] = [LAX, BUR, VNY, LGB, SNA, ONT]; // ---- Landmarks ------------------------------------------------------------ /** * The buildings placed by hand, because the eye goes looking for them. * * `footprint` is a half-width in degrees of longitude, which works out — at any * `latScale`, since the two cancel — as roughly `metres / 185000`. Like San * Francisco's, these are drawn about half again wider than life: a tower at its * true footprint and this vertical exaggeration is a nineteen-to-one needle, * and real towers do not look like that. * * A few of these are not buildings at all. LAX and Disneyland are flat pads * standing in for a footprint, because what the eye is actually looking for in * Westchester and Anaheim is a shape on the ground rather than anything with a * height. */ export const LANDMARKS: Landmark[] = [ // ---- The downtown cluster ---- { name: "U.S. Bank Tower", lat: 34.0509, lng: -118.2545, height: 310, footprint: 0.00045, shape: "tower", label: true, }, { name: "Wilshire Grand Center", lat: 34.0512, lng: -118.2605, height: 335, footprint: 0.0004, shape: "tower", label: true, }, { name: "Aon Center", lat: 34.0505, lng: -118.2585, height: 262, footprint: 0.00042, shape: "box", color: 0xb0a08c, }, { name: "Two California Plaza", lat: 34.0535, lng: -118.251, height: 229, footprint: 0.0004, shape: "box", }, // The 1928 ziggurat that was the only building in the city allowed to break // the height limit for forty years, and still the shape people draw when they // draw Los Angeles. { name: "Los Angeles City Hall", lat: 34.0537, lng: -118.2427, height: 138, footprint: 0.00048, shape: "tower", color: 0xe0d8c4, label: true, }, { name: "Walt Disney Concert Hall", lat: 34.0553, lng: -118.2498, height: 40, footprint: 0.00055, shape: "cylinder", color: 0xc9cdd2, label: true, }, { name: "Union Station", lat: 34.0561, lng: -118.2365, height: 40, footprint: 0.0006, shape: "box", color: 0xd9c8ab, label: true, }, { name: "Crypto.com Arena", lat: 34.043, lng: -118.2673, height: 45, footprint: 0.0006, shape: "cylinder", color: 0x9aa4ad, }, { name: "Dodger Stadium", lat: 34.0739, lng: -118.24, height: 35, footprint: 0.0009, shape: "cylinder", color: 0x5c7fa0, label: true, }, { name: "Los Angeles Memorial Coliseum", lat: 34.0141, lng: -118.2879, height: 38, footprint: 0.00095, shape: "cylinder", color: 0xc0a882, label: true, }, // ---- Hollywood and the hills ---- // Fourteen-metre letters on a five-hundred-metre hillside. The hill does the // work; the landmark just puts something white on the ridge where the eye is // already looking. { name: "Hollywood Sign", lat: 34.1341, lng: -118.3215, height: 15, footprint: 0.0005, shape: "box", color: 0xf2f0ea, label: true, }, { name: "Griffith Observatory", lat: 34.1184, lng: -118.3004, height: 22, footprint: 0.0004, shape: "cylinder", color: 0xdcd8cc, label: true, }, { name: "Capitol Records Building", lat: 34.1024, lng: -118.3264, height: 46, footprint: 0.00022, shape: "cylinder", color: 0xd8cfc0, label: true, }, // ---- The Westside ---- { name: "Getty Center", lat: 34.078, lng: -118.4741, height: 32, footprint: 0.0008, shape: "box", color: 0xe8e2d2, label: true, }, { name: "Century Plaza Towers", lat: 34.0585, lng: -118.4146, height: 173, footprint: 0.00038, shape: "box", color: 0xb8bfc6, label: true, }, { name: "Century Plaza Towers (south)", lat: 34.0568, lng: -118.4118, height: 173, footprint: 0.00038, shape: "box", color: 0xb8bfc6, }, { name: "Fox Plaza", lat: 34.0556, lng: -118.4131, height: 150, footprint: 0.0003, shape: "tower", }, { name: "Santa Monica Pier", lat: 34.0086, lng: -118.4977, height: 30, footprint: 0.0004, shape: "cylinder", color: 0xd6c9a8, label: true, }, { name: "SoFi Stadium", lat: 33.9535, lng: -118.3392, height: 48, footprint: 0.0013, shape: "cylinder", color: 0x9fa8b0, label: true, }, // ---- LAX ---- // This used to be a flat two-kilometre pad of a landmark standing in for an // airport, beside two runway-shaped roads. `LAX` in `AIRPORTS` draws the real // thing now and the pad would sit on top of its own field, so what is left // here is the one piece of LAX the kit does not draw: the tower, at its real // 277 ft. // // It is a landmark rather than the airport's own `tower` because `label: true` // is what puts LAX on the minimap — `minimap.ts` reads `city.landmarks` and // has never heard of `city.airports`. Declaring both would stand two towers // four hundred metres apart, which is how the Bay Area pack found this out. { name: "LAX Control Tower", lat: 33.9421, lng: -118.4022, height: 84, footprint: 0.00028, shape: "cylinder", color: 0xc9ccce, label: true, }, { name: "LAX Theme Building", lat: 33.9448, lng: -118.402, height: 41, footprint: 0.00035, shape: "cylinder", color: 0xe4e1d8, }, // ---- The Valley ---- { name: "Warner Center", lat: 34.172, lng: -118.601, height: 95, footprint: 0.00045, shape: "box", label: true, }, // ---- Pasadena ---- { name: "Pasadena City Hall", lat: 34.1478, lng: -118.1445, height: 63, footprint: 0.00045, shape: "tower", color: 0xd9c9a8, label: true, }, { name: "Rose Bowl", lat: 34.1613, lng: -118.1676, height: 26, footprint: 0.0011, shape: "cylinder", color: 0xc4bda8, label: true, }, // ---- The harbour ---- // Three gantry cranes on Terminal Island. They are the tallest things for // fifteen kilometres and they are what makes the port look like a port rather // than an empty basin. { name: "Long Beach Cranes", lat: 33.7535, lng: -118.2385, height: 78, footprint: 0.00022, shape: "box", color: 0x8c9298, label: true, }, { name: "Long Beach Cranes (2)", lat: 33.7515, lng: -118.2345, height: 78, footprint: 0.00022, shape: "box", color: 0x8c9298, }, { name: "Long Beach Cranes (3)", lat: 33.7495, lng: -118.2305, height: 78, footprint: 0.00022, shape: "box", color: 0x8c9298, }, { name: "Queen Mary", lat: 33.7525, lng: -118.19, height: 55, footprint: 0.00055, shape: "box", color: 0x33506a, label: true, }, { name: "Watts Towers", lat: 33.939, lng: -118.2415, height: 30, footprint: 0.00012, shape: "tower", color: 0xb08a5a, label: true, }, // ---- Orange County ---- // Disneyland as a footprint, which is what the brief of this map is: a // kilometre of green in the middle of Anaheim's flat grid, with one white // peak in it. The Matterhorn is forty-four metres of chicken wire and plaster // and it is still the only mountain in the OC basin. { name: "Disneyland", lat: 33.8121, lng: -117.919, height: 10, footprint: 0.0052, shape: "box", color: 0x5f7a52, label: true, }, { name: "Matterhorn", lat: 33.8129, lng: -117.9178, height: 46, footprint: 0.00024, shape: "pyramid", color: 0xeceff2, label: true, }, { name: "Angel Stadium", lat: 33.8003, lng: -117.8827, height: 38, footprint: 0.0009, shape: "cylinder", color: 0xa8b0b8, label: true, }, { name: "Honda Center", lat: 33.8078, lng: -117.8766, height: 35, footprint: 0.0006, shape: "cylinder", color: 0x9aa4ad, }, { name: "Fashion Island", lat: 33.618, lng: -117.876, height: 90, footprint: 0.0004, shape: "box", }, { name: "Park Place, Irvine", lat: 33.68, lng: -117.857, height: 100, footprint: 0.0004, shape: "box", }, // ---- Riverside ---- { name: "Mission Inn", lat: 33.982, lng: -117.3745, height: 42, footprint: 0.0005, shape: "tower", color: 0xd8c4a0, label: true, }, { name: "Riverside County Administrative Center", lat: 33.98, lng: -117.376, height: 60, footprint: 0.0003, shape: "box", }, ]; // ---- Districts ------------------------------------------------------------ /** * Where buildings go, how tall, and on what bearing. * * **The bearings are the point of this section.** Southern California is one * continuous field of low buildings for a hundred kilometres, and if it were * laid out on one grid it would render as a single grey sheet. It is not: it is * a dozen surveys that never agreed with each other, and the seams between them * are the most legible thing on the ground plan. `gridAngle` is in radians, and * the convention works out as *the compass bearing of the north-south street * axis*, so 0 is a true cardinal grid and 0.63 is thirty-six degrees clockwise * of one. Only the value modulo a right angle matters, since a square lattice * is symmetric under a quarter turn. * * The six that carry the map: * * - **Downtown at 0.63**, thirty-six degrees off north. Laid out under the * Laws of the Indies so that every building would get sun on more than one * face, and never corrected since. This is the local equivalent of Market * Street: the rotated core is why the freeway interchanges around downtown * are the shape they are, and it is the first thing that tells you this is * not Phoenix. * - **The San Fernando Valley at 0.0**, dead cardinal, over four hundred * square kilometres. The single largest uninterrupted grid on the map, and * the reason the Valley reads as a different city from the one south of the * hills. * - **Pasadena at 0.02**, also effectively cardinal — which is why Colorado * Boulevard runs arrow-straight due east and downtown's streets do not. * - **The Westside around 0.5**, twenty-nine degrees, inherited from the * Spanish ranchos it was subdivided out of. * - **Santa Monica and Venice at 0.88**, aligned to the beach rather than to * the compass, which is why the Westside grid hits the coastal grid at a * visible angle somewhere around Centinela. * - **Irvine at 0.60** against Anaheim's cardinal 0.02. Two master plans * twenty kilometres apart, drawn a century apart, and the seam runs right * through Santa Ana. * * Two things about the numbers are not obvious and were both got wrong on the * first pass. * * **Coverage stays high.** The instinct is to thin the suburbs out, since a * tract lot is mostly driveway, pool and strip-mall car park. That is an * argument about a forty-metre lot. At a hundred and sixty-four there is * something standing on essentially every lot in the basin, and dropping * coverage to a half produced a metro that read as scattered debris. It is held * near San Francisco's 0.88 through the continuously built districts and pulled * down only where the ground genuinely is empty: Malibu at 0.14, the Palos * Verdes and Palisades hillsides at 0.4. * * **Minimum heights are higher than they look like they should be**, for the * same reason. One instance here is a city block, not a building, and a block * reads as its tallest thing. * * The whole set comes to about fifty-five thousand instances, against the * Bay Area's eighty-three. Fewer buildings over twenty times the district area is * the arithmetic working correctly, not a gap to be filled: a scene unit is * four times longer, so a lot covers sixteen times the ground. */ export const DISTRICTS: District[] = [ // ---- Downtown and the core ---- { id: "dtla", name: "Downtown Los Angeles", polygon: [ [34.068, -118.272], [34.06, -118.228], [34.03, -118.233], [34.037, -118.278], ], minHeight: 30, maxHeight: 240, gridAngle: 0.63, palette: "downtown", towerChance: 0.11, coverage: 0.88, }, { id: "arts-district", name: "Arts District & Vernon", polygon: [ [34.048, -118.228], [34.043, -118.19], [34.0, -118.198], [34.008, -118.238], ], minHeight: 12, maxHeight: 48, gridAngle: 0.63, palette: "industrial", towerChance: 0.006, coverage: 0.84, }, { id: "usc-exposition", name: "South Park & Exposition", polygon: [ [34.038, -118.3], [34.033, -118.25], [33.998, -118.256], [34.005, -118.306], ], minHeight: 14, maxHeight: 90, gridAngle: 0.02, palette: "residential", towerChance: 0.02, coverage: 0.86, }, { id: "koreatown", name: "Koreatown & Mid-Wilshire", polygon: [ [34.08, -118.345], [34.076, -118.272], [34.044, -118.28], [34.049, -118.352], ], minHeight: 16, maxHeight: 82, gridAngle: 0.02, palette: "residential", towerChance: 0.03, coverage: 0.88, }, { id: "hollywood", name: "Hollywood", polygon: [ [34.115, -118.375], [34.11, -118.298], [34.082, -118.305], [34.088, -118.38], ], minHeight: 14, maxHeight: 68, gridAngle: 0.03, palette: "residential", towerChance: 0.025, coverage: 0.86, }, { id: "silver-lake", name: "Silver Lake & Echo Park", polygon: [ [34.115, -118.3], [34.108, -118.236], [34.066, -118.243], [34.074, -118.307], ], minHeight: 12, maxHeight: 34, gridAngle: 0.12, palette: "residential", towerChance: 0.004, coverage: 0.8, }, // Northeast LA is on its own bearing because it was subdivided along the // Arroyo Seco and the Santa Fe line rather than off any city survey — which // is why Figueroa runs diagonally out of downtown and nothing up here lines // up with either Hollywood or Pasadena. { id: "highland-park", name: "Highland Park & Eagle Rock", polygon: [ [34.145, -118.25], [34.14, -118.155], [34.085, -118.163], [34.092, -118.258], ], minHeight: 11, maxHeight: 32, gridAngle: 0.35, palette: "residential", towerChance: 0.003, coverage: 0.8, }, { id: "west-hollywood", name: "West Hollywood & Beverly Hills", polygon: [ [34.098, -118.42], [34.094, -118.345], [34.058, -118.352], [34.063, -118.427], ], minHeight: 13, maxHeight: 62, gridAngle: 0.32, palette: "residential", towerChance: 0.015, coverage: 0.84, }, // ---- The Westside ---- { id: "century-city", name: "Century City", polygon: [ [34.07, -118.43], [34.067, -118.398], [34.048, -118.402], [34.052, -118.434], ], minHeight: 35, maxHeight: 170, gridAngle: 0.5, palette: "downtown", towerChance: 0.2, coverage: 0.88, }, { id: "westwood", name: "Westwood & Brentwood", polygon: [ [34.078, -118.5], [34.073, -118.42], [34.044, -118.428], [34.051, -118.508], ], minHeight: 13, maxHeight: 78, gridAngle: 0.5, palette: "residential", towerChance: 0.02, coverage: 0.76, }, { id: "santa-monica", name: "Santa Monica", polygon: [ [34.042, -118.52], [34.034, -118.462], [33.998, -118.472], [34.007, -118.526], ], minHeight: 15, maxHeight: 62, gridAngle: 0.88, palette: "downtown", towerChance: 0.025, coverage: 0.86, }, { id: "venice", name: "Venice & the Marina", polygon: [ [34.002, -118.484], [33.996, -118.432], [33.958, -118.44], [33.966, -118.492], ], minHeight: 12, maxHeight: 36, gridAngle: 0.88, palette: "residential", towerChance: 0.006, coverage: 0.84, }, { id: "culver-city", name: "Culver City & Palms", polygon: [ [34.038, -118.436], [34.033, -118.36], [33.996, -118.368], [34.002, -118.443], ], minHeight: 13, maxHeight: 60, gridAngle: 0.5, palette: "downtown", towerChance: 0.018, coverage: 0.84, }, // Everything from here west is hillside: a road, a canyon and whatever will // stand on the slope. Sparse on purpose. { id: "palisades", name: "Pacific Palisades", polygon: [ [34.068, -118.562], [34.063, -118.502], [34.036, -118.51], [34.041, -118.568], ], minHeight: 10, maxHeight: 26, gridAngle: 0.62, palette: "residential", towerChance: 0.001, coverage: 0.4, }, { id: "malibu", name: "Malibu", polygon: [ [34.042, -118.94], [34.038, -118.6], [34.02, -118.606], [34.024, -118.946], ], minHeight: 9, maxHeight: 18, gridAngle: 0.12, palette: "residential", towerChance: 0.001, coverage: 0.14, }, // ---- The San Fernando Valley ---- { id: "sherman-oaks", name: "Sherman Oaks & Encino", polygon: [ [34.182, -118.55], [34.178, -118.4], [34.138, -118.406], [34.142, -118.556], ], minHeight: 12, maxHeight: 44, gridAngle: 0.0, palette: "residential", towerChance: 0.008, coverage: 0.82, }, { id: "van-nuys", // Two airports come out of this one polygon. Vertices 3-6 are the notch for // Burbank, cut in from the east boundary; vertices 9-12 are the notch for // Van Nuys, cut in from the west, where the ground it also gives up is the // Sepulveda Basin and already open. `burbank` picks up the eastern strip // that the first notch removes, so nothing is left unbuilt but the fields. name: "Van Nuys & North Hollywood", polygon: [ [34.24, -118.5], [34.235, -118.34], [34.2125, -118.3423], [34.2125, -118.3745], [34.189, -118.3745], [34.189, -118.3447], [34.176, -118.346], [34.181, -118.506], [34.194, -118.5047], [34.194, -118.48], [34.229, -118.48], [34.229, -118.5011], ], minHeight: 12, maxHeight: 48, gridAngle: 0.0, palette: "residential", towerChance: 0.007, coverage: 0.84, }, { id: "warner-center", name: "Warner Center & Woodland Hills", polygon: [ [34.205, -118.65], [34.2, -118.545], [34.152, -118.552], [34.157, -118.657], ], minHeight: 13, maxHeight: 98, gridAngle: 0.0, palette: "downtown", towerChance: 0.035, coverage: 0.8, }, { id: "north-valley", name: "Northridge & Sylmar", polygon: [ [34.3, -118.58], [34.294, -118.38], [34.228, -118.388], [34.235, -118.588], ], minHeight: 11, maxHeight: 30, gridAngle: 0.0, palette: "residential", towerChance: 0.002, coverage: 0.8, }, { id: "burbank", // The north-west corner is cut back from -118.368 to -118.348, which is // Hollywood Way and the east fence of the airport. What that leaves out is // the eastern half of Burbank's field; `van-nuys` gives up the western // half, and between them the two polygons leave one clean hole. name: "Burbank", polygon: [ [34.2125, -118.348], [34.206, -118.282], [34.15, -118.29], [34.157, -118.375], [34.189, -118.3709], [34.189, -118.348], ], minHeight: 13, maxHeight: 62, gridAngle: 0.61, palette: "residential", towerChance: 0.02, coverage: 0.82, }, { id: "glendale", name: "Glendale", polygon: [ [34.18, -118.29], [34.175, -118.212], [34.118, -118.22], [34.124, -118.298], ], minHeight: 14, maxHeight: 92, gridAngle: 0.28, palette: "downtown", towerChance: 0.035, coverage: 0.82, }, // ---- Pasadena and the San Gabriel Valley ---- { id: "pasadena", name: "Pasadena", polygon: [ [34.185, -118.19], [34.18, -118.07], [34.12, -118.078], [34.126, -118.198], ], minHeight: 14, maxHeight: 78, gridAngle: 0.02, palette: "downtown", towerChance: 0.03, coverage: 0.8, }, { id: "sgv-west", name: "Alhambra & El Monte", polygon: [ [34.118, -118.17], [34.113, -117.99], [34.03, -118.0], [34.036, -118.18], ], minHeight: 11, maxHeight: 36, gridAngle: 0.1, palette: "residential", towerChance: 0.004, coverage: 0.8, }, { id: "sgv-east", name: "West Covina & Pomona", polygon: [ [34.125, -117.985], [34.12, -117.72], [34.015, -117.732], [34.021, -117.995], ], minHeight: 11, maxHeight: 32, gridAngle: 0.05, palette: "residential", towerChance: 0.003, coverage: 0.78, }, { id: "ontario", // Ontario International, cut out the same way Long Beach is: a hole with a // corridor, here running south to the boundary along Haven Avenue. Nothing // on the eastern half of this board is close enough to a district edge to // notch, and a warehouse district with a runway drawn through it is worse // than one arterial's worth of missing lots. name: "Ontario & Rancho Cucamonga", polygon: [ [34.125, -117.69], [34.12, -117.48], [34.015, -117.492], [34.0181, -117.601], [34.0475, -117.601], [34.0475, -117.5755], [34.0645, -117.5755], [34.0645, -117.6265], [34.0475, -117.6265], [34.0475, -117.606], [34.0182, -117.606], [34.021, -117.702], ], minHeight: 11, maxHeight: 30, gridAngle: 0.01, palette: "industrial", towerChance: 0.002, coverage: 0.66, }, { id: "chino", name: "Chino & Diamond Bar", polygon: [ [34.02, -117.79], [34.015, -117.61], [33.94, -117.622], [33.946, -117.802], ], minHeight: 10, maxHeight: 26, gridAngle: 0.02, palette: "industrial", towerChance: 0.002, coverage: 0.6, }, // ---- South Los Angeles, the South Bay and the harbour ---- { id: "south-la", name: "South Los Angeles", polygon: [ [34.0, -118.35], [33.996, -118.2], [33.925, -118.212], [33.93, -118.36], ], minHeight: 10, maxHeight: 28, gridAngle: 0.01, palette: "residential", towerChance: 0.002, coverage: 0.88, }, { id: "inglewood", // The last four vertices are the LAX notch: the polygon runs up the west // boundary, turns in along the airport's south fence, round the east and // north fences, and back out to the boundary. `blocks.ts` has never heard // of an airport, so this notch is the only thing keeping tract houses off // the 25R touchdown zone. The strip it also gives up — between the fence at // -118.433 and the boundary — is the Dockweiler dunes, which are genuinely // unbuilt, and that is why the notch opens west rather than east. name: "Inglewood & Hawthorne", polygon: [ [33.985, -118.43], [33.98, -118.32], [33.915, -118.33], [33.92, -118.438], [33.929, -118.4369], [33.929, -118.38], [33.9565, -118.38], [33.9565, -118.4335], ], minHeight: 11, maxHeight: 50, gridAngle: 0.02, palette: "residential", towerChance: 0.008, coverage: 0.84, }, { id: "south-bay", name: "Torrance & the Beach Cities", polygon: [ [33.918, -118.415], [33.912, -118.3], [33.815, -118.312], [33.822, -118.422], ], minHeight: 11, maxHeight: 40, gridAngle: 0.72, palette: "residential", towerChance: 0.006, coverage: 0.8, }, { id: "palos-verdes", name: "Palos Verdes", polygon: [ [33.802, -118.412], [33.797, -118.305], [33.728, -118.315], [33.734, -118.418], ], minHeight: 10, maxHeight: 22, gridAngle: 0.3, palette: "residential", towerChance: 0.001, coverage: 0.4, }, { id: "san-pedro", // The eastern edge is the Main Channel, and it is drawn that way on purpose. // This polygon used to be a plain quad reaching to -118.235, which put the // whole of Terminal Island inside it — so the busiest container terminal in // the hemisphere came out as three dozen generic industrial blocks, // indistinguishable from the housing across the water. `engine/ports.ts` // draws what is actually there. Vertices 3 and 4 run the boundary down the // middle of the channel: San Pedro's own waterfront at about -118.2755 stays // inside it, Terminal Island's west shore at -118.2708 stays outside. name: "San Pedro & Wilmington", polygon: [ [33.795, -118.305], [33.79, -118.235], [33.7745, -118.238], [33.7745, -118.272], [33.708, -118.276], [33.713, -118.31], ], minHeight: 11, maxHeight: 44, gridAngle: 0.05, palette: "industrial", towerChance: 0.005, coverage: 0.76, }, { id: "carson", name: "Compton & Carson", polygon: [ [33.94, -118.29], [33.935, -118.145], [33.85, -118.156], [33.856, -118.3], ], minHeight: 10, maxHeight: 28, gridAngle: 0.02, palette: "industrial", towerChance: 0.002, coverage: 0.8, }, { id: "long-beach", // Long Beach Airport sits three and a half kilometres inside this polygon in // every direction, so it cannot be notched from an edge — it is a hole // reached by a corridor running north to the boundary along Cherry Avenue. // The corridor is 460 m wide and takes about one column of lots with it, // which at 164 m to the lot is what a six-lane arterial looks like here in // any case. Vertices 2-9 walk down the corridor, round the field, and back // up it. name: "Long Beach", // The last vertex moved north from 33.758 to 33.7695 for the reason the San // Pedro polygon's east edge moved: at -118.238 the old south edge sat at // 33.7579, which is below Terminal Island's East Basin and put lots on the // Everport quay. Everything between the old line and the new one is water — // the Long Beach shoreline there is at 33.766 — so nothing real was lost. polygon: [ [33.868, -118.23], [33.8653, -118.166], [33.832, -118.166], [33.832, -118.169], [33.8055, -118.169], [33.8055, -118.136], [33.832, -118.136], [33.832, -118.161], [33.865, -118.161], [33.862, -118.09], [33.752, -118.102], [33.7695, -118.24], ], minHeight: 12, maxHeight: 124, gridAngle: 0.2, palette: "downtown", towerChance: 0.014, coverage: 0.8, }, { id: "downey", name: "Downey & Lakewood", polygon: [ [33.96, -118.19], [33.955, -118.045], [33.845, -118.058], [33.852, -118.2], ], minHeight: 10, maxHeight: 28, gridAngle: 0.04, palette: "residential", towerChance: 0.002, coverage: 0.8, }, { id: "whittier", name: "Whittier & La Mirada", polygon: [ [33.948, -118.055], [33.943, -117.93], [33.895, -117.94], [33.9, -118.065], ], minHeight: 10, maxHeight: 28, gridAngle: 0.06, palette: "residential", towerChance: 0.002, coverage: 0.82, }, // ---- Orange County ---- { id: "anaheim", name: "Anaheim & Fullerton", polygon: [ [33.885, -118.06], [33.879, -117.86], [33.8, -117.872], [33.806, -118.072], ], minHeight: 11, maxHeight: 64, gridAngle: 0.02, palette: "residential", towerChance: 0.012, coverage: 0.82, }, { id: "yorba-linda", name: "Brea & Yorba Linda", polygon: [ [33.935, -117.87], [33.93, -117.72], [33.86, -117.73], [33.866, -117.88], ], minHeight: 10, maxHeight: 28, gridAngle: 0.08, palette: "residential", towerChance: 0.002, coverage: 0.68, }, { id: "santa-ana", name: "Santa Ana", polygon: [ [33.795, -117.925], [33.79, -117.82], [33.705, -117.832], [33.711, -117.937], ], minHeight: 11, maxHeight: 60, gridAngle: 0.05, palette: "downtown", towerChance: 0.018, coverage: 0.86, }, { id: "garden-grove", name: "Garden Grove & Westminster", polygon: [ [33.8, -118.055], [33.795, -117.92], [33.72, -117.93], [33.726, -118.065], ], minHeight: 10, maxHeight: 26, gridAngle: 0.02, palette: "residential", towerChance: 0.002, coverage: 0.8, }, { id: "huntington-beach", name: "Huntington Beach & Fountain Valley", polygon: [ [33.735, -118.075], [33.73, -117.95], [33.64, -117.962], [33.646, -118.087], ], minHeight: 10, maxHeight: 30, gridAngle: 0.05, palette: "residential", towerChance: 0.003, coverage: 0.82, }, { id: "newport-beach", name: "Newport Beach & Costa Mesa", polygon: [ [33.665, -117.94], [33.66, -117.82], [33.58, -117.832], [33.586, -117.952], ], minHeight: 11, maxHeight: 68, gridAngle: 0.35, palette: "residential", towerChance: 0.015, coverage: 0.72, }, { id: "irvine", // John Wayne straddles this polygon's west boundary, so the last four // vertices notch it out from that edge. `newport-beach` stops at about // 33.662 under the field and `santa-ana` starts at 33.705 above it, so this // is the only district the airport touches. name: "Irvine", polygon: [ [33.735, -117.865], [33.73, -117.71], [33.63, -117.722], [33.636, -117.877], [33.662, -117.8739], [33.662, -117.854], [33.6935, -117.854], [33.6935, -117.87], ], minHeight: 12, maxHeight: 84, gridAngle: 0.6, palette: "downtown", towerChance: 0.03, coverage: 0.76, }, { id: "saddleback", name: "Mission Viejo & Laguna", polygon: [ [33.64, -117.75], [33.634, -117.59], [33.505, -117.612], [33.515, -117.762], ], minHeight: 10, maxHeight: 26, gridAngle: 0.42, palette: "residential", towerChance: 0.002, coverage: 0.6, }, { id: "dana-point", name: "Dana Point & San Clemente", polygon: [ [33.5, -117.72], [33.482, -117.62], [33.415, -117.575], [33.435, -117.695], ], minHeight: 10, maxHeight: 24, gridAngle: 0.55, palette: "residential", towerChance: 0.002, coverage: 0.5, }, // ---- Riverside and the Inland Empire ---- { id: "riverside", name: "Downtown Riverside", polygon: [ [34.008, -117.42], [34.002, -117.325], [33.94, -117.333], [33.947, -117.428], ], minHeight: 12, maxHeight: 70, gridAngle: 0.79, palette: "downtown", towerChance: 0.03, coverage: 0.74, }, { id: "moreno-valley", name: "Moreno Valley & Arlington", polygon: [ [33.985, -117.33], [33.978, -117.225], [33.87, -117.238], [33.877, -117.343], ], minHeight: 10, maxHeight: 24, gridAngle: 0.05, palette: "residential", towerChance: 0.002, coverage: 0.62, }, { id: "corona", name: "Corona & Norco", polygon: [ [33.93, -117.64], [33.924, -117.5], [33.84, -117.512], [33.847, -117.652], ], minHeight: 10, maxHeight: 26, gridAngle: 0.03, palette: "residential", towerChance: 0.002, coverage: 0.62, }, ]; // ---- Focus regions -------------------------------------------------------- /** * The two rectangles that get fine terrain, at about 80 m; everywhere else is * ten times coarser, at about 800 m. * * This is the trade ARCHITECTURE.md §5 asked for, and the arithmetic is worth * writing down because it is the whole argument for the feature existing. * Uniform 80 m cells over this frame would be 1.08° / 0.00072 by 1.66° / * 0.00086 — just under 2.9 million lattice points, several seconds of build, * and a mesh with nothing in most of it. What ships is 0.13 million, and the * whole city builds in about 2.3 seconds. * * It was seven boxes when this pack was written, and that did not survive * contact with the engine. `buildAxis` in world.ts refines **per axis**, not * per rectangle: a focus region sharpens its whole row *and* its whole column, * so seven boxes scattered across a basin this wide refine most of the basin * between them. Measured, on this data: seven regions came to 0.73 million * points and a 6.6 second field build; two come to 0.13 million and 1.3. The * boxes that stayed are the two the camera spends its time in. * * Where a box is *not* is as considered as where it is. The San Fernando * Valley and the harbour both get chapters and neither gets a box, because * both are flat: fine cells there would buy several thousand extra triangles * of absolutely level ground. The relief that matters at those two stops is * the range behind the Valley and the coastline around the port, and neither * is inside the frame the camera is pointed at. */ export const FOCUS_REGIONS: FocusRegion[] = [ { minLat: 34.01, maxLat: 34.09, minLng: -118.3, maxLng: -118.19 }, { minLat: 34.075, maxLat: 34.15, minLng: -118.37, maxLng: -118.25 }, ]; // ---- Chapters ------------------------------------------------------------- /** * The tour. Eight stops rather than the seven the basin strictly needs, because * the port is one of the four or five things on this coast that is unmistakably * itself and a chapter is the only way a viewer gets to look at it. * * Camera notes, since the numbers are less obvious here than in a city that * fits in one frame. `rotation` places the camera and the target is looked at * from there, so a negative rotation puts the eye to the south-west — out over * the water — looking back north-east into the basin. That is the standard * Southern California view and six of these eight use it. The whole-board * stop deliberately sits closer than the frame's true half-width, because the * engine's fog closes at 460 units and at 391 m to the unit that is a hundred * and eighty kilometres: pull the camera back far enough to see every corner * and the San Gabriels dissolve into haze. Which is, to be fair, what they * usually do. */ const WHOLE_BOARD: City["chapters"][number] = { id: "all", number: "01", label: "The Whole Board", shortLabel: "Whole Board", focus: { lat: 34.02, lng: -118.12, distance: 236, height: 148, rotation: -0.55, }, description: "A hundred kilometres of basin between the Pacific and a three-thousand-metre wall, with Catalina offshore and the Santa Anas closing the south-east. Everything on this map is inside one mountain rim.", }; export const CHAPTERS: City["chapters"] = [ WHOLE_BOARD, { id: "dtla", number: "02", label: "Downtown Los Angeles", shortLabel: "DTLA", focus: { lat: 34.05, lng: -118.248, distance: 19, height: 13.5, rotation: 0.63, }, description: "The one cluster of real towers in the basin, on a grid turned thirty-six degrees off north since 1781. The camera is lined up with that grid, which is why everything else in the frame looks crooked.", }, { id: "westside", number: "03", label: "The Westside", shortLabel: "Westside", focus: { lat: 34.025, lng: -118.435, distance: 46, height: 30, rotation: -0.6, }, description: "Santa Monica, Venice, Culver City and Century City, seen from over the bay. Three different street grids meet in this frame and none of them agree; the seams are visible from here.", }, { id: "hollywood", number: "04", label: "Hollywood & Silver Lake", shortLabel: "Hollywood", focus: { lat: 34.108, lng: -118.305, distance: 34, height: 24, rotation: 0.1, }, description: "The flats run north on a cardinal grid until they hit the Santa Monica Mountains and stop. The sign is on Mount Lee at the top of the frame; the reservoir below it is Silver Lake.", }, { id: "valley", number: "05", label: "The San Fernando Valley", shortLabel: "The Valley", focus: { lat: 34.19, lng: -118.43, distance: 66, height: 40, rotation: -0.15, }, description: "Four hundred square kilometres of the most uninterrupted cardinal grid in the country, in a bowl with the Santa Monicas behind the camera and the San Gabriels across the top.", }, { id: "harbour", number: "06", label: "The Harbour & Palos Verdes", shortLabel: "Harbour", focus: { lat: 33.76, lng: -118.24, distance: 40, height: 26, rotation: -0.9, }, description: "Three of every four boxes that left Los Angeles in July 2026 left empty \u2014 348,691 of 460,467 \u2014 because a container is worth $7,491 coming east across the Pacific and $347 going back. The pale stacks in these yards are that number. San Pedro, Terminal Island and Long Beach around one basin, behind thirteen kilometres of federal breakwater.", }, { id: "orange-county", number: "07", label: "Orange County", shortLabel: "Orange County", focus: { lat: 33.73, lng: -117.87, distance: 84, height: 52, rotation: -0.5, }, description: "Anaheim's mile grid against Irvine's rotated master plan, with the Santa Ana River running diagonally through both of them and the Santa Anas standing up behind.", }, { id: "inland-empire", number: "08", label: "Riverside & the Inland Empire", shortLabel: "Riverside", focus: { lat: 33.97, lng: -117.42, distance: 62, height: 40, rotation: -0.35, }, description: "Ninety kilometres inland and two hundred and sixty metres up, on a grid rotated forty-five degrees to the Santa Ana River. Box Springs Mountain to the east, Mount Baldy on the skyline north.", }, ]; // ---- The pack ------------------------------------------------------------ export const SOCAL_CITY: City = { id: "socal", name: "Southern California", // The centre of the frame rather than the centre of anything civic — it lands // out past Los Alamitos, roughly equidistant from downtown, Riverside and // Dana Point. Putting the scene origin at the middle of the board keeps the // projection symmetric, which matters more on a board this wide than being // able to say the origin is City Hall. center: { lat: 33.82, lng: -118.05 }, bounds: { minLat: 33.28, maxLat: 34.36, minLng: -118.88, maxLng: -117.22 }, /** * 391 m to the scene unit, against San Francisco's 94. * * The board this produces is 393 by 308 units, against the Bay Area's 1003 by * 830 — a metro four times the area rendered on a third of the board, which is * why one instance here is a city block rather than a building. * * This used to be forced rather than chosen: `scene.ts` capped the orbit at * 340 units and `cityDaylight` closed its fog at 460, both tuned when San * Francisco was the only city, so however large a place was on the ground it * had to come out roughly San Francisco's size in scene units or it could not * be looked at. Both now derive from the board, so a pack is free to pick its * own scale. This one keeps 285 because the numbers below — lot size, hill * radii, bridge spans — were all authored against it, not because the engine * still insists. */ latScale: 285, /** * Lower than San Francisco's 3.6, because the relief here does not need the * help and cannot take it. The San Gabriel front rises three kilometres in * eight, which is already twenty degrees; multiplying its tangent by 3.6 puts * it past fifty-five and turns the most dramatic range front in North America * into an obvious cartoon. 3.4 keeps it a wall without making it a cliff. */ verticalExaggeration: 3.4, // ~80 m inside a focus region, ~800 m outside one. See FOCUS_REGIONS for the // arithmetic; the short version is that this is the difference between // 200,000 lattice points and 2.8 million. cellLat: 0.00072, cellLng: 0.00086, coarseFactor: 10, focusRegions: FOCUS_REGIONS, /** * ~500 m, against San Francisco's 200. * * The falloff exists to ramp the terrain grid's stair-stepped rim down to the * smooth shore plate underneath it, so it has to be at least one cell wide or * the steps survive. Out in the basin a cell is 480 m. The cost is that the * Palos Verdes sea cliffs get a flat shelf in front of them, which is a fair * price for a coastline that reads cleanly along its whole length. */ coastFalloff: 0.0045, landmasses: LANDMASSES, parks: PARKS, inlandWater: INLAND_WATER, hills: HILLS, districts: DISTRICTS, /** * The basin's six fields, drawn by `engine/airports.ts`. LAX's runways-as- * roads are gone from `ROADS` above and must stay gone: a board carrying both * floats a dark stripe over every runway the kit lays flush. */ airports: AIRPORTS, /** * San Pedro Bay, drawn by `engine/ports.ts`. Two ports, one federal * breakwater, fifty-six gantries and six container yards — in four draw calls, * because every bucket merges across both ports. */ ports: PORTS, landmarks: LANDMARKS, bridges: BRIDGES, roads: ROADS, chapters: CHAPTERS, /** * Drier and hazier than the default. San Francisco's palette is a cool grey- * green coast; this one is chaparral and decomposed granite, with a warm * horizon because the fog planes here are standing in for the basin's haze * rather than for marine layer. */ palette: { skyTop: 0x8db2d4, skyHorizon: 0xe6ded0, sea: 0x3f7391, lake: 0x4e7d99, shore: 0xc2b393, sand: 0xd2c3a3, flats: 0xa9a291, upland: 0x9a8d74, park: 0x6d7f52, parkHigh: 0x4e6440, }, }; export default SOCAL_CITY;