173 lines
7.6 KiB
Markdown
173 lines
7.6 KiB
Markdown
# Tera
|
|
|
|
The map view of **Lumbridge Simulate** — California from above, in three.js.
|
|
Its other half, **Spaces**, is the offices you walk into: one engine and one
|
|
asset library, seen from outside and from inside.
|
|
|
|
Apache 2.0. Runs at [tera.lumbridgecorp.com](https://tera.lumbridgecorp.com).
|
|
|
|

|
|
|
|
---
|
|
|
|
## What it is
|
|
|
|
An engine plus data packs. The default board joins Los Angeles and San Francisco
|
|
with live deterministic traffic on US-101 and on the honest I-5 → I-580 → I-80
|
|
approach. Choose either route chapter to follow the procedural black Model X.
|
|
|
|
The engine renders terrain, coastline, built cities on authored street grids,
|
|
bridges, roads, markers, road traffic and air traffic. A *city pack* is
|
|
pure data — coastlines, hills, districts, landmarks, camera chapters — so adding
|
|
a city is a data contribution anyone can review, not a fork.
|
|
|
|
California, the detailed Bay Area, and Los Angeles / Orange County / Riverside
|
|
ship today. The corridor is intentionally sparse; detailed cities remain their
|
|
own boards rather than forcing a 600 km world into one full-resolution mesh.
|
|
|
|
A **plan view** sits top right: the board drawn flat, with the footprint of the
|
|
camera's own frustum on it, so you can see where you are looking from outside
|
|
the shot. Click or drag it to move the camera; scroll it to dolly. It is a 2D
|
|
canvas rather than a second WebGL context, drawn from the same city pack, and it
|
|
follows the sun into the night along with everything else.
|
|
|
|
## Who sees what
|
|
|
|
Three tiers, resolved once at boot by `src/access.ts`:
|
|
|
|
| | anonymous | signed in | admin |
|
|
|---|---|---|---|
|
|
| the map, the plan view, the named chapters | ✅ | ✅ | ✅ |
|
|
| observed weather and live aircraft | ✅ | ✅ | ✅ |
|
|
| the office | public depth — shell, furniture, viewpoints, nobody home | full depth, with presence | full depth |
|
|
| the marker feed | per `TERA_MARKERS_ACCESS` | ✅ | ✅ |
|
|
| the godmode panel (`G`) — date, season, weather override, counters, pose editor | — | — | ✅ |
|
|
|
|
The sky is public on purpose. Cloud cover over San Francisco is a government
|
|
sensor reading, and the aircraft are broadcasting their positions unencrypted to
|
|
anyone with a receiver; neither is something an account can grant you access to.
|
|
Gating them cost the only moment that makes this project land — real fog rolling
|
|
off the Pacific onto a city you recognise, at the real time of day, on a first
|
|
visit.
|
|
|
|
The **markers** are the one feed that can carry something private, so the server
|
|
decides. `TERA_MARKERS_ACCESS` is `members` by default and an operator has to
|
|
say `public` out loud, which `/api/v1/health` then announces in `degraded[]`.
|
|
The default is the safe answer rather than the common one, because the failure
|
|
mode is silent: nothing errors, nothing looks broken, the data is just readable
|
|
by the internet.
|
|
|
|
**These are drawing decisions, not a security boundary**, and `src/access.ts`
|
|
says so at length. Live data and office presence are withheld by the *API*, from
|
|
a caller it does not recognise; the client tier stops the app asking for
|
|
something it will not get. Admin is granted only by `TERA_ADMIN_SUBJECTS` on the
|
|
server — never inferred in the browser, and never from an API that failed to
|
|
answer. A deployment with no API at all is open, because "clone it and it works"
|
|
is the promise; it is not "clone it and you are an administrator".
|
|
|
|
## Quick start
|
|
|
|
```bash
|
|
npm install
|
|
npm run dev
|
|
```
|
|
|
|
## Headless RL environments
|
|
|
|
Tera also exports a versioned, renderer-independent Arena contract with four
|
|
deterministic environments: US-101/I-5 driving, Frontier Valley office
|
|
navigation, crow waypoint flight, and California electric-aircraft flight.
|
|
They share the client controllers and office plan, but require no canvas, DOM,
|
|
Three.js scene, network service, or new runtime dependency.
|
|
|
|
Import them from `@lumbridge/tera/arena`. Seeded train/dev scenarios,
|
|
component rewards, safety terminals, maximum steps, snapshots, checksummed
|
|
traces, exact replay and executable inaction/scripted baseline proofs are
|
|
documented in [ARENA.md](ARENA.md).
|
|
|
|
## Using the engine
|
|
|
|
```ts
|
|
import { createScene } from "@lumbridge/tera/engine/scene.ts";
|
|
import { createStage } from "@lumbridge/tera/engine/stage.ts";
|
|
import SAN_FRANCISCO from "@lumbridge/tera/cities/sf.ts";
|
|
|
|
// One stage per canvas, for the life of the page. Cities are put on it and
|
|
// taken off again; a renderer per city leaks its shadow map on every switch.
|
|
const stage = createStage(canvas);
|
|
|
|
const scene = await createScene(stage, {
|
|
city: SAN_FRANCISCO,
|
|
markerPalette: { hiring: 0x4ade80, closed: 0xef4444 },
|
|
});
|
|
|
|
scene?.setMarkers([
|
|
{ id: "1", lat: 37.7765, lng: -122.4241, label: "Somewhere", colorKey: "hiring" },
|
|
]);
|
|
```
|
|
|
|
`createScene` is async because the heightfield is built in a Worker — half a
|
|
million samples, about 730 ms on the Bay Area, and not on the main thread. It
|
|
resolves to `null` if the build was abandoned through `options.signal`, which is
|
|
what makes switching city mid-build cheap.
|
|
|
|
The engine renders `Marker[]` and looks colours up by `colorKey` in a palette
|
|
you supply. It does not know what your markers *mean* — that mapping lives in
|
|
your adapter. This is what lets one renderer serve a private map coloured by
|
|
one scheme and a public map coloured by another, without either being a fork.
|
|
|
|
## Adding a city
|
|
|
|
Write `src/cities/<id>.ts` exporting a `City`. Trace the coastline and parks by
|
|
hand, place hills as radial peaks, and give each district its street bearing.
|
|
|
|
Two rules, and they are not stylistic:
|
|
|
|
- **Do not import geometry from OpenStreetMap.** OSM and Nominatim output is
|
|
ODbL — share-alike, and incompatible with this repo's licence.
|
|
- **Do not commit logos or brand assets.** They are trademarks, not code.
|
|
|
|
See [ARCHITECTURE.md](ARCHITECTURE.md) §3 for the full reasoning, and
|
|
[NOTICE](NOTICE) for the attribution and data-provenance statement, and
|
|
[PROVENANCE.json](PROVENANCE.json) for the machine-checked shipped-artifact and
|
|
original procedural-lineage ledger. Run `npm run provenance`, `npm run licenses`,
|
|
and `npm run sbom` before accepting assets or dependencies.
|
|
|
|
## Aircraft
|
|
|
|
The engine takes a `FlightSource`. Two ship here: `SimulatedFlights` (original,
|
|
flies real approach and departure corridors) and `AdsbFlights` (open community
|
|
ADS-B feeds such as adsb.lol).
|
|
|
|
FlightRadar24 is deliberately absent — their terms forbid scraping and forbid
|
|
redistributing their data, so a client for it cannot live in an Apache-2.0
|
|
repository. Commercial sources belong in private deployments. The best long-term
|
|
answer is an RTL-SDR receiver: first-party data with nothing to comply with.
|
|
|
|
## Layout
|
|
|
|
```
|
|
src/engine/ renderer — terrain, blocks, structures, markers, flights, scene, minimap
|
|
src/cities/ data packs — pure geography, no code
|
|
src/transport/ serializable route packs and renderer-independent simulation
|
|
src/arena/ versioned headless RL contract, scenarios, traces and environments
|
|
src/assets/ original procedural asset library
|
|
src/adapters/ where outside data plugs in
|
|
src/tools/ instruments — god-only, dynamically imported, never statically
|
|
```
|
|
|
|
`engine` never imports `cities`; neither imports `adapters`.
|
|
|
|
Nothing under `src/tools/` may be reached by a static import from the app. It is
|
|
loaded by one `await import()` behind `access.can.debug`, so a visitor who is
|
|
not an admin does not download the code at all — which is the strongest
|
|
available reading of "nothing here runs for a non-god visitor": not a hidden
|
|
panel, not a disabled panel, no panel. `src/tools/index.ts` states the rule and
|
|
what silently undoes it.
|
|
|
|
## Licence
|
|
|
|
Apache License 2.0 — see [LICENSE](LICENSE) and [NOTICE](NOTICE).
|
|
|
|
The ordered build plan and parallel work lanes live in [BUILD_PLAN.md](BUILD_PLAN.md).
|