Find and explore urban amenities around you
A clean, interactive web map that helps you discover benches, water fountains, bike parking, and other useful amenities in your neighborhood. Built with real-time OpenStreetMap data and high-resolution aerial imagery from PDOK.
- Find My Location: Use your phone's GPS to see what's around you
- Click Anywhere: Click on the map to explore any location you're curious about
- Light: CartoDB Positron
- Dark: CartoDB DarkMatter
- Smart clustering keeps the map readable at all zoom levels
- 🪑 Benches — core focus
- 🚰 Water Fountains — stay hydrated
- 🚻 Toilets — essential facilities
- Adjust search radius from 200m to 2km
- Filter which types of amenities you want to see
- Real-time counts showing how many amenities were found
- Capture the benches you find under a neighborhood name
- Reload saved benches later without hitting Overpass again
- Manage saved sets right from the analysis panel (load or remove)
- Fork this repository to your GitHub account
- Enable Pages: Go to Settings → Pages → Deploy from branch →
main - Visit your site:
https://yourusername.github.io/BenchMark
# Clone the repo
git clone https://github.com/lukasbeuster/BenchMark.git
cd BenchMark
# Start a simple web server
python -m http.server 8000
# Open in your browser
open http://localhost:8000- Open the app in your web browser
- Click "Locate Me" to find amenities near you (allow location access)
- Or switch to "Click-to-query" and click anywhere on the map
- Adjust the search radius with the slider if needed
- Toggle amenity types on/off using the checkboxes
- Name & save benches for a neighborhood to keep a local copy
- Load a saved neighborhood later to revisit benches without re-querying
- Click on markers to see details about each amenity
- Zoom in close to see exactly where things are located
- Theme tokens live under
:root[data-theme="light"]and:root[data-theme="dark"]instyle.css. - Palette (Studio Matter):
- Light — Background
#fcf4ed, Text#1B1B1B, Muted#5A5550, Lines#E6DAC7, Accents#FFD23F(primary),#D96831(secondary) - Dark — Background
#111827, Surface#0B1220–#141A22, Text#F6F2E9, Muted#C9C1B6, Lines#2A3440
- Light — Background
- Toggle the theme using the header control; it switches UI and basemap together.
Click “Check Shade Now” to estimate if benches are currently in sun or shade. Use the Shade Time slider to simulate different hours of the day.
- How it works (client-side):
- Uses SunCalc to get sun azimuth/altitude for the selected local time and map center (night = all shaded; indicator shows “below horizon”)
- Fetches building footprints within the current bounds from Overpass (OSM)
- Estimates height from
building:heightorbuilding:levels(fallback to 12 m; configurable in code) - Translates each footprint opposite the sun azimuth by
height / tan(altitude)and buffers slightly to approximate shadow - Fetches OSM
natural=treepoints and approximates crown shadows (default height 9 m, crown diameter 7 m) - Tests bench points against all shadow shapes (via Turf) → shaded or sunlit
- Notes:
- This is a first-order approximation (no occlusion stacking, terrain, or façade shape)
- Confidence increases when explicit heights exist (buildings/trees) and the sun is low
- Optional tree shading is not included in MVP
- Amenities and buildings: OpenStreetMap via Overpass API
- Trees: OpenStreetMap (
natural=tree) via Overpass API
- Building height default: 12 m (DEFAULT_BUILDING_HEIGHT_M)
- Level-to-meters factor: 3.2 (LEVEL_TO_METERS)
- Tree height default: 9 m (DEFAULT_TREE_HEIGHT_M)
- Crown diameter default: 7 m (DEFAULT_CROWN_DIAM_M)
- Minimum solar altitude clamp: 1.5° (MIN_SOLAR_ALT_DEG)
- On first load, the app initializes analysis time to the user’s current local time (rounded to nearest 15 minutes), sets the slider/minutes, and stores it in
localStorage(bm-shade-time). - All SunCalc calls are made using a local Date constructed from the selected time on the current day.
- The header shows a compact solar altitude indicator (Alt: XX.X° ↑/↓ or “below horizon”).
- Trees are shown as subtle dots (fill #CFE7D1, stroke #B9D6BC) by default. Toggle visibility via the “Show trees” checkbox.
- Basemaps: CARTO (Positron/DarkMatter)
- Overpass responses depend on OSM coverage and may omit heights
- Shadow model is a planar 2D approximation
- Trees are modeled as circles; forests aren’t yet included
- 3D BAG: not integrated yet — hooks are in code to substitute its geometry/height source
- Saved neighborhoods live in your browser storage; clearing it removes the saved benches
- To substitute 3DBAG, implement a
fetchBuildings3DBAG(bounds)function that returns Turf polygons with abuilding:height(meters) tag, then swap it incheckShadeNow()instead offetchBuildings(). - Heavy views are capped for performance; recompute as needed
- Press
Escto clear your current search - Click on cluster numbers to zoom in and see individual markers
- The app works great on mobile devices too!
- Leaflet.js: Interactive maps
- OpenStreetMap: Crowd-sourced amenity data via Overpass API
- PDOK: High-resolution aerial imagery from the Dutch government
- Modern CSS & JavaScript: Clean, responsive design
- Shows up to 250 amenities per search (to keep things fast)
- Smart marker clustering prevents map clutter
- Optimized for both desktop and mobile devices
Want to find something else? Easy! Just edit script.js:
// Add your new amenity type
this.amenityTypes = {
// ... existing amenities
playground: {
icon: '🛝',
color: '#ff6b6b',
name: 'Playgrounds',
category: 'recreation',
size: 'large'
}
};Then add a checkbox in index.html:
<label class="filter-item">
<input type="checkbox" data-amenity="playground" checked>
<span class="filter-marker" style="background-color: #ff6b6b;">🛝</span>
<span class="filter-label">Playgrounds</span>
<span class="filter-count" data-type="playground">0</span>
</label>The design uses CSS variables for easy customization:
:root {
--primary-navy: #1a1f36; /* Header background */
--accent-cyan: #16a085; /* Interactive elements */
--golden-yellow: #FFD23F; /* Your location marker */
}Currently optimized for the Netherlands (uses PDOK aerial imagery), but you can adapt it for anywhere:
// Replace PDOK with standard OpenStreetMap tiles
pdokTileUrl: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
defaultCenter: [40.7128, -74.0060], // New York, for example- New in town? Quickly find essential amenities in your neighborhood
- Planning a bike ride? See where you can park and grab water
- Out and about? Find the nearest public toilet or bench
- Identify gaps: See which areas lack certain amenities
- Plan improvements: Use data to advocate for more benches, bins, etc.
- Accessibility mapping: Check wheelchair accessibility info where available
- Urban planners: Get a quick overview of amenity distribution
- City officials: Identify areas that might need more infrastructure
- Accessibility advocates: Map barrier-free amenities
Works on all modern browsers including:
- Chrome, Firefox, Safari, Edge
- Mobile browsers (iOS Safari, Chrome Mobile)
- Requires location permissions for "Find My Location" feature
Map not loading?
- Check your internet connection
- Try refreshing the page
- Make sure JavaScript is enabled
Location not working?
- Allow location permissions when prompted
- Try the "Click-to-query" mode instead
- Make sure you're using HTTPS (required for location services)
No amenities showing?
- Try increasing the search radius
- Check if you're in an area covered by OpenStreetMap
- Some rural areas may have limited data
Found a bug or want to add a feature? Contributions are welcome!
- Fork the repository
- Create a feature branch:
git checkout -b cool-new-feature - Make your changes and test them
- Submit a pull request
- Your location: Only used locally in your browser, never stored or sent anywhere
- Map data: Comes from OpenStreetMap contributors (thanks! 🙏)
- Aerial imagery: Provided by PDOK (Dutch national spatial data infrastructure)
- No tracking: This app doesn't collect any personal data
MIT License - feel free to use this code for your own projects!
- OpenStreetMap Community: For the amazing crowd-sourced map data
- PDOK: For providing high-quality aerial imagery
- Leaflet: For making interactive maps easy
- GitHub Pages: For free hosting
Made with ♥ for exploring cities
Have suggestions or found this useful? Let us know!
- Custom minimal SVG icons are used for amenities (bench, water fountain, toilets) so they render crisply on Positron at all zoom levels. Colors come from CSS variables and remain accessible:
- Benches (sunlit):
#FFD23F(fill), stroke#1B1B1B - Benches (shaded/night):
#4FA3B6(fill), stroke#1B1B1B - Water:
#607CAA - Toilet:
#002666 - Marker sizing is constant (bench 18px; water/toilet 16px); hit area includes 4px padding.
- Benches (sunlit):
- Trees are fetched by current bounds in Click-to-query mode, or by radius around the analysis point in Location mode. Requests are rate-limited, retried on 429, and cached by bounds/point keys.
- Trees render as circle markers sized from tags where available:
- Prefer
diameter_crown(m); elsecircumference_crown/π; else0.6 × height; else default 7 m. - Diameter is mapped to pixels using current latitude/zoom, clamped to 12–22 px. Fill
#A7D7B3, stroke#6FB789. - A cap (~1500 trees) applies for performance; counts overlay shows totals.
- Prefer
- Benches use two minimal SVG variants with identical footprint so there’s no layout shift on swap:
- Sunlit: benchSunlitIcon — a bench with a small sun disk cue in the corner; fill
#FFD23F, stroke#1B1B1B. - Shaded/Night: benchShadedIcon — the same bench with a subtle diagonal slab cue; fill
#4FA3B6, stroke#1B1B1B.
- Sunlit: benchSunlitIcon — a bench with a small sun disk cue in the corner; fill
- The Amenity Types legend renders the exact same SVGs (at ~14px) so legend and map remain consistent.