HDT CoLab · Fall 2026 · Node.js 22 · node:sqlite · canvas vectors
OSM City Online: a multiplayer OpenStreetMap editor
A multiplayer OpenStreetMap editor that runs against its own local mirror of the map. Roads, buildings, land use, waterways and relations are all editable together in the browser — and nothing is ever written back to OpenStreetMap.
- 2.07 Mnodes
- 320 kways
- 10 krelations
the local mirror
The editor never touches the public database and never asks anyone to authorise an OAuth application.
The server keeps its own extract instead. Importing the Beijing package takes about a minute and produces a single SQLite file — no tile server, no external service, no npm dependencies. Editing is therefore free of consequences for the real map, which is what makes the tool usable in a classroom.
- nodes
- 2.07 M
- ways
- 320 k
- relations
- 10 k
- database
- 478 MB
- import
- 60 s
- peak memory
- 214 MB
drawing a city without tiles
No tile server is involved.
The map is drawn on a canvas from the vector data itself, with 819 styling rules in the spirit of OSM Carto and buildings extruded so that a street reads as a street and a block as a block. The spatial index is the R*Tree built into SQLite, so panning and querying stay instant on a laptop.
| viewport at z16 | 13,411 ways · 79,596 nodes |
|---|---|
| SQL for that viewport | 523 ms |
| payload | 8.5 MB |
| features rendered | 2,817 + 141 labels |
| render time | 101 ms |
| styling rules | 819 |
editing together
Several people edit the same city at once, from the same local network.
Every edit is checked on the server and then broadcast; the client only previews. An element you select is softly locked for 120 seconds so two people cannot rewrite the same road, versions are compared before a write, and a change set can be downloaded as osmChange or rolled back.
- 1selectinspect and edit every OSM tag
- 2nodedrag a node, shift-drag a whole road
- 3pointnew POI, 159 presets
- 4linedraw, enter to finish
- 5areaclosed ways share their first node
- 6splitcut a road at a node
- 7mergejoin two roads at their ends
- 8joincollapse two nodes into one
- 9deletewith optional cascade
- 0rectangularisesquaring a building outline
- Ctrl+F searches by name, by key=value, or by key alone.
- Twelve layer groups can be switched on and off live.
- Undo and redo keep 100 steps per person; a bulk move counts as one.
- Cursors, the element a collaborator is editing, and a chat channel are all visible.
running a network
On top of the real map, you can also run a transport company.
Stations snap to the nearest network node, lines are routed along the real network, and vehicles are simulated on the server. Population and jobs are derived from the buildings themselves, so adding a floor to a building changes the demand around it.
- rail network
- 4,491 ways · 34 k nodes · built in 280 ms
- bus road network
- 91,245 ways · 529 k segments · 3.6 s
- population
- 16.93 M across 32 k grid cells
- jobs
- 4.83 M
- fare
- ¥3 + ¥0.5 per km
- clock
- paused · ×1 · ×5 · ×20
the payload
Making a fast map is mostly a payload problem.
Below the editable zoom the server sends lines and areas merged into compact geometry with no way ids — enough to draw, not enough to select. Reworking what that geometry carries cut the low-zoom payload by roughly half.
before · after
the stack
Zero dependencies: no npm packages, no network at runtime.
The storage engine is the node:sqlite module built into Node 22, the WebSocket server is written from scratch against RFC 6455, and the browser uses Leaflet only as a geometry and interaction engine — never as a tile client.
- browserLeaflet · OSM model · canvas renderer · 819 style rules · 159 presets · 11 tools
- serverroutes · auth (scrypt) · RFC 6455 WebSocket · geometry, tags, references, versions, locks, undo, changesets
- sqlitenodes · ways · way_nodes · relations · relation_members · R*Tree indexes · changesets · changes
how it is checked
Roughly 370 assertions run across six suites: the importer (82), the style table and presets (133), the protocol end to end (77), the browser through CDP (28), boot robustness (18) and the transit protocol (29).
The project's own notes name the next step: binary vector tiles, which should cut the payload by about another ten times.
limits, stated plainly
- This is a local mirror editor, not an upload tool: changes live in one SQLite file and never reach OpenStreetMap.
- OpenStreetMap in China is unevenly mapped, and the page shows raw WGS-84 coordinates rather than GCJ-02.
- Below z15 the map is view-only by design; picking and editing start at the editable band.
- Undo lives in memory — 100 steps per person, cleared when the server restarts.
- A country-wide extract is not a few gigabytes: the project measures 25–40 GB and one to two hours of import.
