An open-source, self-hostable, real-time collaborative web map studio. Atlasdraw stacks an Excalidraw drawing surface on top of a MapLibre GL JS basemap so that hand-drawn annotations stay geographically anchored under pan, zoom, and collaborative editing.
Note
Status: v1.0.0 — released 2026-05-15. See CHANGELOG.md.
You need a map where you can sketch, annotate, and collaborate — not just drop pins. Atlasdraw gives you a full drawing toolkit on a real GIS basemap. Annotations reproject on every camera move. Everything stays where you drew it.
- Drawing meets GIS. Freehand, polygons, routes, text — all geo-anchored.
- Self-host first. Runs offline against a bundled PMTiles basemap. No calls home.
- Real-time collaboration. CRDT-backed with cursor presence and anchored comments.
- Open data I/O. Import GeoJSON, CSV, Shapefile. Export PNG, PDF, GeoJSON,
.atlasdraw.
The monorepo lives under code/ and uses Yarn workspaces
(yarn@1.22). Node >= 18.
cd code
yarn install
yarn --cwd apps/atlas-app dev # editor on http://localhost:5173Two compose stacks in infra/:
infra/docker-compose.minimal.yml— 2 services (web+storageinsqlite-fsmode). Bundled PMTiles basemap. No outbound network calls in the default config.infra/docker-compose.yml— full stack:web+storage(postgres-minio mode) +postgres+minio+caddy. Realtime service available via therealtimecompose profile.
Minimal first run: docs/self-host/README.md.
Production deployment: docs/self-host/.
11 subsystems in a hub-and-spoke pattern — atlas-app consumes all packages;
packages have minimal mutual coupling.
graph LR
A[atlas-app<br/>Editor SPA] --> G[geo]
A --> B[basemap]
A --> T[tools]
A --> D[data]
A --> P[protocol]
A --> E[excalidraw]
A --> S[sdk]
S[storage<br/>Fastify API] -.-> storage
R[realtime<br/>WS relay] -.-> ws
| Subsystem | Path | Boundary |
|---|---|---|
| Editor SPA (hub) | code/apps/atlas-app |
Porous — consumes all |
| Vendored Excalidraw Kernel | code/packages/{excalidraw,element,math,common,utils} |
Tight — self-contained fork |
| Geospatial Engine | code/packages/geo |
Tight — pure functions + types |
| Drawing Tools | code/packages/tools |
Loose — 8 independent tools |
| Map Renderer | code/packages/basemap |
Loose — 4 concerns |
| Data Interchange | code/packages/data |
Loose — I/O + Yjs + geocoding |
| Collaboration Protocol | code/packages/protocol |
Tight — pure types |
| Storage Server | code/apps/storage |
Tight — zero atlas imports |
| Collaboration Relay | code/apps/realtime |
Tight — opaque relay |
| CLI Tooling | code/packages/cli |
Tight — 2 commands |
| Embed SDK | code/packages/sdk |
N/A — stub |
Full system map: docs/architecture/overview.md.
Repository layout
atlasdraw/
├── code/ # Yarn-workspace monorepo (forked from excalidraw/excalidraw)
│ ├── apps/
│ │ ├── atlas-app/ # editor SPA — Vite + React 19
│ │ ├── realtime/ # WebSocket relay — Socket.IO + y-websocket
│ │ └── storage/ # Fastify HTTP API — map metadata + blobs
│ ├── packages/
│ │ ├── geo/ # coord transforms, GeoJSON adapters
│ │ ├── basemap/ # MapLibre wrapper, style registry
│ │ ├── data/ # .atlasdraw / GeoJSON / KML / CSV / SHP I/O
│ │ ├── tools/ # geo-aware drawing tools
│ │ ├── protocol/ # collaboration message types
│ │ ├── sdk/ # embed surface (stub)
│ │ ├── cli/ # headless lint / convert / render
│ │ ├── excalidraw/ # vendored upstream (light patches)
│ │ ├── element/ # vendored upstream
│ │ ├── math/ # vendored upstream
│ │ ├── common/ # vendored upstream
│ │ └── utils/ # vendored upstream
│ └── LICENSING.md
├── infra/ # docker-compose + Caddy configs
├── docs/ # architecture, ADRs, self-host, plans
├── PRD.md
├── atlasdraw-tech-spec.md
├── VENDOR.md
├── CHANGELOG.md
└── CLAUDE.md
The upstream Excalidraw fork is inlined under code/ as plain
files (no submodule). Resync procedure in VENDOR.md.
| Concern | Choice | Version |
|---|---|---|
| UI runtime | React | 19.0.0 |
| Drawing surface | @excalidraw/excalidraw (vendored) |
0.18.0 |
| Basemap | maplibre-gl |
^4.7.1 |
| Realtime CRDT | yjs + y-websocket |
^13.6.20 / ^2.0.0 |
| Realtime presence | socket.io-client |
^4.7.0 |
| State | zustand |
5.0.13 |
| Local persistence | idb (IndexedDB) |
^8.0.0 |
| Schemas | zod |
^3.22.0 |
| Accessibility | @react-aria/focus |
^3.20.0 |
| Print/PDF | pdf-lib |
^1.17.1 |
| Build | vite |
^5.0.12 |
| Tests | vitest, @playwright/test |
3.0.6 / ^1.48.0 |
Server (apps/storage): Fastify, optional Postgres / SQLite, optional MinIO / S3.
- Drawing + map composition. MapLibre + Excalidraw with
CoordinateSyncreprojecting elements on every camera move. Drawing tools retuned for maps: pin, polygon, polyline/route, freehand, text, arrow, rectangle, circle.LayerPanelseparates annotations from GeoJSON-backed data layers. - File format + I/O.
.atlasdrawbundle format (scene JSON + per-layer GeoJSON + manifest). Import GeoJSON, CSV, Shapefile. Export PNG, PDF, GeoJSON,.atlasdraw. - Real-time collaboration. WebSocket relay with Socket.IO presence +
y-websocket CRDT. Cursor presence,
MAP_CAMERA_UPDATEevents, anchored comments on a per-room secondY.Doc. - Maputnik style editing — modal round-tripping edits into
@atlasdraw/basemap. - Categorical + graduated layer styling with deterministic MapLibre expression output.
- Print-to-PDF layout panel built on
pdf-lib. - Excalidraw asset library —
.excalidrawlibreader with curated fixtures. - Workspace abstraction —
WorkspaceIdthroughout storage routes. - Accessibility —
@react-aria/focuskeyboard nav,FocusTrap,AriaAnnouncer.
Full list and per-phase recaps: CHANGELOG.md.
- AtlasdrawAPI / SDK / embed widget (
packages/sdkis a stub) - Felt importer
- Phase 7 plugin sandbox
cd code
yarn install
yarn --cwd apps/atlas-app dev # dev server on http://localhost:5173
# Common commands
yarn --cwd apps/atlas-app build # production bundle
yarn --cwd apps/atlas-app test # vitest
yarn --cwd apps/atlas-app test:typecheck # TypeScript
yarn --cwd apps/atlas-app e2e # Playwright (chromium)
yarn test:all # full suite (typecheck + lint + format + vitest)See code/CONTRIBUTING.md for contribution guidelines,
local setup, and pull request expectations.
Architecture decisions are recorded as ADRs in
docs/decisions/. For larger features, start with a
discussion issue before writing code.
Atlasdraw ships under three open-source licenses; the split is deliberate.
Authoritative table: code/LICENSING.md.
| Component | License |
|---|---|
apps/atlas-app |
MIT |
apps/realtime, apps/storage |
AGPL-3.0-only |
packages/sdk, packages/cli, packages/geo, packages/data |
MIT |
packages/basemap, packages/tools |
MPL-2.0 |
Vendored packages/{excalidraw,element,math,common,utils} |
MIT (upstream) |
License files: code/LICENSE-AGPL,
code/LICENSE-MIT,
code/LICENSE-MPL,
code/LICENSE-EXCALIDRAW-UPSTREAM.
PRD.md— product requirementsatlasdraw-tech-spec.md— coordinate sync, scale modes, phase plandocs/architecture/overview.md— architecture overviewdocs/architecture/subsystems.md— per-subsystem responsibilities + contractsdocs/decisions/— ADRsdocs/superpowers/plans/— per-phase implementation plansVENDOR.md— upstream fork pin and resync procedureCHANGELOG.md— release history