cloudcroft disc golf: how this works

The reusable pattern behind the Cloudcroft disc golf map: open-data ingest, Amazon Location Service, Rust lambdas, and a MapLibre frontend.
October 29, 2026 · 3 min · 622 words · Bryan Chasko

This page documents the pattern so anyone can map their own course the same way. The code stays private; the recipe is public.

the dataset

Four open sources, each verified covering Cloudcroft before use:

  • USGS 3DEP 1-meter DEM (project NM_SouthEast_2018_D19). One 248MB tile covers both courses. Sampled anchor elevations match the National Map point service to 0.1 ft. This is the elevation source of record — 30m DEMs give roughly one pixel per 100-foot hole, useless for per-hole profiles.
  • USGS NAIP 2022 60cm imagery. One tile covers both courses, located via the state’s quarter-quad shapefile index. Cropped to a course-window JPEG for the satellite overlay toggle.
  • OpenStreetMap (ODbL). Live bbox extract: 46 paths + 26 footways with real trail names. The S3-native Daylight parquet path was attempted and rejected on measurement — no spatial partitioning, planet-wide scan projected past 25 minutes for a 5 km box. Same underlying data, bbox-native API, 20 seconds.
  • Ground GPS (pending). Every tee pad and basket pinned on foot with a phone GPS + compass bearings. Until those land, the map shows course anchors and published distances — no fabricated pins.

the pipeline

Registry buckets → our S3 prefix → derived JSON, all scripted and rerunnable:

  1. dem_profiles.py samples the 1m tile straight from S3 (/vsis3/, no local copy) for anchor validation and, once pins land, per-hole elevation profiles.
  2. dem_crop.py cuts the course-area window plus a 200x200 mesh grid that feeds the 3D walkthrough terrain.
  3. naip_crop.py cuts the course-window JPEG from the NAIP tile (copied to our prefix first — NAIP is requester-pays, pennies for two tiles).
  4. osm_to_geojson.py turns the Overpass extract into trail/park GeoJSON.

Terrain Tiles (Terrarium PNGs) were evaluated and set aside: the Cloudcroft tile verified live, but both frontends render elevation from the local 1m 3DEP DEM grid instead — nothing reads Terrarium at render time.

the AWS stack

One CDK stack, account 211125425201, us-east-1. TypeScript, stable L1 constructs for Location Service (the L2 package is still alpha):

  • Amazon Location Service: two maps (Esri topo + imagery), an Esri place index, a per-hole geofence collection, a player tracker, a route calculator. Maps and geocoding carry the 2D experience; geofences trigger hole arrival on-site; the tracker ingests player positions.
  • Amazon Cognito identity pool with guest access. One scoped role serves both the web map and the Android app: map/place reads plus tracker writes and geofence evaluation. (A referer-locked API key was the plan for web, but geo:CreateKey is denied account-side even for administrators — the guest pool is the fallback until that clears.)
  • AWS Lambda (Rust, ARM64, musl-static) behind an HTTP API: a plays-like distance function (haversine + elevation model) and a scorecard API over DynamoDB (on-demand, point-in-time recovery). Static musl because the container gnu toolchain links glibc 2.38+, which provided.al2023 (2.34) rejects at init.
  • Amazon S3 + CloudFront: the site bucket hosts the dataset and the web bundle under a registered sibling prefix the site deploy can never wipe.

the frontend

Vite + MapLibre GL + the official Location auth helper, authenticating as a Cognito guest. Bundled data copies keep every fetch same-origin. Verified in headless Chromium against the live URL: tiles render, nine hole rows, zero failed requests, full scorecard click-path green.

reuse it for your course

  1. Pin your tees and baskets (any GPS app, 30 seconds per pin) and note par + distance per hole.
  2. Query the National Map API for your bbox — if a 1m project covers you, one tile probably covers the whole course.
  3. Find your NAIP tile through your state’s QQ index; crop the window.
  4. Pull the Overpass bbox extract for trails and parking.
  5. Stand up the CDK stack, swap the course JSON, deploy the web bundle to any static host. The AR overlays key off the same GeoJSON.