Files
Arah2/.planning/phases/01-design-tokens-rams-foundation/01-03-PLAN.md
T

120 lines
8.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
phase: 01-design-tokens-rams-foundation
plan: 03
type: execute
wave: 3
depends_on: ["01-01", "01-02"]
files_modified:
- theme/basemap/liberty-rams.json
- theme/basemap/build.mjs
- theme/basemap/index.html
- theme/package.json
autonomous: true
requirements: [DSGN-01]
user_setup: []
must_haves:
decisions: [D-08, D-09, D-10]
truths:
- "A Rams-styled MapLibre basemap renders in a browser: grayscale/muted land + water, desaturated roads, muted labels, zero signal-orange in the basemap"
- "Basemap values are derived from the token package, not hand-tuned hex in the style JSON (D-09)"
- "Map labels use the self-hosted Space Grotesk / Geist assets (D-10)"
artifacts:
- path: "theme/basemap/build.mjs"
provides: "Generates liberty-rams.json by reading token values from theme/src/tokens.css"
contains: "tokens.css"
- path: "theme/basemap/liberty-rams.json"
provides: "Forked OpenFreeMap liberty style with Rams cartography"
contains: "glyphs"
- path: "theme/basemap/index.html"
provides: "MapLibre GL browser view proving the basemap renders (success criterion 3)"
contains: "maplibre-gl"
key_links:
- from: "theme/basemap/build.mjs"
to: "theme/src/tokens.css"
via: "parse token custom properties"
pattern: "tokens\\.css"
- from: "theme/basemap/index.html"
to: "theme/basemap/liberty-rams.json"
via: "MapLibre style URL"
pattern: "liberty-rams\\.json"
---
<objective>
Fork the OpenFreeMap `liberty` basemap style into a Rams-constant cartography output: grayscale/muted grounding, desaturated roads, muted labels in Rams type, `signal-orange` reserved exclusively for the future route line (not used in the basemap itself). Prove it renders in a browser with MapLibre GL.
Purpose: D-08 (full Rams pass on basemap), D-09 (derived from tokens, not hand-tuned), D-10 (Rams font assets for labels), roadmap success criterion 3.
Output: `theme/basemap/` — build script, generated style JSON, browser proof page.
</objective>
<read_first>
@planning/phases/01-design-tokens-rams-foundation/01-CONTEXT.md
@planning/phases/01-design-tokens-rams-foundation/01-01-SUMMARY.md
@stitch_minimalist_route_navigator/telemetry_rams/DESIGN.md
</read_first>
<interfaces>
Derivation targets (map token → cartography role per D-08 / telemetry_rams/DESIGN.md "Grayscale Map Grounding"):
- Land/background ground tone: between `soft-beige` (#D9D2C6) and `chassis-subtle` (#CCC4B5)
- Water: desaturated mid-gray derived from `matte-black` mixed toward low-saturation (rgba derived, NOT brand hues)
- Roads: desaturated, hierarchy by weight only (major roads slightly darker than minor)
- Buildings: light gray within the `#D9D2C6 → #1A1A1A` calibrated gray band
- Labels: `matte-black` at reduced opacity; fonts Space Grotesk (major) / Geist (minor) — same assets as theme/fonts (D-10)
- `signal-orange` (#EB8008), `functional-red` (#ED3F1C), `olive-green` (#736B1E) must NOT appear in the basemap — accent is reserved exclusively for the route line rendered in Phase 5 (D-08).
Style input: `https://tiles.openfreemap.org/styles/liberty` style JSON (fetch at build time and fork; do not vendor the full original JSON — build.mjs fetches, transforms, writes).
</interfaces>
<tasks>
<task type="auto">
<name>task 1: basemap build script deriving style from tokens</name>
<files>theme/basemap/build.mjs, theme/basemap/liberty-rams.json</files>
<action>
1. Create `theme/basemap/build.mjs` (Node ESM, no external deps beyond node builtins): fetches `https://tiles.openfreemap.org/styles/liberty` style JSON, transforms it, writes `theme/basemap/liberty-rams.json`.
2. Derivation step: parse `theme/src/tokens.css` extracting the `--color-*` custom property values (deterministic regex `-\-color-([a-z0-9-]+):\s*(#[0-9A-Fa-f]{6})`). Compute the Rams cartography palette IN SCRIPT (D-09: derived, not hand-tuned): desaturate all land/road/water/building colors to the calibrated gray band via a small `desaturate(hex, satMultiplier)` helper (pure function: convert hex→HSL, multiply saturation toward ~0.06–0.12, adjust lightness per role per Interfaces table). Map transformed values onto the liberty style's `layers[].paint` color properties (`background`, `water`, `road-*`, `building-*`, `landcover-*`, `bridge-*`).
3. FONT STEP: replace liberty's glyph/name font stacks. Point the style's `glyphs` to the OpenFreeMap hosted glyphs endpoint (keep `https://tiles.openfreemap.org/fonts/{fontstack}/{range}.pbf` to avoid self-hosting pbf glyphs in Phase 1), and rewrite every `layout["text-font"]` value to `"Space Grotesk Medium"` for major label layers (place-city, place-subtown and above) and `"Noto Sans Regular"` fallback chain ending `"Space Grotesk Regular"`… — IMPORTANT constraint: OpenFreeMap glyphs server only serves font stacks it hosts. If `Space Grotesk` is not available on the glyphs endpoint, detect a 404 at build time and fall back to the closest hosted stack, recording the substitution in a `"metadata"` block (`"rams-font-substitutions": {...}`) — this keeps D-10 satisfied in spirit (Rams typography for labels) with honest fallback provenance.
4. Common concerns: signal-orange/functional-red/olive-green token names are excluded from the derivation set (guard: throw if any of those 3 hex values end up anywhere in the output layers' paint properties).
5. Add npm script to `theme/package.json`: `"basemap": "node basemap/build.mjs"`.
6. Run it; verify `theme/basemap/liberty-rams.json` exists, is valid JSON, has `version: 8`, `glyphs`, `sources`, `layers[0].paint` uses a transformed neutral.
</action>
<verify><automated>npm run basemap --workspace theme && node -e "const s=require('./theme/basemap/liberty-rams.json'); if(!s.layers||!s.glyphs) process.exit(1); const rgx=/EB8008|ED3F1C|736B1E/i; const bad=JSON.stringify(s.layers).match(rgx); if(bad){process.exit(2)} console.log('OK layers='+s.layers.length)"</automated></verify>
<done>build.mjs derives all basemap colors from tokens.css (no hardcoded cartography hex in the script beyond token parsing), output JSON is a valid MapLibre style, and none of the 3 accent colors appear anywhere in the layer paint properties.</done>
</task>
<task type="auto">
<name>task 2: browser proof page (dummy route + rendered basemap)</name>
<files>theme/basemap/index.html, theme/package.json</files>
<action>
1. Create `theme/basemap/index.html`: static MapLibre GL viewer (CDN unpkg `maplibre-gl@^4`), `<style>` sets page chrome to Rams tokens (`var(--color-surface)` background etc. — import `../dist/rams.css`), init map centered ~3.1513, 101.6958 (KLCC / KL metro, per project region), zoom ~13, style = `./liberty-rams.json`.
2. Draw a placeholder route polyline in `signal-orange` (raw tolerance: the ROUTE line is exactly where signal-orange is allowed per D-08) with a thick 6px stroke so the visual "grayscale guiderail + orange vector" intent is previewable, labeled in a README comment as consumed by Phase 5.
3. Add `"basemap:dev": "npx serve theme/basemap || true"`? No extra server dep — just use `python3 -m http.server` invocation pattern for the verify command instead; document the open command in index.html's comment header. Add npm script `"basemap:preview": "cd theme/basemap && python3 -m http.server 8123"`.
4. Layer order: route layer added LAST in the layer stack so it sits above mapcar/roads but below any label overlap is not required here — keep simple.
</action>
<verify><automated>test -f theme/basemap/index.html && grep -q "maplibre" theme/basemap/index.html && grep -q "liberty-rams.json" theme/basemap/index.html && grep -qE "3\.15|101\.69" theme/basemap/index.html</automated></verify>
<done>index.html loads liberty-rams.json, centers KLCC, draws a signal-orange route placeholder, and is checkable via `npm run basemap:preview --workspace theme` → http://localhost:8123 (human eyes verify the grayscale+muted+Rams feel, success criterion 3).</done>
</task>
</tasks>
<threat_model>
## Trust Boundaries
| Boundary | Description |
|----------|-------------|
| basemap build → OpenFreeMap API | build.mjs fetches external style JSON across network |
</threat_model>
<verification>
- `npm run basemap --workspace theme` → 0 exit, liberty-rams.json regenerated
- No accent hex (#EB8008 / #ED3F1C / #736B1E) anywhere in layers' paint
- index.html renders the basemap via the preview script
- `grep -c "tokens.css" theme/basemap/build.mjs` ≥ 1 (derivation provenance)
</verification>
<success_criteria>
Rams basemap derived from (not decorated with) the token package renders in a browser at KL metro with muted grayscale grounding, Rams label fonts, and zero accent-color leaks into cartography. Route accent visually confirmed against the grayscale base (success criterion 3 of the roadmap).
</success_criteria>
<output>
After completion, create `.planning/phases/01-design-tokens-rams-foundation/01-03-SUMMARY.md`
</output>