"sample data · fabricated, not real companies" sat in the corner of every load, because no deployment has a markers source wired by default and the sample set is therefore the overwhelmingly common case. A caption that is always on screen stops being read after the first second, which is the opposite of what a disclosure is for. So the corner keeps only the rare half — "live data", which is genuinely worth interrupting someone to say — and the fact that the markers are invented moves to the two places someone actually looks: the boot card everyone passes through, and the `?` card, which is one keypress away from any state the app can be in. It did not go into a README nobody opens. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Tera
The map view of Lumbridge Simulate — cities 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.
What it is
An engine plus data packs. The engine renders terrain, coastline, a built city on real street grids, bridges, roads, markers 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.
San Francisco ships today. Los Angeles / Orange County / Riverside is next; New York after that.
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 | ✅ | ✅ | ✅ |
| the office | public depth — shell, furniture, viewpoints, nobody home | full depth, with presence | full depth |
| live markers and live traffic | — | ✅ | ✅ |
| the time scrubber and debug readouts | — | — | ✅ |
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
npm install
npm run dev
Using the engine
import { createScene } from "@lumbridge/tera/engine/scene.ts";
import SAN_FRANCISCO from "@lumbridge/tera/cities/sf.ts";
const scene = createScene(canvas, {
city: SAN_FRANCISCO,
markerPalette: { hiring: 0x4ade80, closed: 0xef4444 },
});
scene.setMarkers([
{ id: "1", lat: 37.7765, lng: -122.4241, label: "Somewhere", colorKey: "hiring" },
]);
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 §3 for the full reasoning, and NOTICE for the attribution and data-provenance statement.
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/adapters/ where outside data plugs in
engine never imports cities; neither imports adapters.
