# BincioPlanner — CLAUDE.md Route planning tool for bincio members. Intentionally separate from `bincio_activity` — different product scope, different lifecycle, no shared codebase. ## Stack - **Vite + Svelte 5** (no Astro — single page, no SSR needed) - **MapLibre GL JS** for the map - **Brouter public API** for routing (`https://brouter.de/brouter`) - Pure static output — no backend, no Python ## Dev & deploy ```bash # local dev (requires bincio_activity running on localhost:4321) npm run dev # deploy to planner.bincio.org bash deploy.sh ``` `.env.local` sets `VITE_ACTIVITY_URL=http://localhost:4321` for dev. `deploy.sh` overrides it with `https://activity.bincio.org` for production. ## Auth On load, fetches `$VITE_ACTIVITY_URL/api/me` with `credentials: 'include'`. The bincio session cookie is scoped to `.bincio.org` so it works across subdomains. Non-authed users are redirected to the bincio login page. The bincio_activity server must allow CORS from `planner.bincio.org` — this is handled by the regex in `bincio/serve/server.py`. ## What's implemented - [x] Click map to place numbered draggable waypoints - [x] Route computed via Brouter, drawn on map (debounced 400ms) - [x] Drag waypoint to move — re-routes correctly - [x] Profile selector: Road / Gravel / MTB / Hiking - [x] "Close loop" button (duplicates first waypoint as last) - [x] "Clear all" button - [x] Route stats: distance + elevation gain - [x] GPX export (generated from Brouter GeoJSON response) - [x] Elevation chart below map (SVG, responsive) - [x] Race-calendar palette (Giro/Tour/Vuelta/default), mirrors bincio_activity - [x] Auth gate with redirect to bincio login - [x] Deployed to `https://planner.bincio.org` with HTTPS ## Activity-year colour palette Year-coded colours used for GPX reference tracks (and potentially other per-year data). Defined as `GPX_PALETTE` in `Planner.svelte`. | Year | Color | Description | |------|-------|-------------| | 2014 | `hsl(265, 38%, 52%)` | muted purple | | 2015 | `hsl(248, 40%, 53%)` | slate-indigo | | 2016 | `hsl(232, 43%, 54%)` | slate-blue | | 2017 | `hsl(208, 48%, 52%)` | steel blue | | 2018 | `hsl(185, 52%, 50%)` | teal | | 2019 | `hsl(165, 50%, 49%)` | green-teal | | 2020 | `hsl(145, 48%, 47%)` | green | | 2021 | `hsl(100, 57%, 49%)` | yellow-green | | 2022 | `hsl(50, 72%, 52%)` | amber | | 2023 | `hsl(34, 75%, 53%)` | orange | | 2024 | `hsl(16, 77%, 56%)` | red-orange | | 2025 | `hsl(5, 70%, 57%)` | warm coral | | 2026 | `#60a5fa` | bright blue | | — | `#71717a` | grey (undated) | ## What's missing (from original plan) - [ ] **Map tile switcher** — toggle between OSM and OpenCycleMap (Thunderforest, requires free API key). OpenCycleMap is significantly better for route planning. - [x] **Drag-to-modify route polyline** — click and drag a point on the route line to insert a new waypoint. Deferred: requires hit-testing which segment was dragged, then inserting a waypoint at the right index. Doable but fiddly. - [ ] **Heatmap overlay** — nice-to-have. Our own data is too sparse (~20 users). Public options: Strava global heatmap (legally gray), Waymarked Trails (clean, OSM-based). - [ ] **Palette flash** — the race-calendar palette runs in `onMount`, so there's a brief flash from the default CSS vars to the correct palette. In bincio_activity this is avoided by an inline `