Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

18 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

brcMapTools

Geocode the camps of Black Rock City. Takes the official Burning Man placement PDF and the camp roster JSON, walks you through some interactive corrections, and emits two enriched JSON files that pair each camp with its real-world location on the playa.

What it produces

For every camp in camps.json that could be matched to a polygon on the map, the camp's location object gains:

  • location.centroid — a GeoJSON Point that indicates where the camp should be indicated on a map for navigation. This might be at the center of the frontage, or at a corner for a corner camp. In some cases where camps have weird shapes, the centroid just ends up at the geographical center of the camp.

    "centroid": {
      "type": "Point",
      "coordinates": [-119.21450503439554, 40.77861635238121]
    }
  • location.border — a GeoJSON Polygon outlining the camp's footprint:

    "border": {
      "type": "Polygon",
      "coordinates": [[[-119.2142, 40.7785], [-119.2143, 40.7784], ...]]
    }

Two output files are written:

  • 2025/camps-geocoded.json — camps + centroid only.
  • 2025/camps-geocoded-with-borders.json — camps + centroid + border.

Camps that don't appear on the map come through unchanged (no centroid, no border) in both files.

Prerequisites

We use two input files:

  • 2025/input.pdf — the official BRC placement map
  • 2025/camps.json — the camp roster as an array of objects, from the Burning Man API

Data for each year of burning man is only released to the public when the gate opens. If you need earlier access to build your app and have it ready in time for the burn, join the org's Innovate community -- you will have to sign a nondisclosure agreement.

Setup

npm install

Requires Node ≥ 18 (uses native ES modules), plus tesseract on your PATH (brew install tesseract) for any year whose PDF ships its labels as outlines rather than text — see below.

Different years, different PDFs

The map is redrawn every year and the artists rename and restructure the PDF's layers as they go. layers.js holds one profile per year and is the only place that knows the difference; everything downstream speaks the 2025 vocabulary (Camp Outlines, Camp Names, Listed Name Callouts, Base Map Things).

What changed in 2026:

  • Layer names. Camp Outlines became Listed Theme Camp outlines plus Support camps; Camp Names became Listed Camp Names / Unlisted Camp Names; Listed Name Callouts became Callouts.
  • No text at all. Every label was converted to outlines before export, so the names arrive as ~15k glyph-shaped paths. ocr.js clusters those glyphs back into labels — using the camp outlines themselves to decide which glyphs belong together — renders each one upright, reads it with tesseract, and snaps the result to the closest name in camps.json. It gets ~97% of the listed camps; the rest fall into the usual unmatched-camp naming step. Readings are cached in <year>/ocr-cache.json, so only the first run is slow (~20s). Delete that file to re-read from scratch.
  • Camp outlines are filled ribbons. Each camp is a stroke converted to outlines, i.e. two rings about 8 real feet apart. layers.js pulls them back to the single centreline the artist actually drew, keeping the curves intact so frontage detection still recognises a camp facing a circular street. A camp drawn with just one ring was never closed; those come through open so the client still flags them for you to fix.
  • Callouts are filled artwork — a dot on the camp and an outlined leader — rather than a stroked two-point line, so they get converted back.

To work on a new year, add a profile to layers.js and point YEAR in server.js at it.

Run

npm start

Then open http://localhost:3000.

The server extracts the four target layers from input.pdf at startup (takes a few seconds for the full city) and serves the interactive app from a single page.

A compass in the top-right toggles between 12:00-up (the PDF's native orientation) and true-north-up.

Interaction reference

  • Pan: drag with the left mouse button.
  • Zoom: mouse wheel or trackpad pinch.
  • Fit to window: 0 or f.
  • Toggle orientation: click the compass icon in the top-right.
  • Hover a camp: tooltip shows the camp's name (bold), location_string, dimensions, and exact_location from the roster.

Walkthrough

The app guides you through the calibration steps in order. A status bar at the bottom left corner prompts for each one.

  1. Set the Golden Spike. Click YES, then aim at the dead center of the man and press Enter (red guides snap to the BRC clock-face radials to help you align). Confirm with ACCEPT.

  2. Calibrate the map scale. Translucent green BRC streets are overlaid on top of the PDF. Use + / to grow/shrink them and < / > to refine/coarsen the step size until the green rings sit on the actual streets. Press Enter to accept.

  3. Enter the spike's lat/lon. Paste the published coordinates of the Golden Spike for the current year (e.g. 40.786958, -119.202994). Get this from the Burning Man datasets page

  4. Fix unclosed polygons. The camp outlines on the PDF map were hand drawn by placement team members nad sometimes they are not closed polygons due to user error. They will show up in red. For each one, you have three options: CLOSE AUTOMATICALLY (snaps the last vertex back to the first), DELETE (if the whole polygon is an artifact), or REDRAW (let's you draw a fresh polygon to replace the wrong one in the map, by clicking vertices — Esc cancels, Enter or clicking the start vertex closes).

  5. Add missing polygons. Occasionally you'll see a camp name in the map that doesn't actually have any polygon around it representing its borders. Click ADD and draw a polygon for each — or DONE to skip.

  6. Name unmatched camps. Polygons that the auto-matcher couldn't tie to a roster entry are highlighted pink. Pick the right name from the dropdown (or type one in) and ACCEPT. The dropdown lists camps from the roster that aren't already on the map.

All corrections are saved as you go to 2025/corrections.json, so you can quit and resume without losing progress.

Output

Once every step is done — spike + scale + lat/lon set, no unclosed polygons, add-polygons step finished, no unmatched camps — the status bar disappears and the two output files are written automatically. The browser console logs:

Wrote camps-geocoded.json (N/total centroids) and camps-geocoded-with-borders.json (M borders)

Re-emission happens on every load (and on every correction once you're past the all-done threshold), so the files always reflect the latest state.

Layout

The data directory is named for the event year. It's set by the YEAR constant at the top of server.js — change that one line to work on a different year, and rename/create the directory to match.

.
├── 2025/                                  (named by YEAR in server.js)
│   ├── input.pdf                          (you supply)
│   ├── camps.json                         (you supply)
│   ├── corrections.json                   (created/updated as you work)
│   ├── ocr-cache.json                     (cached label readings, outlined-text years)
│   ├── camps-geocoded.json                (output)
│   └── camps-geocoded-with-borders.json   (output)
├── public/
│   └── app.js                             (browser-side logic)
├── extract.js                             (pdf.js layer extraction)
├── layers.js                              (per-year PDF profiles + normalization)
├── ocr.js                                 (reads camp names off outlined labels)
├── server.js                              (Node HTTP server + endpoints)
└── package.json

About

No description, website, or topics provided.

Resources

Stars

5 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages