@unmap/themes 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +10 -8
- package/dist/index.d.ts +188 -36
- package/dist/index.js +868 -559
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/palette.ts","../src/recipe.ts","../src/recipes.ts","../src/validate.ts","../src/codec.ts","../src/compose.ts","../src/contrast.ts","../src/presets.ts","../src/oklch.ts","../src/generate.ts","../src/palettes.ts"],"sourcesContent":["/**\n * Named colour ramps: the single source of colour truth for unmap cartography.\n *\n * Moved here from apps/gateway/src/palette.ts (which now re-exports these) so themes, the\n * gateway, and the builder all draw from one vocabulary. Flavors and theme recipes reference\n * these by name and never inline a hex literal.\n *\n * Ramps run light to dark by ascending key.\n */\n\n/**\n * Ember. Pre-rebrand brand accent; survives only as the `street` motorway orange, which is\n * cartographic convention (orange motorways) rather than brand. Never the interface accent —\n * that is magenta, which stays out of every basemap.\n */\nexport const ember = {\n 200: \"#ffe9c9\",\n 300: \"#ffc08c\",\n 400: \"#f7a35c\",\n 500: \"#f97316\",\n 600: \"#e07b2e\",\n 700: \"#b45309\",\n} as const;\n\n/* ── Process Ink ramps ─────────────────────────────────────────────────────────────────────\n *\n *\n * Generated in OKLCH rather than picked by eye, from three hues the brand already implies:\n * cool neutrals at 212, water at 200, vegetation at 152, with one warm family at 82 for sand\n * and farmland. OKLCH matters here because a ramp picked in sRGB has uneven perceived steps —\n * two adjacent greens can look identical while two adjacent greys look like a seam.\n *\n * Lightness is chosen so the label contrast the cartography tests enforce is a property of the\n * ramp rather than something rescued per flavour afterwards. `ink.700` on `ink.25` clears 4.5:1,\n * `ink.500` on `ink.1000` clears it inverted, and every flavour's labels are drawn from those\n * steps. That is the whole reason the generator solves for lightness instead of guessing.\n *\n * Magenta is deliberately absent. It is the interface accent — markers, selection, overlays —\n * and keeping it out of the basemap is what lets a customer's data always win the colour fight.\n *\n * Regenerate rather than hand-edit: the ramp is the source, the hex is the output.\n */\n\n/** Cool neutrals, hue 212. The spine of every Process Ink flavour. */\nexport const ink = {\n 25: \"#F1F8FA\",\n 50: \"#EAF2F3\",\n 100: \"#E2E9EB\",\n 200: \"#D6DEE0\",\n 300: \"#C9D1D3\",\n 400: \"#B7C0C2\",\n 500: \"#9DA7A9\",\n 600: \"#7E888B\",\n 700: \"#5C6769\",\n 800: \"#3D494B\",\n 850: \"#2B3639\",\n 900: \"#1A2628\",\n 950: \"#0E191C\",\n 1000: \"#030E10\",\n} as const;\n\n/** Water, hue 200. Cooler and more chromatic than the land it meets. */\nexport const wave = {\n 100: \"#C7F1F3\",\n 200: \"#B3E2E4\",\n 300: \"#9CCFD2\",\n 400: \"#7FB8BB\",\n 500: \"#5F9FA2\",\n 600: \"#368286\",\n 700: \"#1C6265\",\n 800: \"#024347\",\n 900: \"#002A2C\",\n 950: \"#001C1E\",\n 980: \"#001012\",\n} as const;\n\n/** Vegetation, hue 152: park, wood, scrub. */\nexport const verdant = {\n 100: \"#D3F1DA\",\n 200: \"#C3E3CA\",\n 300: \"#AFD2B7\",\n 400: \"#96BC9F\",\n 500: \"#76A281\",\n 600: \"#50825E\",\n 700: \"#366042\",\n 800: \"#1E4128\",\n 900: \"#0B2815\",\n} as const;\n\n/** Warm landcover, hue 82: sand, beach, farmland. */\nexport const sandstone = {\n 100: \"#F5E8D0\",\n 200: \"#E7D9BF\",\n 300: \"#D6C7AC\",\n 400: \"#BFAF92\",\n 500: \"#A19070\",\n} as const;\n\n/**\n * Pure neutrals, zero chroma. The `muted` pair only.\n *\n * `ink` carries a hue-212 cool cast, which is right for every other flavour and wrong for this\n * one: `muted` exists to vanish under a customer's data, and a basemap with *any* hue biases the\n * colours laid on top of it. So muted gets its own ramp where R=G=B exactly.\n *\n * Calibrated against Mapbox Light and Protomaps' `WHITE`, whose land/water/building relationships\n * this flavour follows: land a light grey, roads *brighter* than the land rather than darker,\n * buildings a single step down, and water the only tone with any real weight.\n *\n * Their label colours are deliberately NOT copied. Protomaps `WHITE` puts `state_label` #b3b3b3\n * on #ffffff, roughly 2:1, which fails the 4.5:1 floor `cartography.test.ts` enforces. The\n * structure is worth borrowing; the label contrast is not.\n */\nexport const graphite = {\n 25: \"#FAFAFA\",\n 50: \"#F2F2F2\",\n 100: \"#E9E9E9\",\n 200: \"#DEDEDE\",\n 300: \"#D1D1D1\",\n 400: \"#BEBEBE\",\n 500: \"#A4A4A4\",\n 600: \"#868686\",\n 700: \"#656565\",\n 800: \"#464646\",\n 900: \"#232323\",\n 1000: \"#0B0B0B\",\n} as const;\n","import type { Flavor } from \"@protomaps/basemaps\";\n\n/**\n * The unmap cartography authoring surface, moved here from apps/gateway/src/flavors.ts so the\n * gateway, the theme system, and the unmap.dev builder share one definition.\n *\n * A `Recipe` is what a theme can override: every colour a Flavor controls, expressed at the\n * level we author at. Expanding through `makeFlavor` keeps the consistency guarantees a raw\n * Flavor cannot: a casing is always derived beside its fill, and the tunnel and bridge families\n * cannot drift out of step with the surface roads they mirror.\n */\n\n/**\n * Appended, never inserted. This array's order drives the style picker in the unmap.dev builder,\n * so inserting a base mid-array silently reorders a control people have already learned.\n */\nexport const THEME_BASES = [\"base\", \"muted\", \"relief\", \"street\", \"outdoor\"] as const;\nexport type ThemeBase = (typeof THEME_BASES)[number];\n\nexport const MODES = [\"light\", \"dark\"] as const;\nexport type ThemeMode = (typeof MODES)[number];\n\nexport interface RoadRamp {\n /** Unclassified / track. The bottom of the hierarchy. */\n other: string;\n otherCasing: string;\n /** Residential and service. */\n minor: string;\n minorCasing: string;\n service: string;\n serviceCasing: string;\n /** Primary / secondary. */\n major: string;\n majorCasing: string;\n /** Motorway. */\n highway: string;\n highwayCasing: string;\n /** Slip roads. */\n link: string;\n linkCasing: string;\n}\n\nexport interface LabelRamp {\n city: string;\n cityHalo: string;\n state: string;\n stateHalo: string;\n country: string;\n subplace: string;\n subplaceHalo: string;\n address: string;\n addressHalo: string;\n roadMinor: string;\n roadMinorHalo: string;\n roadMajor: string;\n roadMajorHalo: string;\n ocean: string;\n}\n\nexport interface Recipe {\n background: string;\n earth: string;\n water: string;\n /** Park, wood and scrub each take two tones; `b` is the slightly deeper of the pair. */\n parkA: string;\n parkB: string;\n woodA: string;\n woodB: string;\n scrubA: string;\n scrubB: string;\n sand: string;\n beach: string;\n glacier: string;\n /** Institutional land: hospital, school, industrial, military, zoo, aerodrome. */\n institutional: string;\n pedestrian: string;\n aerodrome: string;\n runway: string;\n pier: string;\n buildings: string;\n railway: string;\n boundaries: string;\n roads: RoadRamp;\n labels: LabelRamp;\n /**\n * Tunnels read one step recessive against the surface road, bridges one step assertive.\n * Expressed as the colours to substitute rather than a computed shift, so a style can opt\n * out of the convention where it does not suit the palette.\n */\n tunnelFill: string;\n tunnelCasing: string;\n bridgeCasing: string;\n pois: Flavor[\"pois\"];\n landcover: Flavor[\"landcover\"];\n}\n\n/**\n * Expand a recipe into the full Flavor. Every one of the interface's required slots is written\n * here exactly once, so a missing slot is a compile error rather than a silently black layer.\n */\nexport function makeFlavor(r: Recipe): Flavor {\n return {\n background: r.background,\n earth: r.earth,\n water: r.water,\n\n park_a: r.parkA,\n park_b: r.parkB,\n wood_a: r.woodA,\n wood_b: r.woodB,\n scrub_a: r.scrubA,\n scrub_b: r.scrubB,\n sand: r.sand,\n beach: r.beach,\n glacier: r.glacier,\n\n hospital: r.institutional,\n industrial: r.institutional,\n school: r.institutional,\n zoo: r.institutional,\n military: r.institutional,\n pedestrian: r.pedestrian,\n aerodrome: r.aerodrome,\n runway: r.runway,\n pier: r.pier,\n buildings: r.buildings,\n\n // Surface roads.\n other: r.roads.other,\n minor_service: r.roads.service,\n minor_a: r.roads.minor,\n minor_b: r.roads.minor,\n link: r.roads.link,\n major: r.roads.major,\n highway: r.roads.highway,\n\n minor_service_casing: r.roads.serviceCasing,\n minor_casing: r.roads.minorCasing,\n link_casing: r.roads.linkCasing,\n // early/late are the same colour: they exist so Protomaps can fade casings in at\n // different zooms, not to differentiate hue.\n major_casing_early: r.roads.majorCasing,\n major_casing_late: r.roads.majorCasing,\n highway_casing_early: r.roads.highwayCasing,\n highway_casing_late: r.roads.highwayCasing,\n\n // Tunnels: recessive, one flat fill so the network reads as \"beneath\".\n tunnel_other: r.tunnelFill,\n tunnel_minor: r.tunnelFill,\n tunnel_link: r.tunnelFill,\n tunnel_major: r.tunnelFill,\n tunnel_highway: r.tunnelFill,\n tunnel_other_casing: r.tunnelCasing,\n tunnel_minor_casing: r.tunnelCasing,\n tunnel_link_casing: r.tunnelCasing,\n tunnel_major_casing: r.tunnelCasing,\n tunnel_highway_casing: r.tunnelCasing,\n\n // Bridges: same fills as the surface road so the ribbon stays continuous, with a\n // stronger casing that lifts it off whatever it crosses.\n bridges_other: r.roads.other,\n bridges_minor: r.roads.minor,\n bridges_link: r.roads.link,\n bridges_major: r.roads.major,\n bridges_highway: r.roads.highway,\n bridges_other_casing: r.bridgeCasing,\n bridges_minor_casing: r.bridgeCasing,\n bridges_link_casing: r.bridgeCasing,\n bridges_major_casing: r.bridgeCasing,\n bridges_highway_casing: r.bridgeCasing,\n\n railway: r.railway,\n boundaries: r.boundaries,\n\n roads_label_minor: r.labels.roadMinor,\n roads_label_minor_halo: r.labels.roadMinorHalo,\n roads_label_major: r.labels.roadMajor,\n roads_label_major_halo: r.labels.roadMajorHalo,\n ocean_label: r.labels.ocean,\n subplace_label: r.labels.subplace,\n subplace_label_halo: r.labels.subplaceHalo,\n city_label: r.labels.city,\n city_label_halo: r.labels.cityHalo,\n state_label: r.labels.state,\n state_label_halo: r.labels.stateHalo,\n country_label: r.labels.country,\n address_label: r.labels.address,\n address_label_halo: r.labels.addressHalo,\n\n pois: r.pois,\n landcover: r.landcover,\n };\n}\n","import type { Recipe, ThemeBase, ThemeMode } from \"./recipe\";\nimport { ember, graphite, ink, sandstone, verdant, wave } from \"./palette\";\n\n/**\n * The five ramp families (plus ember) a recipe draws from. `buildRecipes` is parameterized on\n * this so the theme generator can re-emit the same recipes from *generated* ramps — same\n * lightness ladders, a customer's hues — while the stock `RECIPES` stay byte-identical to the\n * hand-tuned originals (they are `buildRecipes(STOCK_RAMPS)`).\n */\nexport interface RampSet {\n ink: typeof ink;\n wave: typeof wave;\n verdant: typeof verdant;\n sandstone: typeof sandstone;\n graphite: typeof graphite;\n ember: typeof ember;\n}\n\nexport const STOCK_RAMPS: RampSet = { ink, wave, verdant, sandstone, graphite, ember };\n\n/*\n * The eight Process Ink recipes as data, moved from apps/gateway/src/flavors.ts.\n * These are the chassis a ThemeDoc's sparse overrides merge onto. Colour comes from the\n * ramps in ./palette and never a hex literal here, except pure white road fills.\n */\n\n/** Build the eight recipes from a ramp set. Stock ramps in → the shipped cartography out. */\nexport function buildRecipes(r: RampSet): Record<ThemeBase, Record<ThemeMode, Recipe>> {\n/**\n * `base` / `light`. The general-purpose map: full road hierarchy, buildings you can see, and\n * landcover differentiated enough to read as terrain rather than as one flat field. This is the\n * flavour someone gets when they have not chosen one, so it errs towards legible over quiet.\n */\nconst BASE_LIGHT: Recipe = {\n background: r.ink[200],\n earth: r.ink[100],\n water: r.wave[300],\n parkA: r.verdant[200],\n parkB: r.verdant[300],\n woodA: r.verdant[200],\n woodB: r.verdant[300],\n scrubA: r.verdant[200],\n scrubB: r.verdant[300],\n sand: r.sandstone[200],\n beach: r.sandstone[200],\n glacier: r.ink[25],\n institutional: r.ink[50],\n pedestrian: r.ink[50],\n aerodrome: r.ink[50],\n runway: r.ink[200],\n pier: r.ink[300],\n buildings: r.ink[300],\n railway: r.ink[500],\n boundaries: r.ink[600],\n roads: {\n other: r.ink[50],\n otherCasing: r.ink[300],\n minor: r.ink[25],\n minorCasing: r.ink[300],\n service: r.ink[50],\n serviceCasing: r.ink[300],\n major: \"#FFFFFF\",\n majorCasing: r.ink[400],\n highway: \"#FFFFFF\",\n highwayCasing: r.ink[500],\n link: \"#FFFFFF\",\n linkCasing: r.ink[400],\n },\n tunnelFill: r.ink[200],\n tunnelCasing: r.ink[300],\n bridgeCasing: r.ink[500],\n labels: {\n city: r.ink[1000],\n cityHalo: r.ink[25],\n state: r.ink[700],\n stateHalo: r.ink[25],\n country: r.ink[700],\n subplace: r.ink[700],\n subplaceHalo: r.ink[25],\n address: r.ink[700],\n addressHalo: r.ink[25],\n roadMinor: r.ink[700],\n roadMinorHalo: r.ink[25],\n roadMajor: r.ink[800],\n roadMajorHalo: r.ink[25],\n ocean: r.wave[800],\n },\n\n pois: {\n blue: \"#2D6E8F\",\n green: r.verdant[700],\n lapis: \"#3F5C93\",\n pink: \"#8F4A6B\",\n red: \"#9B4340\",\n slategray: r.ink[700],\n tangerine: \"#8F5322\",\n turquoise: r.wave[700],\n },\n landcover: {\n grassland: r.verdant[200],\n barren: r.sandstone[200],\n urban_area: r.ink[50],\n farmland: r.verdant[100],\n glacier: r.ink[25],\n scrub: r.verdant[100],\n forest: r.verdant[300],\n },\n};\n\n/**\n * `base` / `dark`. The same map inverted, with the inversion that matters: water is drawn\n * *darker* than land. Two mid-tones meeting at a coastline is how a dark basemap turns to mud,\n * so the figure/ground edge is bought with lightness rather than hue.\n */\nconst BASE_DARK: Recipe = {\n background: r.ink[950],\n earth: r.ink[900],\n water: r.wave[980],\n parkA: r.verdant[800],\n parkB: r.verdant[700],\n woodA: r.verdant[800],\n woodB: r.verdant[700],\n scrubA: r.verdant[800],\n scrubB: r.verdant[700],\n sand: r.sandstone[500],\n beach: r.sandstone[500],\n glacier: r.ink[700],\n institutional: r.ink[950],\n pedestrian: r.ink[950],\n aerodrome: r.ink[950],\n runway: r.ink[850],\n pier: r.ink[850],\n buildings: r.ink[850],\n railway: r.ink[700],\n boundaries: r.ink[600],\n roads: {\n other: r.ink[850],\n otherCasing: r.ink[1000],\n minor: r.ink[800],\n minorCasing: r.ink[1000],\n service: r.ink[850],\n serviceCasing: r.ink[1000],\n major: r.ink[700],\n majorCasing: r.ink[1000],\n highway: r.ink[600],\n highwayCasing: r.ink[1000],\n link: r.ink[700],\n linkCasing: r.ink[1000],\n },\n tunnelFill: r.ink[900],\n tunnelCasing: r.ink[1000],\n bridgeCasing: r.ink[1000],\n labels: {\n city: r.ink[100],\n cityHalo: r.ink[1000],\n state: r.ink[500],\n stateHalo: r.ink[1000],\n country: r.ink[500],\n subplace: r.ink[500],\n subplaceHalo: r.ink[1000],\n address: r.ink[500],\n addressHalo: r.ink[1000],\n roadMinor: r.ink[500],\n roadMinorHalo: r.ink[1000],\n roadMajor: r.ink[400],\n roadMajorHalo: r.ink[1000],\n ocean: r.wave[400],\n },\n\n pois: {\n blue: \"#7FC4E8\",\n green: r.verdant[400],\n lapis: \"#8FB0EA\",\n pink: \"#E3A0C0\",\n red: \"#EE968F\",\n slategray: r.ink[500],\n tangerine: \"#E8AC7C\",\n turquoise: r.wave[400],\n },\n landcover: {\n grassland: r.verdant[800],\n barren: r.sandstone[500],\n urban_area: r.ink[950],\n farmland: r.verdant[900],\n glacier: r.ink[700],\n scrub: r.verdant[900],\n forest: r.verdant[700],\n },\n};\n\n/**\n * `muted` / `light`. Fully achromatic — no hue anywhere, water included.\n *\n * Modelled on Mapbox Light and Protomaps `WHITE`: a compressed lightness band where land, water\n * and buildings sit within a few steps of each other, and the road network is the only thing that\n * really reads because it is drawn *brighter* than the land it cuts through. Everything a customer\n * puts on top is then the only saturated thing on screen, which is the entire job.\n *\n * Their label greys are not copied; see `graphite` in `palette.ts` for why.\n */\nconst MUTED_LIGHT: Recipe = {\n background: r.graphite[300],\n earth: r.graphite[50],\n water: r.graphite[200],\n parkA: r.graphite[25],\n parkB: r.graphite[50],\n woodA: r.graphite[25],\n woodB: r.graphite[50],\n scrubA: r.graphite[25],\n scrubB: r.graphite[50],\n sand: r.graphite[100],\n beach: r.graphite[100],\n glacier: r.graphite[25],\n institutional: r.graphite[100],\n pedestrian: r.graphite[25],\n aerodrome: r.graphite[100],\n runway: r.graphite[200],\n pier: r.graphite[200],\n buildings: r.graphite[100],\n railway: r.graphite[400],\n boundaries: r.graphite[500],\n roads: {\n other: r.graphite[25],\n otherCasing: r.graphite[200],\n minor: \"#FFFFFF\",\n minorCasing: r.graphite[200],\n service: r.graphite[25],\n serviceCasing: r.graphite[200],\n major: \"#FFFFFF\",\n majorCasing: r.graphite[300],\n highway: \"#FFFFFF\",\n highwayCasing: r.graphite[300],\n link: \"#FFFFFF\",\n linkCasing: r.graphite[300],\n },\n tunnelFill: r.graphite[100],\n tunnelCasing: r.graphite[200],\n bridgeCasing: r.graphite[300],\n labels: {\n city: r.graphite[1000],\n cityHalo: r.graphite[25],\n state: r.graphite[700],\n stateHalo: r.graphite[25],\n country: r.graphite[700],\n subplace: r.graphite[700],\n subplaceHalo: r.graphite[25],\n address: r.graphite[700],\n addressHalo: r.graphite[25],\n roadMinor: r.graphite[700],\n roadMinorHalo: r.graphite[25],\n roadMajor: r.graphite[800],\n roadMajorHalo: r.graphite[25],\n ocean: r.graphite[800],\n },\n\n pois: {\n blue: r.graphite[600],\n green: r.graphite[600],\n lapis: r.graphite[700],\n pink: r.graphite[600],\n red: r.graphite[700],\n slategray: r.graphite[700],\n tangerine: r.graphite[600],\n turquoise: r.graphite[600],\n },\n landcover: {\n grassland: r.graphite[50],\n barren: r.graphite[100],\n urban_area: r.graphite[100],\n farmland: r.graphite[50],\n glacier: r.graphite[25],\n scrub: r.graphite[50],\n forest: r.graphite[100],\n },\n};\n\n/**\n * `muted` / `dark`. The achromatic backdrop inverted, same discipline.\n *\n * With no hue available anywhere the coastline is a pure lightness step, so water sits below the\n * land rather than beside it, and the roads stay the brightest thing on the map exactly as they\n * are in the light mode. Road hierarchy therefore reads identically in both modes.\n */\nconst MUTED_DARK: Recipe = {\n background: r.graphite[1000],\n earth: r.graphite[900],\n water: r.graphite[1000],\n parkA: r.graphite[900],\n parkB: r.graphite[800],\n woodA: r.graphite[900],\n woodB: r.graphite[800],\n scrubA: r.graphite[900],\n scrubB: r.graphite[800],\n sand: r.graphite[800],\n beach: r.graphite[800],\n glacier: r.graphite[700],\n institutional: r.graphite[900],\n pedestrian: r.graphite[900],\n aerodrome: r.graphite[900],\n runway: r.graphite[800],\n pier: r.graphite[800],\n buildings: r.graphite[800],\n railway: r.graphite[700],\n boundaries: r.graphite[600],\n roads: {\n other: r.graphite[800],\n otherCasing: r.graphite[1000],\n minor: r.graphite[700],\n minorCasing: r.graphite[1000],\n service: r.graphite[800],\n serviceCasing: r.graphite[1000],\n major: r.graphite[600],\n majorCasing: r.graphite[1000],\n highway: r.graphite[500],\n highwayCasing: r.graphite[1000],\n link: r.graphite[600],\n linkCasing: r.graphite[1000],\n },\n tunnelFill: r.graphite[900],\n tunnelCasing: r.graphite[1000],\n bridgeCasing: r.graphite[1000],\n labels: {\n city: r.graphite[100],\n cityHalo: r.graphite[1000],\n state: r.graphite[500],\n stateHalo: r.graphite[1000],\n country: r.graphite[500],\n subplace: r.graphite[500],\n subplaceHalo: r.graphite[1000],\n address: r.graphite[500],\n addressHalo: r.graphite[1000],\n roadMinor: r.graphite[500],\n roadMinorHalo: r.graphite[1000],\n roadMajor: r.graphite[400],\n roadMajorHalo: r.graphite[1000],\n ocean: r.graphite[400],\n },\n\n pois: {\n blue: r.graphite[400],\n green: r.graphite[400],\n lapis: r.graphite[500],\n pink: r.graphite[400],\n red: r.graphite[500],\n slategray: r.graphite[500],\n tangerine: r.graphite[400],\n turquoise: r.graphite[400],\n },\n landcover: {\n grassland: r.graphite[900],\n barren: r.graphite[800],\n urban_area: r.graphite[900],\n farmland: r.graphite[900],\n glacier: r.graphite[700],\n scrub: r.graphite[900],\n forest: r.graphite[800],\n },\n};\n\n/**\n * `relief` / `light`. Terrain. Land sits a step lighter than `base` on purpose: a hillshade is\n * composited beneath the roads with a multiply blend, which only ever darkens, so the lift is the\n * headroom that shading spends. Rendered without a DEM it will look flat and slightly washed —\n * that is the tell that the terrain source is missing, not a palette bug. See `terrain.ts`.\n */\nconst RELIEF_LIGHT: Recipe = {\n background: r.ink[200],\n earth: r.ink[50],\n water: r.wave[300],\n parkA: r.verdant[200],\n parkB: r.verdant[300],\n woodA: r.verdant[200],\n woodB: r.verdant[300],\n scrubA: r.verdant[200],\n scrubB: r.verdant[300],\n sand: r.sandstone[200],\n beach: r.sandstone[200],\n glacier: r.ink[25],\n institutional: r.ink[25],\n pedestrian: r.ink[50],\n aerodrome: r.ink[50],\n runway: r.ink[200],\n pier: r.ink[300],\n buildings: r.ink[300],\n railway: r.ink[500],\n boundaries: r.ink[600],\n roads: {\n other: r.ink[50],\n otherCasing: r.ink[300],\n minor: r.ink[25],\n minorCasing: r.ink[300],\n service: r.ink[50],\n serviceCasing: r.ink[300],\n major: \"#FFFFFF\",\n majorCasing: r.ink[400],\n highway: \"#FFFFFF\",\n highwayCasing: r.ink[500],\n link: \"#FFFFFF\",\n linkCasing: r.ink[400],\n },\n tunnelFill: r.ink[200],\n tunnelCasing: r.ink[300],\n bridgeCasing: r.ink[500],\n labels: {\n city: r.ink[1000],\n cityHalo: r.ink[25],\n state: r.ink[700],\n stateHalo: r.ink[25],\n country: r.ink[700],\n subplace: r.ink[700],\n subplaceHalo: r.ink[25],\n address: r.ink[700],\n addressHalo: r.ink[25],\n roadMinor: r.ink[700],\n roadMinorHalo: r.ink[25],\n roadMajor: r.ink[800],\n roadMajorHalo: r.ink[25],\n ocean: r.wave[800],\n },\n\n pois: {\n blue: \"#2D6E8F\",\n green: r.verdant[700],\n lapis: \"#3F5C93\",\n pink: \"#8F4A6B\",\n red: \"#9B4340\",\n slategray: r.ink[700],\n tangerine: \"#8F5322\",\n turquoise: r.wave[700],\n },\n landcover: {\n grassland: r.verdant[200],\n barren: r.sandstone[200],\n urban_area: r.ink[50],\n farmland: r.verdant[100],\n glacier: r.ink[25],\n scrub: r.verdant[100],\n forest: r.verdant[300],\n },\n};\n\n/**\n * `relief` / `dark`. Terrain inverted. The lift goes the other way — land sits a step *darker*\n * than `base` dark, because on a dark map the hillshade highlight is what does the modelling and\n * it needs room above the land tone, not below it.\n */\nconst RELIEF_DARK: Recipe = {\n background: r.ink[1000],\n earth: r.ink[950],\n water: r.wave[980],\n parkA: r.verdant[800],\n parkB: r.verdant[700],\n woodA: r.verdant[800],\n woodB: r.verdant[700],\n scrubA: r.verdant[800],\n scrubB: r.verdant[700],\n sand: r.sandstone[500],\n beach: r.sandstone[500],\n glacier: r.ink[700],\n institutional: r.ink[1000],\n pedestrian: r.ink[950],\n aerodrome: r.ink[950],\n runway: r.ink[850],\n pier: r.ink[850],\n buildings: r.ink[900],\n railway: r.ink[700],\n boundaries: r.ink[600],\n roads: {\n other: r.ink[850],\n otherCasing: r.ink[1000],\n minor: r.ink[800],\n minorCasing: r.ink[1000],\n service: r.ink[850],\n serviceCasing: r.ink[1000],\n major: r.ink[700],\n majorCasing: r.ink[1000],\n highway: r.ink[600],\n highwayCasing: r.ink[1000],\n link: r.ink[700],\n linkCasing: r.ink[1000],\n },\n tunnelFill: r.ink[900],\n tunnelCasing: r.ink[1000],\n bridgeCasing: r.ink[1000],\n labels: {\n city: r.ink[100],\n cityHalo: r.ink[1000],\n state: r.ink[500],\n stateHalo: r.ink[1000],\n country: r.ink[500],\n subplace: r.ink[500],\n subplaceHalo: r.ink[1000],\n address: r.ink[500],\n addressHalo: r.ink[1000],\n roadMinor: r.ink[500],\n roadMinorHalo: r.ink[1000],\n roadMajor: r.ink[400],\n roadMajorHalo: r.ink[1000],\n ocean: r.wave[400],\n },\n\n pois: {\n blue: \"#7FC4E8\",\n green: r.verdant[400],\n lapis: \"#8FB0EA\",\n pink: \"#E3A0C0\",\n red: \"#EE968F\",\n slategray: r.ink[500],\n tangerine: \"#E8AC7C\",\n turquoise: r.wave[400],\n },\n landcover: {\n grassland: r.verdant[800],\n barren: r.sandstone[500],\n urban_area: r.ink[950],\n farmland: r.verdant[900],\n glacier: r.ink[700],\n scrub: r.verdant[900],\n forest: r.verdant[700],\n },\n};\n\n/**\n * `street` / `light`. The full-colour map, the one that reads as a map with nothing on it.\n * Warmer landcover, stronger vegetation, and a motorway that carries an orange fill.\n *\n * That orange is the one warm note left from the old `ember` brand ramp, and it survives on\n * cartographic grounds rather than brand ones: orange motorways is long-standing convention, so\n * it lands where the eye already looks. It is not the brand accent — magenta is, and magenta\n * stays out of the basemap entirely so customer data always owns it.\n */\nconst STREET_LIGHT: Recipe = {\n background: r.ink[300],\n earth: r.sandstone[100],\n water: r.wave[400],\n parkA: r.verdant[200],\n parkB: r.verdant[400],\n woodA: r.verdant[200],\n woodB: r.verdant[400],\n scrubA: r.verdant[200],\n scrubB: r.verdant[400],\n sand: r.sandstone[300],\n beach: r.sandstone[300],\n glacier: r.ink[25],\n institutional: r.sandstone[200],\n pedestrian: r.ink[50],\n aerodrome: r.ink[50],\n runway: r.ink[200],\n pier: r.ink[300],\n buildings: r.ink[400],\n railway: r.ink[500],\n boundaries: r.ink[600],\n roads: {\n other: r.ink[50],\n otherCasing: r.ink[300],\n minor: r.ink[25],\n minorCasing: r.ink[300],\n service: r.ink[50],\n serviceCasing: r.ink[300],\n major: \"#FFFFFF\",\n majorCasing: r.ink[400],\n highway: r.ember[400],\n highwayCasing: r.ink[500],\n link: \"#FFFFFF\",\n linkCasing: r.ink[400],\n },\n tunnelFill: r.ink[200],\n tunnelCasing: r.ink[300],\n bridgeCasing: r.ink[500],\n labels: {\n city: r.ink[1000],\n cityHalo: r.ink[25],\n state: r.ink[700],\n stateHalo: r.ink[25],\n country: r.ink[700],\n subplace: r.ink[700],\n subplaceHalo: r.ink[25],\n address: r.ink[700],\n addressHalo: r.ink[25],\n roadMinor: r.ink[700],\n roadMinorHalo: r.ink[25],\n roadMajor: r.ink[800],\n roadMajorHalo: r.ink[25],\n ocean: r.wave[800],\n },\n\n pois: {\n blue: \"#2D6E8F\",\n green: r.verdant[700],\n lapis: \"#3F5C93\",\n pink: \"#8F4A6B\",\n red: \"#9B4340\",\n slategray: r.ink[700],\n tangerine: \"#8F5322\",\n turquoise: r.wave[700],\n },\n landcover: {\n grassland: r.verdant[300],\n barren: r.sandstone[300],\n urban_area: r.ink[100],\n farmland: r.sandstone[200],\n glacier: r.ink[25],\n scrub: r.verdant[200],\n forest: r.verdant[400],\n },\n};\n\n/**\n * `street` / `dark`. The full-colour map at night. Landcover keeps its hue rather than\n * collapsing to grey, which is what separates this from `base` dark, and the motorway keeps the\n * same orange so the road hierarchy reads identically in both modes.\n */\nconst STREET_DARK: Recipe = {\n background: r.ink[1000],\n earth: r.ink[900],\n water: r.wave[950],\n parkA: r.verdant[800],\n parkB: r.verdant[700],\n woodA: r.verdant[800],\n woodB: r.verdant[700],\n scrubA: r.verdant[800],\n scrubB: r.verdant[700],\n sand: r.sandstone[500],\n beach: r.sandstone[500],\n glacier: r.ink[700],\n institutional: r.ink[850],\n pedestrian: r.ink[950],\n aerodrome: r.ink[950],\n runway: r.ink[850],\n pier: r.ink[850],\n buildings: r.ink[800],\n railway: r.ink[700],\n boundaries: r.ink[600],\n roads: {\n other: r.ink[850],\n otherCasing: r.ink[1000],\n minor: r.ink[800],\n minorCasing: r.ink[1000],\n service: r.ink[850],\n serviceCasing: r.ink[1000],\n major: r.ink[700],\n majorCasing: r.ink[1000],\n highway: r.ember[600],\n highwayCasing: r.ink[1000],\n link: r.ink[700],\n linkCasing: r.ink[1000],\n },\n tunnelFill: r.ink[900],\n tunnelCasing: r.ink[1000],\n bridgeCasing: r.ink[1000],\n labels: {\n city: r.ink[100],\n cityHalo: r.ink[1000],\n state: r.ink[500],\n stateHalo: r.ink[1000],\n country: r.ink[500],\n subplace: r.ink[500],\n subplaceHalo: r.ink[1000],\n address: r.ink[500],\n addressHalo: r.ink[1000],\n roadMinor: r.ink[500],\n roadMinorHalo: r.ink[1000],\n roadMajor: r.ink[400],\n roadMajorHalo: r.ink[1000],\n ocean: r.wave[400],\n },\n\n pois: {\n blue: \"#7FC4E8\",\n green: r.verdant[400],\n lapis: \"#8FB0EA\",\n pink: \"#E3A0C0\",\n red: \"#EE968F\",\n slategray: r.ink[500],\n tangerine: \"#E8AC7C\",\n turquoise: r.wave[400],\n },\n landcover: {\n grassland: r.verdant[700],\n barren: r.sandstone[500],\n urban_area: r.ink[850],\n farmland: r.verdant[800],\n glacier: r.ink[700],\n scrub: r.verdant[800],\n forest: r.verdant[700],\n },\n};\n\n/**\n * `outdoor` / `light`. Terrain-first scenic: the map you use to look at ground rather than to\n * find an address.\n *\n * It starts from `relief` — same lifted land, because it composites the same hillshade and needs\n * the same headroom — and diverges on exactly three axes. Anything else it shares with `relief`\n * is shared on purpose, not by omission.\n *\n * **Landcover stops receding.** Every other flavour keeps ground cover near-neutral so a\n * customer's data wins. Here the ground cover *is* the content, so forest, scrub and grassland\n * separate across `verdant` instead of collapsing into one field.\n *\n * **Protected land reads as protected.** `park` steps a tone deeper than generic vegetation, so a\n * national park is distinguishable from the golf course that `landuse_park` files beside it.\n *\n * **Roads recede one step**, via their casings rather than their fills: a lighter casing on a\n * white road keeps the shape legible while surrendering the contrast fight to the terrain.\n * Labels and halos are untouched from `relief`, which is what keeps the enforced contrast floors\n * satisfied — the ramps are solved against those, and re-deriving them for one flavour would be\n * re-solving a problem that is already solved.\n */\nconst OUTDOOR_LIGHT: Recipe = {\n background: r.ink[200],\n earth: r.ink[50],\n water: r.wave[300],\n parkA: r.verdant[300],\n parkB: r.verdant[400],\n woodA: r.verdant[300],\n woodB: r.verdant[400],\n scrubA: r.verdant[200],\n scrubB: r.verdant[300],\n sand: r.sandstone[300],\n beach: r.sandstone[300],\n glacier: r.ink[25],\n institutional: r.ink[25],\n pedestrian: r.ink[50],\n aerodrome: r.ink[50],\n runway: r.ink[200],\n pier: r.ink[300],\n // A step lighter than `relief`: outdoors, the building footprint is context, not content.\n buildings: r.ink[200],\n railway: r.ink[500],\n boundaries: r.ink[600],\n roads: {\n other: r.ink[50],\n otherCasing: r.ink[200],\n minor: r.ink[25],\n minorCasing: r.ink[200],\n service: r.ink[50],\n serviceCasing: r.ink[200],\n major: \"#FFFFFF\",\n majorCasing: r.ink[300],\n highway: \"#FFFFFF\",\n highwayCasing: r.ink[400],\n link: \"#FFFFFF\",\n linkCasing: r.ink[300],\n },\n tunnelFill: r.ink[200],\n tunnelCasing: r.ink[300],\n bridgeCasing: r.ink[400],\n labels: {\n city: r.ink[1000],\n cityHalo: r.ink[25],\n state: r.ink[700],\n stateHalo: r.ink[25],\n country: r.ink[700],\n subplace: r.ink[700],\n subplaceHalo: r.ink[25],\n address: r.ink[700],\n addressHalo: r.ink[25],\n roadMinor: r.ink[700],\n roadMinorHalo: r.ink[25],\n roadMajor: r.ink[800],\n roadMajorHalo: r.ink[25],\n ocean: r.wave[800],\n },\n\n pois: {\n blue: \"#2D6E8F\",\n // Peaks, parks, forests and gardens all come through green. On this flavour they are the\n // POIs worth finding, so it carries a full step more weight than elsewhere.\n green: r.verdant[800],\n lapis: \"#3F5C93\",\n pink: \"#8F4A6B\",\n red: \"#9B4340\",\n slategray: r.ink[700],\n tangerine: \"#8F5322\",\n turquoise: r.wave[700],\n },\n landcover: {\n grassland: r.verdant[200],\n barren: r.sandstone[300],\n urban_area: r.ink[100],\n farmland: r.sandstone[200],\n glacier: r.ink[25],\n scrub: r.verdant[300],\n forest: r.verdant[400],\n },\n};\n\n/**\n * `outdoor` / `dark`. The same three divergences, inverted the way `relief` dark inverts: the\n * land sits darker to leave room *above* it for a hillshade highlight to do the modelling.\n *\n * Vegetation lifts rather than deepens here. On a dark basemap a deeper green is indistinguishable\n * from the land it sits on, so the separation that `light` gets by going darker, `dark` gets by\n * going lighter — the same intent through the opposite move.\n */\nconst OUTDOOR_DARK: Recipe = {\n background: r.ink[1000],\n earth: r.ink[950],\n water: r.wave[980],\n parkA: r.verdant[700],\n parkB: r.verdant[600],\n woodA: r.verdant[700],\n woodB: r.verdant[600],\n scrubA: r.verdant[800],\n scrubB: r.verdant[700],\n sand: r.sandstone[500],\n beach: r.sandstone[500],\n glacier: r.ink[700],\n institutional: r.ink[1000],\n pedestrian: r.ink[950],\n aerodrome: r.ink[950],\n runway: r.ink[850],\n pier: r.ink[850],\n buildings: r.ink[900],\n railway: r.ink[700],\n boundaries: r.ink[600],\n roads: {\n // The minor tier recedes toward `earth`; majors and highways hold their `relief` values,\n // because a road you cannot see is a different failure from a road that is merely quiet.\n other: r.ink[900],\n otherCasing: r.ink[1000],\n minor: r.ink[850],\n minorCasing: r.ink[1000],\n service: r.ink[900],\n serviceCasing: r.ink[1000],\n major: r.ink[700],\n majorCasing: r.ink[1000],\n highway: r.ink[600],\n highwayCasing: r.ink[1000],\n link: r.ink[700],\n linkCasing: r.ink[1000],\n },\n tunnelFill: r.ink[900],\n tunnelCasing: r.ink[1000],\n bridgeCasing: r.ink[1000],\n labels: {\n city: r.ink[100],\n cityHalo: r.ink[1000],\n state: r.ink[500],\n stateHalo: r.ink[1000],\n country: r.ink[500],\n subplace: r.ink[500],\n subplaceHalo: r.ink[1000],\n address: r.ink[500],\n addressHalo: r.ink[1000],\n roadMinor: r.ink[500],\n roadMinorHalo: r.ink[1000],\n roadMajor: r.ink[400],\n roadMajorHalo: r.ink[1000],\n ocean: r.wave[400],\n },\n\n pois: {\n blue: \"#7FC4E8\",\n green: r.verdant[300],\n lapis: \"#8FB0EA\",\n pink: \"#E3A0C0\",\n red: \"#EE968F\",\n slategray: r.ink[500],\n tangerine: \"#E8AC7C\",\n turquoise: r.wave[400],\n },\n landcover: {\n grassland: r.verdant[700],\n barren: r.sandstone[500],\n urban_area: r.ink[950],\n farmland: r.verdant[900],\n glacier: r.ink[700],\n scrub: r.verdant[800],\n forest: r.verdant[600],\n },\n};\n\n\n return {\n base: { light: BASE_LIGHT, dark: BASE_DARK },\n muted: { light: MUTED_LIGHT, dark: MUTED_DARK },\n relief: { light: RELIEF_LIGHT, dark: RELIEF_DARK },\n street: { light: STREET_LIGHT, dark: STREET_DARK },\n outdoor: { light: OUTDOOR_LIGHT, dark: OUTDOOR_DARK },\n };\n}\n\nexport const RECIPES: Record<ThemeBase, Record<ThemeMode, Recipe>> = buildRecipes(STOCK_RAMPS);\n","import { THEME_BASES } from \"./recipe\";\nimport { RECIPES } from \"./recipes\";\nimport type { ThemeDoc } from \"./doc\";\n\n/**\n * Validation failure. `detail` lists every bad path in one throw — collect-then-throw, so a\n * builder user fixing a hand-edited document sees all of it at once rather than one field per\n * round trip (the same reporting philosophy as the cartography contrast tests).\n */\nexport class ThemeError extends Error {\n readonly detail: string[];\n constructor(message: string, detail: string[]) {\n super(message);\n this.name = \"ThemeError\";\n this.detail = detail;\n }\n}\n\n/** 6- or 8-digit hex only. Hex-by-grammar is what makes \"no URLs, no expressions\" a property. */\nconst HEX = /^#[0-9a-fA-F]{6}([0-9a-fA-F]{2})?$/;\n\nconst MAX_NAME_LENGTH = 40;\n\n/** [min, max] bounds per numeric field. */\nconst MARKER_BOUNDS: Record<string, readonly [number, number]> = {\n scale: [0.5, 2],\n};\nconst ROUTE_BOUNDS: Record<string, readonly [number, number]> = {\n width: [1, 12],\n opacity: [0, 1],\n casingWidth: [0, 24],\n casingOpacity: [0, 1],\n};\n\nconst isRecord = (v: unknown): v is Record<string, unknown> =>\n typeof v === \"object\" && v !== null && !Array.isArray(v);\n\n/**\n * Validate a basemap override object against the Recipe shape, using a real recipe as the\n * schema: a key is legal iff it exists on the reference, objects recurse, strings must be hex.\n * The data is the schema, so the validator can never drift from what `mergeRecipe` accepts.\n */\nfunction walkBasemap(value: unknown, reference: unknown, path: string, errors: string[]): void {\n if (!isRecord(value)) {\n errors.push(`${path}: must be an object`);\n return;\n }\n const ref = reference as Record<string, unknown>;\n for (const [key, v] of Object.entries(value)) {\n const target = ref[key];\n const p = `${path}.${key}`;\n if (target === undefined) {\n errors.push(`${p}: unknown field`);\n } else if (typeof target === \"string\") {\n if (typeof v !== \"string\" || !HEX.test(v)) {\n errors.push(`${p}: must be a hex colour (#RRGGBB or #RRGGBBAA)`);\n }\n } else {\n walkBasemap(v, target, p, errors);\n }\n }\n}\n\n/** Validate a flat colour+number leaf object (marker/route) against a bounds table. */\nfunction walkLeaf(\n value: unknown,\n colorKeys: readonly string[],\n bounds: Record<string, readonly [number, number]>,\n path: string,\n errors: string[],\n): void {\n if (!isRecord(value)) {\n errors.push(`${path}: must be an object`);\n return;\n }\n for (const [key, v] of Object.entries(value)) {\n const p = `${path}.${key}`;\n if (colorKeys.includes(key)) {\n if (typeof v !== \"string\" || !HEX.test(v)) {\n errors.push(`${p}: must be a hex colour (#RRGGBB or #RRGGBBAA)`);\n }\n } else if (key in bounds) {\n const [lo, hi] = bounds[key]!;\n if (typeof v !== \"number\" || !Number.isFinite(v) || v < lo || v > hi) {\n errors.push(`${p}: out of bounds (${lo}–${hi})`);\n }\n } else {\n errors.push(`${p}: unknown field`);\n }\n }\n}\n\nconst HALF_KEYS = [\"basemap\", \"marker\", \"route\"] as const;\nconst DOC_KEYS = [\"v\", \"name\", \"base\", \"seeds\", \"light\", \"dark\"] as const;\nconst SEED_COLOR_KEYS = [\"land\", \"water\", \"nature\", \"accent\"] as const;\nconst REQUIRED_SEED_KEYS = [\"land\", \"water\", \"nature\"] as const;\n\n/**\n * Validate an untrusted value as a ThemeDoc. Returns the (unchanged) document on success;\n * throws a `ThemeError` naming every invalid path otherwise. Unknown fields anywhere are\n * errors — a theme is data only, and the reject-unknown posture is what keeps it that way.\n */\nexport function validateTheme(input: unknown): ThemeDoc {\n const errors: string[] = [];\n if (!isRecord(input)) {\n throw new ThemeError(\"invalid theme\", [\"theme must be a JSON object\"]);\n }\n\n for (const key of Object.keys(input)) {\n if (!(DOC_KEYS as readonly string[]).includes(key)) errors.push(`${key}: unknown field`);\n }\n\n if (input.v !== 1) errors.push(\"v: must be 1\");\n if (typeof input.base !== \"string\" || !(THEME_BASES as readonly string[]).includes(input.base)) {\n errors.push(`base: must be one of ${THEME_BASES.join(\", \")}`);\n }\n if (input.name !== undefined) {\n if (typeof input.name !== \"string\" || input.name.length > MAX_NAME_LENGTH) {\n errors.push(`name: must be a string of at most ${MAX_NAME_LENGTH} characters`);\n }\n }\n\n if (input.seeds !== undefined) {\n walkLeaf(input.seeds, SEED_COLOR_KEYS, {}, \"seeds\", errors);\n if (isRecord(input.seeds)) {\n for (const key of REQUIRED_SEED_KEYS) {\n if (input.seeds[key] === undefined) errors.push(`seeds.${key}: required`);\n }\n }\n }\n\n // Any complete recipe works as the schema reference; base.light is as good as any.\n const reference = RECIPES.base.light;\n\n for (const mode of [\"light\", \"dark\"] as const) {\n const half = input[mode];\n if (half === undefined) continue;\n if (!isRecord(half)) {\n errors.push(`${mode}: must be an object`);\n continue;\n }\n for (const key of Object.keys(half)) {\n if (!(HALF_KEYS as readonly string[]).includes(key)) {\n errors.push(`${mode}.${key}: unknown field`);\n }\n }\n if (half.basemap !== undefined) walkBasemap(half.basemap, reference, `${mode}.basemap`, errors);\n if (half.marker !== undefined) {\n walkLeaf(half.marker, [\"color\"], MARKER_BOUNDS, `${mode}.marker`, errors);\n }\n if (half.route !== undefined) {\n walkLeaf(half.route, [\"color\", \"casingColor\"], ROUTE_BOUNDS, `${mode}.route`, errors);\n }\n }\n\n if (errors.length > 0) throw new ThemeError(\"invalid theme\", errors);\n return input as unknown as ThemeDoc;\n}\n","import { ThemeError, validateTheme } from \"./validate\";\nimport type { ThemeDoc } from \"./doc\";\n\n/**\n * The compact theme code: `ut1.` + base64url(deflate(minified JSON)).\n *\n * Web-standard streams only (CompressionStream/DecompressionStream, Blob, btoa/atob) so the\n * same module runs in Workers, browsers and Node 18+. `deflate` (zlib) rather than\n * `deflate-raw`, which Node 20 — the repo floor — does not implement; the wrapper costs six\n * bytes and buys a checksum.\n *\n * `ut1` is the wire version. Bump it only for a breaking change, and keep decoding old\n * prefixes forever: codes get hardcoded into customers' pages.\n */\n\nexport const THEME_CODE_PREFIX = \"ut1.\";\nexport const MAX_CODE_LENGTH = 4096;\nconst MAX_JSON_BYTES = 16 * 1024;\n\n/** Drain a stream into one buffer, refusing to grow past `cap` (the zip-bomb guard). */\nasync function pump(stream: ReadableStream<Uint8Array>, cap: number): Promise<Uint8Array> {\n const reader = stream.getReader();\n const chunks: Uint8Array[] = [];\n let size = 0;\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n size += value.byteLength;\n if (size > cap) {\n // Cancelling releases the underlying decompressor before we throw.\n await reader.cancel().catch(() => {});\n throw new ThemeError(\"invalid theme\", [\"theme document too large\"]);\n }\n chunks.push(value);\n }\n const out = new Uint8Array(size);\n let off = 0;\n for (const c of chunks) {\n out.set(c, off);\n off += c.byteLength;\n }\n return out;\n}\n\nconst toB64url = (b: Uint8Array): string => {\n let bin = \"\";\n // Chunked: String.fromCharCode(...whole) overflows the argument limit on large arrays.\n for (let i = 0; i < b.length; i += 0x8000) {\n bin += String.fromCharCode(...b.subarray(i, i + 0x8000));\n }\n return btoa(bin).replaceAll(\"+\", \"-\").replaceAll(\"/\", \"_\").replace(/=+$/, \"\");\n};\n\nconst fromB64url = (s: string): Uint8Array => {\n const bin = atob(s.replaceAll(\"-\", \"+\").replaceAll(\"_\", \"/\"));\n return Uint8Array.from(bin, (c) => c.charCodeAt(0));\n};\n\nasync function through(\n bytes: Uint8Array,\n transform: CompressionStream | DecompressionStream,\n cap: number,\n): Promise<Uint8Array> {\n const stream = new Blob([bytes as BlobPart]).stream().pipeThrough(transform);\n return pump(stream, cap);\n}\n\n/** Validate and encode a theme document to its compact `ut1.` code. Throws `ThemeError`. */\nexport async function encodeTheme(doc: ThemeDoc): Promise<string> {\n const valid = validateTheme(doc);\n const json = new TextEncoder().encode(JSON.stringify(valid));\n const packed = await through(json, new CompressionStream(\"deflate\"), Number.POSITIVE_INFINITY);\n const code = THEME_CODE_PREFIX + toB64url(packed);\n if (code.length > MAX_CODE_LENGTH) {\n throw new ThemeError(\"invalid theme\", [\n `encoded theme exceeds ${MAX_CODE_LENGTH} characters`,\n ]);\n }\n return code;\n}\n\n/** Decode and validate a compact `ut1.` code. Every failure lands as `ThemeError`. */\nexport async function decodeTheme(code: string): Promise<ThemeDoc> {\n if (code.length > MAX_CODE_LENGTH) {\n throw new ThemeError(\"invalid theme\", [`code exceeds ${MAX_CODE_LENGTH} characters`]);\n }\n if (!code.startsWith(THEME_CODE_PREFIX)) {\n throw new ThemeError(\"invalid theme\", [`code must start with \"${THEME_CODE_PREFIX}\"`]);\n }\n let bytes: Uint8Array;\n try {\n const packed = fromB64url(code.slice(THEME_CODE_PREFIX.length));\n bytes = await through(packed, new DecompressionStream(\"deflate\"), MAX_JSON_BYTES);\n } catch (e) {\n if (e instanceof ThemeError) throw e;\n throw new ThemeError(\"invalid theme\", [\"code is not valid base64url deflate data\"]);\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(new TextDecoder().decode(bytes));\n } catch {\n throw new ThemeError(\"invalid theme\", [\"decoded payload is not JSON\"]);\n }\n return validateTheme(parsed);\n}\n","import type { Flavor } from \"@protomaps/basemaps\";\nimport { makeFlavor, type Recipe, type ThemeBase, type ThemeMode } from \"./recipe\";\nimport { RECIPES } from \"./recipes\";\nimport type { BasemapOverrides, MarkerTheme, RouteTheme, ThemeDoc } from \"./doc\";\n\n/**\n * Platform drawing defaults for the two client-side overlays a theme styles. These are exactly\n * the convention the unmap.dev hero has always drawn: a magenta pin, and a route as a solid\n * line over a wide translucent casing so it stays legible on light and dark cartography alike.\n */\nexport const DEFAULT_MARKER: Required<MarkerTheme> = { color: \"#FF3E9A\", scale: 1 };\nexport const DEFAULT_ROUTE: Required<RouteTheme> = {\n color: \"#FF3E9A\",\n width: 3,\n opacity: 1,\n casingColor: \"#FF3E9A\",\n casingWidth: 10,\n casingOpacity: 0.2,\n};\n\nexport interface ResolvedTheme {\n /** `<base>-<mode>`, the chassis name — what selects sprites and terrain behaviour. */\n flavorName: `${ThemeBase}-${ThemeMode}`;\n flavor: Flavor;\n marker: Required<MarkerTheme>;\n route: Required<RouteTheme>;\n}\n\n/**\n * Merge sparse overrides onto a base recipe, walking the base's own shape. Composing from the\n * base's keys (never spreading the override object) means an unexpected key cannot ride along\n * even if a caller skipped validation — defence in depth behind `validateTheme`.\n */\nexport function mergeRecipe(base: Recipe, overrides?: BasemapOverrides): Recipe {\n if (!overrides) return structuredClone(base);\n const walk = (ref: Record<string, unknown>, over: Record<string, unknown>) => {\n const out: Record<string, unknown> = {};\n for (const [key, refValue] of Object.entries(ref)) {\n const o = over[key];\n if (refValue !== null && typeof refValue === \"object\") {\n out[key] =\n o !== null && typeof o === \"object\" && !Array.isArray(o)\n ? walk(refValue as Record<string, unknown>, o as Record<string, unknown>)\n : structuredClone(refValue);\n } else {\n out[key] = typeof o === \"string\" ? o : refValue;\n }\n }\n return out;\n };\n return walk(\n base as unknown as Record<string, unknown>,\n overrides as Record<string, unknown>,\n ) as unknown as Recipe;\n}\n\n/**\n * Resolve one half of a theme into everything a renderer needs: the expanded Flavor, the\n * chassis name, and marker/route styles with defaults filled in.\n */\nexport function resolveTheme(doc: ThemeDoc, mode: ThemeMode): ResolvedTheme {\n const half = doc[mode] ?? {};\n const recipe = mergeRecipe(RECIPES[doc.base][mode], half.basemap);\n return {\n flavorName: `${doc.base}-${mode}`,\n flavor: makeFlavor(recipe),\n marker: { ...DEFAULT_MARKER, ...half.marker },\n route: { ...DEFAULT_ROUTE, ...half.route },\n };\n}\n","import type { Flavor } from \"@protomaps/basemaps\";\nimport { MODES, type ThemeMode } from \"./recipe\";\nimport type { ThemeDoc } from \"./doc\";\nimport { resolveTheme } from \"./compose\";\n\n/**\n * Label-contrast checks for theme documents — the same WCAG maths and label/background pairs\n * `apps/gateway/test/cartography.test.ts` enforces on unmap's own flavors, exported as a\n * library so the builder can warn live.\n *\n * Warn, not reject: the gateway holds its own flavors to these floors, but a custom theme is\n * the customer's canvas. The builder surfaces every breach; shipping one anyway is a choice.\n */\n\nfunction parseHex(hex: string): [number, number, number] {\n const h = hex.replace(\"#\", \"\");\n return [\n parseInt(h.slice(0, 2), 16),\n parseInt(h.slice(2, 4), 16),\n parseInt(h.slice(4, 6), 16),\n ];\n}\n\nfunction luminance(hex: string): number {\n const toLinear = (v: number) => {\n const c = v / 255;\n return c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;\n };\n const [r, g, b] = parseHex(hex);\n return 0.2126 * toLinear(r) + 0.7152 * toLinear(g) + 0.0722 * toLinear(b);\n}\n\n/** WCAG contrast ratio between two hex colours (1–21). */\nexport function contrast(a: string, b: string): number {\n const la = luminance(a);\n const lb = luminance(b);\n const [hi, lo] = la > lb ? [la, lb] : [lb, la];\n return (hi + 0.05) / (lo + 0.05);\n}\n\n/**\n * Halo colour is the effective background wherever a halo is set, because that is what the\n * glyph actually sits on. Where there is no halo slot (country labels), the label sits on the\n * land; ocean labels sit on water.\n */\nconst PRIMARY: Array<[keyof Flavor, keyof Flavor]> = [\n [\"city_label\", \"city_label_halo\"],\n [\"state_label\", \"state_label_halo\"],\n [\"country_label\", \"earth\"],\n [\"roads_label_major\", \"roads_label_major_halo\"],\n];\n\nconst SECONDARY: Array<[keyof Flavor, keyof Flavor]> = [\n [\"subplace_label\", \"subplace_label_halo\"],\n [\"address_label\", \"address_label_halo\"],\n [\"roads_label_minor\", \"roads_label_minor_halo\"],\n [\"ocean_label\", \"water\"],\n];\n\n/** Every enforced pair with its floor — the generator's contrast-clamp iterates these. */\nexport const LABEL_PAIRS: Array<[keyof Flavor, keyof Flavor, number]> = [\n ...PRIMARY.map(([l, b]) => [l, b, 4.5] as [keyof Flavor, keyof Flavor, number]),\n ...SECONDARY.map(([l, b]) => [l, b, 3] as [keyof Flavor, keyof Flavor, number]),\n];\n\nexport interface ContrastWarning {\n mode: ThemeMode;\n /** The Flavor label slot that breaches, e.g. \"city_label\". */\n label: string;\n /** The Flavor slot it was checked against, e.g. \"city_label_halo\". */\n background: string;\n ratio: number;\n /** 4.5 for primary labels, 3 for secondary. */\n floor: number;\n}\n\n/** Every label-contrast breach in the theme, across both modes. Empty means clean. */\nexport function contrastWarnings(doc: ThemeDoc): ContrastWarning[] {\n const warnings: ContrastWarning[] = [];\n for (const mode of MODES) {\n const flavor = resolveTheme(doc, mode).flavor as unknown as Record<string, string>;\n const check = (pairs: Array<[keyof Flavor, keyof Flavor]>, floor: number) => {\n for (const [label, background] of pairs) {\n const ratio = contrast(flavor[label as string]!, flavor[background as string]!);\n if (ratio < floor) {\n warnings.push({ mode, label: String(label), background: String(background), ratio, floor });\n }\n }\n };\n check(PRIMARY, 4.5);\n check(SECONDARY, 3);\n }\n return warnings;\n}\n","import type { ThemeDoc } from \"./doc\";\nimport type { ThemeBase } from \"./recipe\";\n\n/**\n * The shipped styles as starting-point themes: zero overrides, so each is guaranteed identical\n * to its `flavor=` twin (asserted in the gateway theme tests). The builder opens on these.\n */\nexport const PRESET_THEMES: Record<ThemeBase, ThemeDoc> = {\n base: { v: 1, name: \"ink\", base: \"base\" },\n muted: { v: 1, name: \"graphite\", base: \"muted\" },\n relief: { v: 1, name: \"relief\", base: \"relief\" },\n street: { v: 1, name: \"street\", base: \"street\" },\n outdoor: { v: 1, name: \"outdoor\", base: \"outdoor\" },\n};\n","/**\n * Minimal sRGB ↔ OKLCH conversion (Björn Ottosson's OKLab constants), plus a chroma-reducing\n * gamut map. Zero dependencies — the generator is the only consumer and needs exactly this.\n *\n * OKLCH is the working space for the same reason the hand-built ramps in `palette.ts` were\n * generated in it: perceived lightness is carried almost entirely by L, so a generator can swap\n * hue and chroma while *preserving a ramp's lightness ladder* — which is where the label\n * contrast the cartography tests enforce actually lives.\n */\n\nexport interface Oklch {\n /** Perceptual lightness, 0–1. */\n l: number;\n /** Chroma, 0 upward (~0.37 max for sRGB). */\n c: number;\n /** Hue in degrees, 0–360. */\n h: number;\n}\n\nconst srgbToLinear = (v: number) => (v <= 0.04045 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4);\nconst linearToSrgb = (v: number) =>\n v <= 0.0031308 ? 12.92 * v : 1.055 * v ** (1 / 2.4) - 0.055;\n\nfunction hexToRgb(hex: string): [number, number, number] {\n const h = hex.replace(\"#\", \"\");\n return [\n parseInt(h.slice(0, 2), 16) / 255,\n parseInt(h.slice(2, 4), 16) / 255,\n parseInt(h.slice(4, 6), 16) / 255,\n ];\n}\n\n/** Parse #RRGGBB (or #RRGGBBAA — alpha ignored) into OKLCH. */\nexport function hexToOklch(hex: string): Oklch {\n const [r, g, b] = hexToRgb(hex).map(srgbToLinear) as [number, number, number];\n const l = Math.cbrt(0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b);\n const m = Math.cbrt(0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b);\n const s = Math.cbrt(0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b);\n const L = 0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s;\n const a = 1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s;\n const bb = 0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s;\n const c = Math.hypot(a, bb);\n let h = (Math.atan2(bb, a) * 180) / Math.PI;\n if (h < 0) h += 360;\n return { l: L, c, h };\n}\n\n/** OKLCH → linear sRGB triple (possibly out of gamut). */\nfunction oklchToLinear({ l: L, c, h }: Oklch): [number, number, number] {\n const hr = (h * Math.PI) / 180;\n const a = c * Math.cos(hr);\n const bb = c * Math.sin(hr);\n const l = (L + 0.3963377774 * a + 0.2158037573 * bb) ** 3;\n const m = (L - 0.1055613458 * a - 0.0638541728 * bb) ** 3;\n const s = (L - 0.0894841775 * a - 1.291485548 * bb) ** 3;\n return [\n 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s,\n -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s,\n -0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s,\n ];\n}\n\nconst inGamut = (rgb: [number, number, number]) =>\n rgb.every((v) => v >= -1e-6 && v <= 1 + 1e-6);\n\n/**\n * OKLCH → #RRGGBB. Out-of-gamut colours are mapped by *reducing chroma* at constant L and h\n * (bisection), never by clipping channels — clipping shifts perceived lightness, and the whole\n * generator contract is that L is preserved.\n */\nexport function oklchToHex(color: Oklch): string {\n let { c } = color;\n let rgb = oklchToLinear({ ...color, c });\n if (!inGamut(rgb)) {\n let lo = 0;\n let hi = c;\n for (let i = 0; i < 24; i++) {\n c = (lo + hi) / 2;\n rgb = oklchToLinear({ ...color, c });\n if (inGamut(rgb)) lo = c;\n else hi = c;\n }\n rgb = oklchToLinear({ ...color, c: lo });\n }\n const to255 = (v: number) => Math.round(Math.min(1, Math.max(0, linearToSrgb(v))) * 255);\n return (\n \"#\" +\n rgb\n .map((v) => to255(v).toString(16).padStart(2, \"0\"))\n .join(\"\")\n .toUpperCase()\n );\n}\n","import { hexToOklch, oklchToHex } from \"./oklch\";\nimport { buildRecipes, RECIPES, STOCK_RAMPS, type RampSet } from \"./recipes\";\nimport { makeFlavor, MODES, type Recipe, type ThemeBase } from \"./recipe\";\nimport type { BasemapOverrides, ThemeDoc, ThemeSeeds } from \"./doc\";\nimport { contrast, LABEL_PAIRS } from \"./contrast\";\n\n/**\n * The simple-mode generator: three seed colours in, a full light + dark theme out.\n *\n * The trick is the one the hand-built ramps were made with. Each stock ramp is a *lightness\n * ladder* — its steps were solved so the label-contrast floors hold — and hue/chroma merely\n * carry identity. So the generator keeps every step's OKLCH lightness exactly, swaps in the\n * seed's hue, scales chroma to the seed's vividness, and rebuilds the recipes through the same\n * `buildRecipes` factory the shipped cartography uses. Casing/tunnel/bridge coherence and the\n * figure/ground relationships come along for free; the seeds only ever recolour.\n *\n * The output is a plain, valid ThemeDoc (sparse overrides + the seeds themselves), so nothing\n * downstream — codec, gateway, SDK — knows generation exists.\n */\n\n/** Neutrals must stay a cast, not a colour, or the whole map shouts. */\nconst NEUTRAL_CHROMA_CAP = 0.045;\n/** `muted` exists to vanish under data; its cast cap is a whisper of the normal one. */\nconst MUTED_CHROMA_CAP = 0.012;\n/** Ceiling for chromatic families (water, vegetation) before gamut mapping. */\nconst CHROMA_CAP = 0.32;\n\n/** The seeds that reproduce (approximately) the stock cartography. Simple mode opens on these. */\nexport const DEFAULT_SEEDS: Required<ThemeSeeds> = {\n land: STOCK_RAMPS.ink[500],\n water: STOCK_RAMPS.wave[500],\n nature: STOCK_RAMPS.verdant[500],\n accent: \"#FF3E9A\",\n};\n\ntype Ramp = Record<string | number, string>;\n\n/**\n * Re-emit a ramp in the seed's hue: every step keeps its stock lightness, chroma scales by the\n * seed's vividness relative to the ramp's own mid-step, clamped to `cap`.\n */\nfunction reRamp<T extends Ramp>(ref: T, seedHex: string, cap: number): T {\n const seed = hexToOklch(seedHex);\n const steps = Object.keys(ref);\n const midStep = steps[Math.floor(steps.length / 2)]!;\n const midChroma = Math.max(hexToOklch(ref[midStep]!).c, 0.005);\n const factor = Math.min(Math.max(seed.c / midChroma, 0.15), 3);\n const out: Ramp = {};\n for (const step of steps) {\n const refColor = hexToOklch(ref[step]!);\n out[step] = oklchToHex({\n l: refColor.l,\n c: Math.min(refColor.c * factor, cap),\n h: seed.h,\n });\n }\n return out as T;\n}\n\n/**\n * Enforce the label floors on a generated flavor's recipe. Lightness is preserved from the\n * stock ladders, which pass with margin, but WCAG contrast is computed in sRGB luminance and a\n * strong hue shift can erode that margin — so each breaching label slot has its OKLCH lightness\n * nudged away from its background until the pair clears. Bounded and deterministic.\n */\nfunction enforceLabelContrast(recipe: Recipe): Recipe {\n const fixed = structuredClone(recipe);\n for (const [labelSlot, bgSlot, floor] of LABEL_PAIRS) {\n for (let i = 0; i < 40; i++) {\n const flavor = makeFlavor(fixed) as unknown as Record<string, string>;\n const label = flavor[labelSlot as string]!;\n const bg = flavor[bgSlot as string]!;\n if (contrast(label, bg) >= floor) break;\n const l = hexToOklch(label);\n const direction = hexToOklch(bg).l > l.l ? -1 : 1;\n const nudged = oklchToHex({ ...l, l: Math.min(1, Math.max(0, l.l + direction * 0.015)) });\n setLabelSlot(fixed, labelSlot as string, nudged);\n }\n }\n return fixed;\n}\n\n/** Map a Flavor label slot back to its Recipe field. Only slots LABEL_PAIRS can name. */\nconst LABEL_SLOT_TO_RECIPE: Record<string, (r: Recipe, hex: string) => void> = {\n city_label: (r, v) => (r.labels.city = v),\n state_label: (r, v) => (r.labels.state = v),\n country_label: (r, v) => (r.labels.country = v),\n roads_label_major: (r, v) => (r.labels.roadMajor = v),\n subplace_label: (r, v) => (r.labels.subplace = v),\n address_label: (r, v) => (r.labels.address = v),\n roads_label_minor: (r, v) => (r.labels.roadMinor = v),\n ocean_label: (r, v) => (r.labels.ocean = v),\n};\n\nfunction setLabelSlot(recipe: Recipe, slot: string, hex: string): void {\n LABEL_SLOT_TO_RECIPE[slot]?.(recipe, hex);\n}\n\n/** Diff a generated recipe against the stock one into sparse overrides. */\nfunction diffRecipe(stock: Recipe, generated: Recipe): BasemapOverrides | undefined {\n const walk = (a: Record<string, unknown>, b: Record<string, unknown>) => {\n const out: Record<string, unknown> = {};\n for (const [key, stockValue] of Object.entries(a)) {\n const genValue = b[key];\n if (stockValue !== null && typeof stockValue === \"object\") {\n const nested = walk(\n stockValue as Record<string, unknown>,\n (genValue ?? {}) as Record<string, unknown>,\n );\n if (Object.keys(nested).length > 0) out[key] = nested;\n } else if (typeof genValue === \"string\" && genValue !== stockValue) {\n out[key] = genValue;\n }\n }\n return out;\n };\n const diff = walk(\n stock as unknown as Record<string, unknown>,\n generated as unknown as Record<string, unknown>,\n );\n return Object.keys(diff).length > 0 ? (diff as BasemapOverrides) : undefined;\n}\n\n/**\n * Generate a full theme from seed colours. Deterministic; the result always clears the label\n * floors in both modes (enforced, and asserted by the hue-sweep test).\n *\n * Family mapping: `land` recolours the neutral spine (and `muted`'s graphite, at a whisper of\n * chroma — that flavour exists to vanish under data), `water` the wave ramp, `nature` the\n * verdant ramp. Warm landcover (sandstone), POI accents, white road fills and the street\n * motorway orange stay stock: they are tuned relationships, not identity. `accent` styles the\n * marker and route overlays only — it never enters the basemap, same rule as the brand magenta.\n */\nexport function generateTheme(base: ThemeBase, seeds: ThemeSeeds): ThemeDoc {\n const ramps: RampSet = {\n ...STOCK_RAMPS,\n ink: reRamp(STOCK_RAMPS.ink, seeds.land, NEUTRAL_CHROMA_CAP),\n graphite: reRamp(STOCK_RAMPS.graphite, seeds.land, MUTED_CHROMA_CAP),\n wave: reRamp(STOCK_RAMPS.wave, seeds.water, CHROMA_CAP),\n verdant: reRamp(STOCK_RAMPS.verdant, seeds.nature, CHROMA_CAP),\n };\n const generated = buildRecipes(ramps);\n\n const doc: ThemeDoc = { v: 1, base, seeds: { ...seeds } };\n for (const mode of MODES) {\n const recipe = enforceLabelContrast(generated[base][mode]);\n const basemap = diffRecipe(RECIPES[base][mode], recipe);\n const half: NonNullable<ThemeDoc[\"light\"]> = {};\n if (basemap) half.basemap = basemap;\n if (seeds.accent) {\n half.marker = { color: seeds.accent };\n half.route = { color: seeds.accent, casingColor: seeds.accent };\n }\n if (Object.keys(half).length > 0) doc[mode] = half;\n }\n return doc;\n}\n","import { oklchToHex } from \"./oklch\";\nimport type { ThemeSeeds } from \"./doc\";\nimport { DEFAULT_SEEDS } from \"./generate\";\n\n/**\n * Curated seed palettes for the builder's simple mode — the hand-picked starting points, named\n * for Canadian landscapes. Each is just a seed trio + accent; `generateTheme` does the rest,\n * and its contrast guarantee holds for these like any other seeds (asserted in tests).\n */\nexport interface SeedPalette {\n /** Display name, lowercase like the flavour names. Not translated — these are names. */\n name: string;\n seeds: Required<ThemeSeeds>;\n}\n\nexport const SEED_PALETTES: SeedPalette[] = [\n { name: \"process ink\", seeds: DEFAULT_SEEDS },\n {\n name: \"boreal\",\n seeds: { land: \"#7D8B87\", water: \"#33606B\", nature: \"#3F6B4F\", accent: \"#E4572E\" },\n },\n {\n name: \"prairie\",\n seeds: { land: \"#A08D6B\", water: \"#4E7E99\", nature: \"#7C8A4D\", accent: \"#C33149\" },\n },\n {\n name: \"tundra\",\n seeds: { land: \"#8B9AA6\", water: \"#4A7BA6\", nature: \"#6E8B74\", accent: \"#FF3E9A\" },\n },\n {\n name: \"badlands\",\n seeds: { land: \"#A67B5B\", water: \"#3E7C8F\", nature: \"#6B7F53\", accent: \"#22577A\" },\n },\n {\n name: \"aurora\",\n seeds: { land: \"#8C86A3\", water: \"#4F6D9E\", nature: \"#56828A\", accent: \"#58E1C1\" },\n },\n {\n name: \"pacific\",\n seeds: { land: \"#7F9089\", water: \"#2E7D74\", nature: \"#38755B\", accent: \"#F25F5C\" },\n },\n {\n name: \"chinook\",\n seeds: { land: \"#9C8A5D\", water: \"#56789C\", nature: \"#8A9A5B\", accent: \"#D95D39\" },\n },\n];\n\n/** Wrap a hue into [0, 360). */\nconst wrap = (h: number) => ((h % 360) + 360) % 360;\n\n/**\n * A random but *harmonic* seed trio — the shuffle button. Hues are related (water lands\n * cool-of-complementary, nature analogous-of-triadic, the accent opposes the land) and chroma\n * stays inside a tasteful band, so shuffles read as designed rather than random; the\n * generator's contrast guarantee makes every one of them legible regardless.\n *\n * `rng` is injectable (returns [0,1)) so tests can drive it deterministically.\n */\nexport function shuffleSeeds(rng: () => number = Math.random): Required<ThemeSeeds> {\n const h = rng() * 360;\n return {\n land: oklchToHex({ l: 0.55, c: 0.03 + rng() * 0.05, h }),\n water: oklchToHex({ l: 0.5, c: 0.08 + rng() * 0.1, h: wrap(h + 150 + rng() * 60) }),\n nature: oklchToHex({ l: 0.5, c: 0.06 + rng() * 0.08, h: wrap(h + 60 + rng() * 80) }),\n accent: oklchToHex({ l: 0.65, c: 0.22 + rng() * 0.08, h: wrap(h + 170 + rng() * 40) }),\n };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/palette.ts","../src/recipe.ts","../src/recipes.ts","../src/validate.ts","../src/presets.ts","../src/oklch.ts","../src/compose.ts","../src/contrast.ts","../src/generate.ts","../src/palettes.ts","../src/preset.ts","../src/codec.ts"],"sourcesContent":["/**\n * Named colour ramps: the single source of colour truth for unmap cartography.\n *\n * Moved here from apps/gateway/src/palette.ts (which now re-exports these) so themes, the\n * gateway, and the builder all draw from one vocabulary. Flavors and theme recipes reference\n * these by name and never inline a hex literal.\n *\n * Ramps run light to dark by ascending key.\n */\n\n/**\n * Ember. Pre-rebrand brand accent; survives only as the `street` motorway orange, which is\n * cartographic convention (orange motorways) rather than brand. Never the interface accent —\n * that is magenta, which stays out of every basemap.\n */\nexport const ember = {\n 200: \"#ffe9c9\",\n 300: \"#ffc08c\",\n 400: \"#f7a35c\",\n 500: \"#f97316\",\n 600: \"#e07b2e\",\n 700: \"#b45309\",\n} as const;\n\n/* ── Process Ink ramps ─────────────────────────────────────────────────────────────────────\n *\n *\n * Generated in OKLCH rather than picked by eye, from three hues the brand already implies:\n * cool neutrals at 212, water at 200, vegetation at 152, with one warm family at 82 for sand\n * and farmland. OKLCH matters here because a ramp picked in sRGB has uneven perceived steps —\n * two adjacent greens can look identical while two adjacent greys look like a seam.\n *\n * Lightness is chosen so the label contrast the cartography tests enforce is a property of the\n * ramp rather than something rescued per flavour afterwards. `ink.700` on `ink.25` clears 4.5:1,\n * `ink.500` on `ink.1000` clears it inverted, and every flavour's labels are drawn from those\n * steps. That is the whole reason the generator solves for lightness instead of guessing.\n *\n * Magenta is deliberately absent. It is the interface accent — markers, selection, overlays —\n * and keeping it out of the basemap is what lets a customer's data always win the colour fight.\n *\n * Regenerate rather than hand-edit: the ramp is the source, the hex is the output.\n */\n\n/** Cool neutrals, hue 212. The spine of every Process Ink flavour except `base`. */\nexport const ink = {\n 25: \"#F1F8FA\",\n 50: \"#EAF2F3\",\n 100: \"#E2E9EB\",\n 200: \"#D6DEE0\",\n 300: \"#C9D1D3\",\n 400: \"#B7C0C2\",\n 500: \"#9DA7A9\",\n 600: \"#7E888B\",\n 700: \"#5C6769\",\n 800: \"#3D494B\",\n 850: \"#2B3639\",\n 900: \"#1A2628\",\n 950: \"#0E191C\",\n 1000: \"#030E10\",\n} as const;\n\n/**\n * Warm off-white neutrals, hue 50, chroma 0.008. The `base` pair only.\n *\n * Same lightness ladder as `ink`, re-hued to the land of the Mapbox Streets reference `base`\n * follows (`hsl(20, 20%, 95%)`): a faint warm tint rather than the cream it had, so parks,\n * water and the motorway orange read as colour against it instead of competing with it.\n */\nexport const paper = {\n 25: \"#FBF5F2\",\n 50: \"#F5EFEC\",\n 100: \"#ECE6E3\",\n 200: \"#E1DBD8\",\n 300: \"#D4CECB\",\n 400: \"#C3BDBA\",\n 500: \"#A9A3A0\",\n 600: \"#8A8582\",\n 700: \"#696361\",\n 800: \"#4A4543\",\n 850: \"#373330\",\n 900: \"#272220\",\n 950: \"#1A1614\",\n 1000: \"#0E0B09\",\n} as const;\n\n/** Water, hue 200. Cooler and more chromatic than the land it meets. */\nexport const wave = {\n 100: \"#C7F1F3\",\n 200: \"#B3E2E4\",\n 300: \"#9CCFD2\",\n 400: \"#7FB8BB\",\n 500: \"#5F9FA2\",\n 600: \"#368286\",\n 700: \"#1C6265\",\n 800: \"#024347\",\n 900: \"#002A2C\",\n 950: \"#001C1E\",\n 980: \"#001012\",\n} as const;\n\n/**\n * Sky water, hue 230. The `base` pair only.\n *\n * Same lightness ladder as `wave`, re-hued and brightened to the Streets reference's water\n * (`hsl(200, 100%, 80%)`). `sky.200` is that colour; the rest of the ladder is the dark-mode\n * inversion and the ocean-label step.\n */\nexport const sky = {\n 100: \"#CCEEFF\",\n 200: \"#A7E2FF\",\n 300: \"#8ACFF0\",\n 400: \"#73B7D7\",\n 500: \"#5A9CBC\",\n 600: \"#387D9C\",\n 700: \"#155F7C\",\n 800: \"#004057\",\n 900: \"#002837\",\n 950: \"#001B27\",\n 980: \"#000F17\",\n} as const;\n\n/** Vegetation, hue 152: park, wood, scrub. */\nexport const verdant = {\n 100: \"#D3F1DA\",\n 200: \"#C3E3CA\",\n 300: \"#AFD2B7\",\n 400: \"#96BC9F\",\n 500: \"#76A281\",\n 600: \"#50825E\",\n 700: \"#366042\",\n 800: \"#1E4128\",\n 900: \"#0B2815\",\n} as const;\n\n/** Warm landcover, hue 82: sand, beach, farmland. */\nexport const sandstone = {\n 100: \"#F5E8D0\",\n 200: \"#E7D9BF\",\n 300: \"#D6C7AC\",\n 400: \"#BFAF92\",\n 500: \"#A19070\",\n} as const;\n\n/**\n * Pure neutrals, zero chroma. Everything on `muted` except its water (see `mist`), plus the\n * road casings on `base`. Kept R=G=B so `muted` is greyscale in fact rather than in name.\n */\nexport const graphite = {\n 25: \"#FAFAFA\",\n 50: \"#F2F2F2\",\n 100: \"#E9E9E9\",\n 200: \"#DEDEDE\",\n 300: \"#D1D1D1\",\n 400: \"#BEBEBE\",\n 500: \"#A4A4A4\",\n 600: \"#868686\",\n 700: \"#656565\",\n 800: \"#464646\",\n 900: \"#232323\",\n 1000: \"#0B0B0B\",\n} as const;\n\n/**\n * Muted water: the `wave` lightness ladder at zero chroma. `muted` is greyscale end to end,\n * water included, so this ramp exists for one reason — it is the ramp the *water* seed\n * recolours when a theme is applied to `muted`, which the land ramp (`graphite`) is not.\n * `mist.200` is the light-mode fill; `mist.980` the dark-mode inversion so water stays darker\n * than land.\n */\nexport const mist = {\n 100: \"#E7E7E7\",\n 200: \"#D7D7D7\",\n 300: \"#C4C4C4\",\n 400: \"#ACACAC\",\n 500: \"#929292\",\n 600: \"#757575\",\n 700: \"#575757\",\n 800: \"#3A3A3A\",\n 900: \"#242424\",\n 950: \"#171717\",\n 980: \"#0D0D0D\",\n} as const;\n\n/**\n * Jade, hue 163. The `decimal` pair: one green family on near-black (dark) or near-white\n * (light), nothing else. Same lightness ladder as `ink`, so every label step the other styles\n * rely on clears the floors here too. Chroma rises with lightness up to the mid steps\n * (`0.16·L`) and eases off toward white (`0.42·(1−L)`), which is the profile of the\n * reference's own four greens (`#142a21` → `#50a882`).\n */\nexport const jade = {\n 25: \"#F1F9F4\",\n 50: \"#E6F4ED\",\n 100: \"#D7EEE2\",\n 200: \"#C3E6D4\",\n 300: \"#ACDDC4\",\n 400: \"#8BCFAF\",\n 500: \"#56BB90\",\n 600: \"#459975\",\n 700: \"#327357\",\n 800: \"#21513D\",\n 850: \"#173C2C\",\n 900: \"#0E2A1E\",\n 950: \"#071C13\",\n 1000: \"#030F09\",\n} as const;\n\n/**\n * Cobalt, hue 267. The `blueprint` pair: royal blue field with navy roads and pale blue water\n * in dark, blue lines on blue-white paper in light. Same lightness ladder as `ink`. Chroma\n * peaks at the field step (`700`, `0.23` — the reference's `#1c44dc`) and falls away on both\n * sides, so the pale steps stay paper-like and the navy steps stay ink-like.\n */\nexport const cobalt = {\n 25: \"#F4F7FB\",\n 50: \"#ECF0F9\",\n 100: \"#E1E8F7\",\n 200: \"#D2DCF5\",\n 300: \"#C0CFF3\",\n 400: \"#A8BDF1\",\n 500: \"#84A2EE\",\n 600: \"#587EEA\",\n 700: \"#2C4EE5\",\n 800: \"#243D93\",\n 850: \"#1D2F65\",\n 900: \"#162241\",\n 950: \"#0F1629\",\n 1000: \"#080B15\",\n} as const;\n","import type { Flavor } from \"@protomaps/basemaps\";\n\n/**\n * The unmap cartography authoring surface, moved here from apps/gateway/src/flavors.ts so the\n * gateway, the theme system, and the unmap.dev builder share one definition.\n *\n * A `Recipe` is what a theme can override: every colour a Flavor controls, expressed at the\n * level we author at. Expanding through `makeFlavor` keeps the consistency guarantees a raw\n * Flavor cannot: a casing is always derived beside its fill, and the tunnel and bridge families\n * cannot drift out of step with the surface roads they mirror.\n */\n\n/**\n * The shipped styles. Appended, never inserted: this array's order drives the style picker in\n * the unmap.dev builder, so inserting a style mid-array silently reorders a control people have\n * already learned.\n *\n * `relief` and `street` were retired; they are not listed here. Short preset codes still\n * decode those slots via `normalizeThemeBase` / the slot table in `preset.ts`.\n */\nexport const THEME_BASES = [\"base\", \"muted\", \"outdoor\", \"decimal\", \"blueprint\"] as const;\nexport type ThemeBase = (typeof THEME_BASES)[number];\n\n/** Retired style names still accepted on the wire so hardcoded theme codes keep working. */\nconst RETIRED_BASES: Record<string, ThemeBase> = {\n relief: \"outdoor\",\n street: \"base\",\n};\n\n/** Map a theme `base` — living or retired — onto a shipped style. `null` if unknown. */\nexport function normalizeThemeBase(base: string): ThemeBase | null {\n if ((THEME_BASES as readonly string[]).includes(base)) return base as ThemeBase;\n return RETIRED_BASES[base] ?? null;\n}\n\nexport const MODES = [\"light\", \"dark\"] as const;\nexport type ThemeMode = (typeof MODES)[number];\n\nexport interface RoadRamp {\n /** Unclassified / track. The bottom of the hierarchy. */\n other: string;\n otherCasing: string;\n /** Residential and service. */\n minor: string;\n minorCasing: string;\n service: string;\n serviceCasing: string;\n /** Primary / secondary. */\n major: string;\n majorCasing: string;\n /** Motorway. */\n highway: string;\n highwayCasing: string;\n /** Slip roads. */\n link: string;\n linkCasing: string;\n}\n\nexport interface LabelRamp {\n city: string;\n cityHalo: string;\n state: string;\n stateHalo: string;\n country: string;\n subplace: string;\n subplaceHalo: string;\n address: string;\n addressHalo: string;\n roadMinor: string;\n roadMinorHalo: string;\n roadMajor: string;\n roadMajorHalo: string;\n ocean: string;\n}\n\nexport interface Recipe {\n background: string;\n earth: string;\n water: string;\n /** Park, wood and scrub each take two tones; `b` is the slightly deeper of the pair. */\n parkA: string;\n parkB: string;\n woodA: string;\n woodB: string;\n scrubA: string;\n scrubB: string;\n sand: string;\n beach: string;\n glacier: string;\n /** Institutional land: hospital, school, industrial, military, zoo, aerodrome. */\n institutional: string;\n pedestrian: string;\n aerodrome: string;\n runway: string;\n pier: string;\n buildings: string;\n railway: string;\n boundaries: string;\n roads: RoadRamp;\n labels: LabelRamp;\n /**\n * Tunnels read one step recessive against the surface road, bridges one step assertive.\n * Expressed as the colours to substitute rather than a computed shift, so a style can opt\n * out of the convention where it does not suit the palette.\n */\n tunnelFill: string;\n tunnelCasing: string;\n bridgeCasing: string;\n pois: Flavor[\"pois\"];\n landcover: Flavor[\"landcover\"];\n}\n\n/**\n * Expand a recipe into the full Flavor. Every one of the interface's required slots is written\n * here exactly once, so a missing slot is a compile error rather than a silently black layer.\n */\nexport function makeFlavor(r: Recipe): Flavor {\n return {\n background: r.background,\n earth: r.earth,\n water: r.water,\n\n park_a: r.parkA,\n park_b: r.parkB,\n wood_a: r.woodA,\n wood_b: r.woodB,\n scrub_a: r.scrubA,\n scrub_b: r.scrubB,\n sand: r.sand,\n beach: r.beach,\n glacier: r.glacier,\n\n hospital: r.institutional,\n industrial: r.institutional,\n school: r.institutional,\n zoo: r.institutional,\n military: r.institutional,\n pedestrian: r.pedestrian,\n aerodrome: r.aerodrome,\n runway: r.runway,\n pier: r.pier,\n buildings: r.buildings,\n\n // Surface roads.\n other: r.roads.other,\n minor_service: r.roads.service,\n minor_a: r.roads.minor,\n minor_b: r.roads.minor,\n link: r.roads.link,\n major: r.roads.major,\n highway: r.roads.highway,\n\n minor_service_casing: r.roads.serviceCasing,\n minor_casing: r.roads.minorCasing,\n link_casing: r.roads.linkCasing,\n // early/late are the same colour: they exist so Protomaps can fade casings in at\n // different zooms, not to differentiate hue.\n major_casing_early: r.roads.majorCasing,\n major_casing_late: r.roads.majorCasing,\n highway_casing_early: r.roads.highwayCasing,\n highway_casing_late: r.roads.highwayCasing,\n\n // Tunnels: recessive, one flat fill so the network reads as \"beneath\".\n tunnel_other: r.tunnelFill,\n tunnel_minor: r.tunnelFill,\n tunnel_link: r.tunnelFill,\n tunnel_major: r.tunnelFill,\n tunnel_highway: r.tunnelFill,\n tunnel_other_casing: r.tunnelCasing,\n tunnel_minor_casing: r.tunnelCasing,\n tunnel_link_casing: r.tunnelCasing,\n tunnel_major_casing: r.tunnelCasing,\n tunnel_highway_casing: r.tunnelCasing,\n\n // Bridges: same fills as the surface road so the ribbon stays continuous, with a\n // stronger casing that lifts it off whatever it crosses.\n bridges_other: r.roads.other,\n bridges_minor: r.roads.minor,\n bridges_link: r.roads.link,\n bridges_major: r.roads.major,\n bridges_highway: r.roads.highway,\n bridges_other_casing: r.bridgeCasing,\n bridges_minor_casing: r.bridgeCasing,\n bridges_link_casing: r.bridgeCasing,\n bridges_major_casing: r.bridgeCasing,\n bridges_highway_casing: r.bridgeCasing,\n\n railway: r.railway,\n boundaries: r.boundaries,\n\n roads_label_minor: r.labels.roadMinor,\n roads_label_minor_halo: r.labels.roadMinorHalo,\n roads_label_major: r.labels.roadMajor,\n roads_label_major_halo: r.labels.roadMajorHalo,\n ocean_label: r.labels.ocean,\n subplace_label: r.labels.subplace,\n subplace_label_halo: r.labels.subplaceHalo,\n city_label: r.labels.city,\n city_label_halo: r.labels.cityHalo,\n state_label: r.labels.state,\n state_label_halo: r.labels.stateHalo,\n country_label: r.labels.country,\n address_label: r.labels.address,\n address_label_halo: r.labels.addressHalo,\n\n pois: r.pois,\n landcover: r.landcover,\n };\n}\n","import type { Recipe, ThemeBase, ThemeMode } from \"./recipe\";\nimport {\n cobalt,\n ember,\n graphite,\n ink,\n jade,\n mist,\n paper,\n sandstone,\n sky,\n verdant,\n wave,\n} from \"./palette\";\n\n/**\n * The ramp families (plus ember) a recipe draws from. `buildRecipes` is parameterized on\n * this so the theme generator can re-emit the same recipes from *generated* ramps — same\n * lightness ladders, a customer's hues — while the stock `RECIPES` stay byte-identical to the\n * hand-tuned originals (they are `buildRecipes(STOCK_RAMPS)`).\n */\nexport interface RampSet {\n ink: typeof ink;\n paper: typeof paper;\n wave: typeof wave;\n sky: typeof sky;\n verdant: typeof verdant;\n sandstone: typeof sandstone;\n graphite: typeof graphite;\n mist: typeof mist;\n jade: typeof jade;\n cobalt: typeof cobalt;\n ember: typeof ember;\n}\n\nexport const STOCK_RAMPS: RampSet = {\n ink,\n paper,\n wave,\n sky,\n verdant,\n sandstone,\n graphite,\n mist,\n jade,\n cobalt,\n ember,\n};\n\n/*\n * The shipped Process Ink recipes as data, moved from apps/gateway/src/flavors.ts.\n * These are the styles a ThemeDoc's sparse overrides merge onto. Colour comes from the\n * ramps in ./palette and never a hex literal here, except pure white road fills.\n */\n\n/** Build the shipped recipes from a ramp set. Stock ramps in → the shipped cartography out. */\nexport function buildRecipes(\n r: RampSet,\n): Record<ThemeBase, Record<ThemeMode, Recipe>> {\n /**\n * `base` / `light`. The general-purpose map, following the design of Mapbox Streets rather\n * than copying it: a faintly warm off-white land (`paper`, hue 50), parks and woods in a\n * green that reads as green, sky-blue water, white roads with cool grey casings, and the\n * motorway drawn in orange — the one cartographic convention allowed to carry warmth.\n * Boundaries and aerodromes take a lavender from `cobalt` the way Streets gives them a\n * purple, so they never read as roads. Full road hierarchy and visible buildings stay; this\n * is the map someone gets when they have not chosen one, so it errs towards legible over\n * quiet.\n *\n * Streets' blue-grey neighbourhood labels and its blue water labels both miss the contrast\n * floors on their backgrounds, so labels keep the contrast-safe `paper` and `sky` steps.\n */\n const BASE_LIGHT: Recipe = {\n background: r.paper[100],\n earth: r.paper[25],\n water: r.sky[200],\n parkA: r.verdant[300],\n parkB: r.verdant[400],\n woodA: r.verdant[300],\n woodB: r.verdant[400],\n scrubA: r.verdant[200],\n scrubB: r.verdant[300],\n sand: r.sandstone[200],\n beach: r.sandstone[200],\n glacier: r.paper[25],\n institutional: r.paper[100],\n pedestrian: r.paper[100],\n aerodrome: r.cobalt[200],\n runway: r.cobalt[300],\n pier: r.paper[300],\n buildings: r.paper[200],\n railway: r.graphite[400],\n boundaries: r.cobalt[600],\n roads: {\n other: r.paper[100],\n otherCasing: r.graphite[200],\n minor: \"#FFFFFF\",\n minorCasing: r.graphite[200],\n service: r.paper[100],\n serviceCasing: r.graphite[200],\n major: \"#FFFFFF\",\n majorCasing: r.graphite[300],\n highway: r.ember[400],\n highwayCasing: r.ember[600],\n link: r.ember[300],\n linkCasing: r.ember[500],\n },\n tunnelFill: r.paper[200],\n tunnelCasing: r.graphite[200],\n bridgeCasing: r.graphite[400],\n labels: {\n city: r.paper[1000],\n cityHalo: r.paper[25],\n state: r.paper[700],\n stateHalo: r.paper[25],\n country: r.paper[700],\n subplace: r.paper[700],\n subplaceHalo: r.paper[25],\n address: r.paper[700],\n addressHalo: r.paper[25],\n roadMinor: r.paper[800],\n roadMinorHalo: r.paper[25],\n roadMajor: r.paper[900],\n roadMajorHalo: r.paper[25],\n ocean: r.sky[800],\n },\n\n pois: {\n blue: \"#2D6E8F\",\n green: r.verdant[700],\n lapis: \"#3F5C93\",\n pink: \"#8F4A6B\",\n red: \"#9B4340\",\n slategray: r.paper[700],\n tangerine: \"#8F5322\",\n turquoise: r.sky[700],\n },\n landcover: {\n grassland: r.verdant[200],\n barren: r.sandstone[200],\n urban_area: r.paper[50],\n farmland: r.verdant[100],\n glacier: r.paper[25],\n scrub: r.verdant[200],\n forest: r.verdant[400],\n },\n };\n\n /**\n * `base` / `dark`. The same map inverted, with the inversion that matters: water is drawn\n * *darker* than land. Two mid-tones meeting at a coastline is how a dark basemap turns to\n * mud, so the figure/ground edge is bought with lightness rather than hue. The motorway keeps\n * its orange, one step deeper.\n */\n const BASE_DARK: Recipe = {\n background: r.paper[950],\n earth: r.paper[900],\n water: r.sky[980],\n parkA: r.verdant[800],\n parkB: r.verdant[700],\n woodA: r.verdant[800],\n woodB: r.verdant[700],\n scrubA: r.verdant[900],\n scrubB: r.verdant[800],\n sand: r.sandstone[500],\n beach: r.sandstone[500],\n glacier: r.paper[700],\n institutional: r.paper[950],\n pedestrian: r.paper[950],\n aerodrome: r.cobalt[900],\n runway: r.cobalt[850],\n pier: r.paper[850],\n buildings: r.paper[850],\n railway: r.paper[700],\n boundaries: r.cobalt[500],\n roads: {\n other: r.paper[850],\n otherCasing: r.paper[1000],\n minor: r.paper[800],\n minorCasing: r.paper[1000],\n service: r.paper[850],\n serviceCasing: r.paper[1000],\n major: r.paper[700],\n majorCasing: r.paper[1000],\n highway: r.ember[600],\n highwayCasing: r.paper[1000],\n link: r.ember[700],\n linkCasing: r.paper[1000],\n },\n tunnelFill: r.paper[900],\n tunnelCasing: r.paper[1000],\n bridgeCasing: r.paper[1000],\n labels: {\n city: r.paper[100],\n cityHalo: r.paper[1000],\n state: r.paper[500],\n stateHalo: r.paper[1000],\n country: r.paper[500],\n subplace: r.paper[500],\n subplaceHalo: r.paper[1000],\n address: r.paper[500],\n addressHalo: r.paper[1000],\n roadMinor: r.paper[500],\n roadMinorHalo: r.paper[1000],\n roadMajor: r.paper[400],\n roadMajorHalo: r.paper[1000],\n ocean: r.sky[400],\n },\n\n pois: {\n blue: \"#7FC4E8\",\n green: r.verdant[400],\n lapis: \"#8FB0EA\",\n pink: \"#E3A0C0\",\n red: \"#EE968F\",\n slategray: r.paper[500],\n tangerine: \"#E8AC7C\",\n turquoise: r.sky[400],\n },\n landcover: {\n grassland: r.verdant[800],\n barren: r.sandstone[500],\n urban_area: r.paper[950],\n farmland: r.verdant[900],\n glacier: r.paper[700],\n scrub: r.verdant[900],\n forest: r.verdant[700],\n },\n };\n\n /**\n * `muted` / `light`. Greyscale end to end, after Mapbox Standard's monochrome theme: a\n * near-white field, parks and buildings a step or two down the same grey, white roads with\n * grey casings, grey water, grey labels, grey icons (its own sprite sheet). The style exists\n * so external data can be drawn over it without an arms race: nothing on the map carries a\n * hue, so an overlay in any colour is the only colour there is.\n *\n * Water is drawn from `mist`, a zero-chroma twin of the water ladder, rather than from\n * `graphite`: same greys, but it is the ramp the water seed recolours when someone applies\n * a theme to `muted`.\n */\n const MUTED_LIGHT: Recipe = {\n background: r.graphite[100],\n earth: r.graphite[25],\n water: r.mist[200],\n parkA: r.graphite[50],\n parkB: r.graphite[100],\n woodA: r.graphite[50],\n woodB: r.graphite[100],\n scrubA: r.graphite[50],\n scrubB: r.graphite[100],\n sand: r.graphite[100],\n beach: r.graphite[100],\n glacier: r.graphite[25],\n institutional: r.graphite[100],\n pedestrian: r.graphite[50],\n aerodrome: r.graphite[100],\n runway: r.graphite[200],\n pier: r.graphite[200],\n buildings: r.graphite[100],\n railway: r.graphite[400],\n boundaries: r.graphite[500],\n roads: {\n other: r.graphite[25],\n otherCasing: r.graphite[200],\n minor: \"#FFFFFF\",\n minorCasing: r.graphite[200],\n service: r.graphite[25],\n serviceCasing: r.graphite[200],\n major: \"#FFFFFF\",\n majorCasing: r.graphite[300],\n highway: r.graphite[200],\n highwayCasing: r.graphite[300],\n link: \"#FFFFFF\",\n linkCasing: r.graphite[300],\n },\n tunnelFill: r.graphite[100],\n tunnelCasing: r.graphite[200],\n bridgeCasing: r.graphite[400],\n labels: {\n city: r.graphite[1000],\n cityHalo: r.graphite[25],\n state: r.graphite[700],\n stateHalo: r.graphite[25],\n country: r.graphite[700],\n subplace: r.graphite[700],\n subplaceHalo: r.graphite[25],\n address: r.graphite[700],\n addressHalo: r.graphite[25],\n roadMinor: r.graphite[700],\n roadMinorHalo: r.graphite[25],\n roadMajor: r.graphite[800],\n roadMajorHalo: r.graphite[25],\n ocean: r.graphite[800],\n },\n\n pois: {\n blue: r.graphite[600],\n green: r.graphite[600],\n lapis: r.graphite[700],\n pink: r.graphite[600],\n red: r.graphite[700],\n slategray: r.graphite[700],\n tangerine: r.graphite[600],\n turquoise: r.graphite[600],\n },\n landcover: {\n grassland: r.graphite[50],\n barren: r.graphite[100],\n urban_area: r.graphite[50],\n farmland: r.graphite[50],\n glacier: r.graphite[25],\n scrub: r.graphite[50],\n forest: r.graphite[100],\n },\n };\n\n /**\n * `muted` / `dark`. The greyscale pair inverted: water sits below the land, roads stay the\n * brightest thing on the map, same hierarchy as light.\n */\n const MUTED_DARK: Recipe = {\n background: r.graphite[1000],\n earth: r.graphite[900],\n water: r.mist[980],\n parkA: r.graphite[900],\n parkB: r.graphite[800],\n woodA: r.graphite[900],\n woodB: r.graphite[800],\n scrubA: r.graphite[900],\n scrubB: r.graphite[800],\n sand: r.graphite[800],\n beach: r.graphite[800],\n glacier: r.graphite[700],\n institutional: r.graphite[900],\n pedestrian: r.graphite[900],\n aerodrome: r.graphite[900],\n runway: r.graphite[800],\n pier: r.graphite[800],\n buildings: r.graphite[800],\n railway: r.graphite[700],\n boundaries: r.graphite[600],\n roads: {\n other: r.graphite[800],\n otherCasing: r.graphite[1000],\n minor: r.graphite[700],\n minorCasing: r.graphite[1000],\n service: r.graphite[800],\n serviceCasing: r.graphite[1000],\n major: r.graphite[600],\n majorCasing: r.graphite[1000],\n highway: r.graphite[500],\n highwayCasing: r.graphite[1000],\n link: r.graphite[600],\n linkCasing: r.graphite[1000],\n },\n tunnelFill: r.graphite[900],\n tunnelCasing: r.graphite[1000],\n bridgeCasing: r.graphite[1000],\n labels: {\n city: r.graphite[100],\n cityHalo: r.graphite[1000],\n state: r.graphite[500],\n stateHalo: r.graphite[1000],\n country: r.graphite[500],\n subplace: r.graphite[500],\n subplaceHalo: r.graphite[1000],\n address: r.graphite[500],\n addressHalo: r.graphite[1000],\n roadMinor: r.graphite[500],\n roadMinorHalo: r.graphite[1000],\n roadMajor: r.graphite[400],\n roadMajorHalo: r.graphite[1000],\n ocean: r.graphite[400],\n },\n\n pois: {\n blue: r.graphite[400],\n green: r.graphite[400],\n lapis: r.graphite[500],\n pink: r.graphite[400],\n red: r.graphite[500],\n slategray: r.graphite[500],\n tangerine: r.graphite[400],\n turquoise: r.graphite[400],\n },\n landcover: {\n grassland: r.graphite[900],\n barren: r.graphite[800],\n urban_area: r.graphite[900],\n farmland: r.graphite[900],\n glacier: r.graphite[700],\n scrub: r.graphite[900],\n forest: r.graphite[800],\n },\n };\n\n /**\n * `outdoor` / `light`. Terrain-first scenic: the map you use to look at ground rather than to\n * find an address.\n *\n * Land sits a step lighter than `base` on purpose: a hillshade is composited beneath the roads\n * with a multiply blend, which only ever darkens, so the lift is the headroom that shading\n * spends. Rendered without a DEM it will look flat and slightly washed — that is the tell that\n * the terrain source is missing, not a palette bug. See `terrain.ts`.\n *\n * **Landcover stops receding.** Every other flavour keeps ground cover near-neutral so a\n * customer's data wins. Here the ground cover *is* the content, so forest, scrub and grassland\n * separate across `verdant` instead of collapsing into one field.\n *\n * **Protected land reads as protected.** `park` steps a tone deeper than generic vegetation, so a\n * national park is distinguishable from the golf course that `landuse_park` files beside it.\n *\n * **Roads recede one step**, via their casings rather than their fills: a lighter casing on a\n * white road keeps the shape legible while surrendering the contrast fight to the terrain.\n * Labels and halos keep the same contrast-safe `ink` steps as `base`, which is what keeps the\n * enforced contrast floors satisfied — the ramps are solved against those, and re-deriving them\n * for one flavour would be re-solving a problem that is already solved.\n */\n const OUTDOOR_LIGHT: Recipe = {\n background: r.ink[200],\n earth: r.ink[50],\n water: r.wave[300],\n parkA: r.verdant[300],\n parkB: r.verdant[400],\n woodA: r.verdant[300],\n woodB: r.verdant[400],\n scrubA: r.verdant[200],\n scrubB: r.verdant[300],\n sand: r.sandstone[300],\n beach: r.sandstone[300],\n glacier: r.ink[25],\n institutional: r.ink[25],\n pedestrian: r.ink[50],\n aerodrome: r.ink[50],\n runway: r.ink[200],\n pier: r.ink[300],\n // A step lighter than `base`: outdoors, the building footprint is context, not content.\n buildings: r.ink[200],\n railway: r.ink[500],\n boundaries: r.ink[600],\n roads: {\n other: r.ink[50],\n otherCasing: r.ink[200],\n minor: r.ink[25],\n minorCasing: r.ink[200],\n service: r.ink[50],\n serviceCasing: r.ink[200],\n major: \"#FFFFFF\",\n majorCasing: r.ink[300],\n highway: \"#FFFFFF\",\n highwayCasing: r.ink[400],\n link: \"#FFFFFF\",\n linkCasing: r.ink[300],\n },\n tunnelFill: r.ink[200],\n tunnelCasing: r.ink[300],\n bridgeCasing: r.ink[400],\n labels: {\n city: r.ink[1000],\n cityHalo: r.ink[25],\n state: r.ink[700],\n stateHalo: r.ink[25],\n country: r.ink[700],\n subplace: r.ink[700],\n subplaceHalo: r.ink[25],\n address: r.ink[700],\n addressHalo: r.ink[25],\n roadMinor: r.ink[700],\n roadMinorHalo: r.ink[25],\n roadMajor: r.ink[800],\n roadMajorHalo: r.ink[25],\n ocean: r.wave[800],\n },\n\n pois: {\n blue: \"#2D6E8F\",\n // Peaks, parks, forests and gardens all come through green. On this flavour they are the\n // POIs worth finding, so it carries a full step more weight than elsewhere.\n green: r.verdant[800],\n lapis: \"#3F5C93\",\n pink: \"#8F4A6B\",\n red: \"#9B4340\",\n slategray: r.ink[700],\n tangerine: \"#8F5322\",\n turquoise: r.wave[700],\n },\n landcover: {\n grassland: r.verdant[200],\n barren: r.sandstone[300],\n urban_area: r.ink[100],\n farmland: r.sandstone[200],\n glacier: r.ink[25],\n scrub: r.verdant[300],\n forest: r.verdant[400],\n },\n };\n\n /**\n * `outdoor` / `dark`. The same three divergences, inverted: the land sits darker to leave room\n * *above* it for a hillshade highlight to do the modelling.\n *\n * Vegetation lifts rather than deepens here. On a dark basemap a deeper green is indistinguishable\n * from the land it sits on, so the separation that `light` gets by going darker, `dark` gets by\n * going lighter — the same intent through the opposite move.\n */\n const OUTDOOR_DARK: Recipe = {\n background: r.ink[1000],\n earth: r.ink[950],\n water: r.wave[980],\n parkA: r.verdant[700],\n parkB: r.verdant[600],\n woodA: r.verdant[700],\n woodB: r.verdant[600],\n scrubA: r.verdant[800],\n scrubB: r.verdant[700],\n sand: r.sandstone[500],\n beach: r.sandstone[500],\n glacier: r.ink[700],\n institutional: r.ink[1000],\n pedestrian: r.ink[950],\n aerodrome: r.ink[950],\n runway: r.ink[850],\n pier: r.ink[850],\n buildings: r.ink[900],\n railway: r.ink[700],\n boundaries: r.ink[600],\n roads: {\n // The minor tier recedes toward `earth`; majors and highways hold their contrast,\n // because a road you cannot see is a different failure from a road that is merely quiet.\n other: r.ink[900],\n otherCasing: r.ink[1000],\n minor: r.ink[850],\n minorCasing: r.ink[1000],\n service: r.ink[900],\n serviceCasing: r.ink[1000],\n major: r.ink[700],\n majorCasing: r.ink[1000],\n highway: r.ink[600],\n highwayCasing: r.ink[1000],\n link: r.ink[700],\n linkCasing: r.ink[1000],\n },\n tunnelFill: r.ink[900],\n tunnelCasing: r.ink[1000],\n bridgeCasing: r.ink[1000],\n labels: {\n city: r.ink[100],\n cityHalo: r.ink[1000],\n state: r.ink[500],\n stateHalo: r.ink[1000],\n country: r.ink[500],\n subplace: r.ink[500],\n subplaceHalo: r.ink[1000],\n address: r.ink[500],\n addressHalo: r.ink[1000],\n roadMinor: r.ink[500],\n roadMinorHalo: r.ink[1000],\n roadMajor: r.ink[400],\n roadMajorHalo: r.ink[1000],\n ocean: r.wave[400],\n },\n\n pois: {\n blue: \"#7FC4E8\",\n green: r.verdant[300],\n lapis: \"#8FB0EA\",\n pink: \"#E3A0C0\",\n red: \"#EE968F\",\n slategray: r.ink[500],\n tangerine: \"#E8AC7C\",\n turquoise: r.wave[400],\n },\n landcover: {\n grassland: r.verdant[700],\n barren: r.sandstone[500],\n urban_area: r.ink[950],\n farmland: r.verdant[900],\n glacier: r.ink[700],\n scrub: r.verdant[800],\n forest: r.verdant[600],\n },\n };\n\n /**\n * `decimal` / `light`. The same family turned over: mint-white paper, water the pale green,\n * roads as darker green lines with a white casing (a line on paper rather than a light on\n * glass), labels in the deep greens. Same hierarchy, same single hue.\n */\n const DECIMAL_LIGHT: Recipe = {\n background: r.jade[100],\n earth: r.jade[25],\n water: r.jade[200],\n parkA: r.jade[50],\n parkB: r.jade[100],\n woodA: r.jade[50],\n woodB: r.jade[100],\n scrubA: r.jade[50],\n scrubB: r.jade[100],\n sand: r.jade[50],\n beach: r.jade[50],\n glacier: r.jade[25],\n institutional: r.jade[50],\n pedestrian: r.jade[50],\n aerodrome: r.jade[50],\n runway: r.jade[200],\n pier: r.jade[200],\n buildings: r.jade[100],\n railway: r.jade[500],\n boundaries: r.jade[600],\n roads: {\n other: r.jade[200],\n otherCasing: r.jade[25],\n minor: r.jade[300],\n minorCasing: r.jade[25],\n service: r.jade[200],\n serviceCasing: r.jade[25],\n major: r.jade[400],\n majorCasing: r.jade[25],\n highway: r.jade[500],\n highwayCasing: r.jade[25],\n link: r.jade[400],\n linkCasing: r.jade[25],\n },\n tunnelFill: r.jade[100],\n tunnelCasing: r.jade[200],\n bridgeCasing: r.jade[600],\n labels: {\n city: r.jade[1000],\n cityHalo: r.jade[25],\n state: r.jade[700],\n stateHalo: r.jade[25],\n country: r.jade[700],\n subplace: r.jade[700],\n subplaceHalo: r.jade[25],\n address: r.jade[700],\n addressHalo: r.jade[25],\n roadMinor: r.jade[700],\n roadMinorHalo: r.jade[25],\n roadMajor: r.jade[800],\n roadMajorHalo: r.jade[25],\n ocean: r.jade[800],\n },\n\n pois: {\n blue: r.jade[700],\n green: r.jade[700],\n lapis: r.jade[700],\n pink: r.jade[700],\n red: r.jade[700],\n slategray: r.jade[700],\n tangerine: r.jade[700],\n turquoise: r.jade[700],\n },\n landcover: {\n grassland: r.jade[50],\n barren: r.jade[50],\n urban_area: r.jade[50],\n farmland: r.jade[50],\n glacier: r.jade[25],\n scrub: r.jade[50],\n forest: r.jade[100],\n },\n };\n\n /**\n * `decimal` / `dark`. The native mode: one green family on near-black, modelled on the\n * \"Decimal\" monochrome look — land and background the same black, water and parks a shade\n * of the darkest green, roads drawn as green lines that brighten up the hierarchy\n * (`850` tracks, `800` streets, `700` primaries, `600` motorways) with the background as\n * their casing, and every label in the two brightest greens. Nothing on the map is any\n * other hue, which is the whole point: a customer's overlay in any colour is the only\n * colour there is.\n */\n const DECIMAL_DARK: Recipe = {\n background: r.jade[1000],\n earth: r.jade[1000],\n water: r.jade[900],\n parkA: r.jade[950],\n parkB: r.jade[900],\n woodA: r.jade[950],\n woodB: r.jade[900],\n scrubA: r.jade[950],\n scrubB: r.jade[900],\n sand: r.jade[950],\n beach: r.jade[950],\n glacier: r.jade[900],\n institutional: r.jade[950],\n pedestrian: r.jade[950],\n aerodrome: r.jade[950],\n runway: r.jade[850],\n pier: r.jade[850],\n buildings: r.jade[900],\n railway: r.jade[800],\n boundaries: r.jade[700],\n roads: {\n other: r.jade[850],\n otherCasing: r.jade[1000],\n minor: r.jade[800],\n minorCasing: r.jade[1000],\n service: r.jade[850],\n serviceCasing: r.jade[1000],\n major: r.jade[700],\n majorCasing: r.jade[1000],\n highway: r.jade[600],\n highwayCasing: r.jade[1000],\n link: r.jade[700],\n linkCasing: r.jade[1000],\n },\n tunnelFill: r.jade[900],\n tunnelCasing: r.jade[1000],\n bridgeCasing: r.jade[1000],\n labels: {\n city: r.jade[500],\n cityHalo: r.jade[1000],\n state: r.jade[600],\n stateHalo: r.jade[1000],\n country: r.jade[600],\n subplace: r.jade[600],\n subplaceHalo: r.jade[1000],\n address: r.jade[600],\n addressHalo: r.jade[1000],\n roadMinor: r.jade[600],\n roadMinorHalo: r.jade[1000],\n roadMajor: r.jade[500],\n roadMajorHalo: r.jade[1000],\n ocean: r.jade[500],\n },\n\n pois: {\n blue: r.jade[600],\n green: r.jade[600],\n lapis: r.jade[600],\n pink: r.jade[600],\n red: r.jade[600],\n slategray: r.jade[600],\n tangerine: r.jade[600],\n turquoise: r.jade[600],\n },\n landcover: {\n grassland: r.jade[950],\n barren: r.jade[950],\n urban_area: r.jade[950],\n farmland: r.jade[950],\n glacier: r.jade[900],\n scrub: r.jade[950],\n forest: r.jade[900],\n },\n };\n\n /**\n * `blueprint` / `light`. The print, not the plate: blue-white paper, pale blue water, roads\n * as blue lines with a white casing that darken up the hierarchy, labels in the deep blues.\n */\n const BLUEPRINT_LIGHT: Recipe = {\n background: r.cobalt[100],\n earth: r.cobalt[25],\n water: r.cobalt[200],\n parkA: r.cobalt[50],\n parkB: r.cobalt[100],\n woodA: r.cobalt[50],\n woodB: r.cobalt[100],\n scrubA: r.cobalt[50],\n scrubB: r.cobalt[100],\n sand: r.cobalt[50],\n beach: r.cobalt[50],\n glacier: r.cobalt[25],\n institutional: r.cobalt[50],\n pedestrian: r.cobalt[50],\n aerodrome: r.cobalt[50],\n runway: r.cobalt[200],\n pier: r.cobalt[200],\n buildings: r.cobalt[100],\n railway: r.cobalt[500],\n boundaries: r.cobalt[600],\n roads: {\n other: r.cobalt[200],\n otherCasing: r.cobalt[25],\n minor: r.cobalt[300],\n minorCasing: r.cobalt[25],\n service: r.cobalt[200],\n serviceCasing: r.cobalt[25],\n major: r.cobalt[400],\n majorCasing: r.cobalt[25],\n highway: r.cobalt[500],\n highwayCasing: r.cobalt[25],\n link: r.cobalt[400],\n linkCasing: r.cobalt[25],\n },\n tunnelFill: r.cobalt[100],\n tunnelCasing: r.cobalt[200],\n bridgeCasing: r.cobalt[600],\n labels: {\n city: r.cobalt[1000],\n cityHalo: r.cobalt[25],\n state: r.cobalt[700],\n stateHalo: r.cobalt[25],\n country: r.cobalt[700],\n subplace: r.cobalt[700],\n subplaceHalo: r.cobalt[25],\n address: r.cobalt[700],\n addressHalo: r.cobalt[25],\n roadMinor: r.cobalt[700],\n roadMinorHalo: r.cobalt[25],\n roadMajor: r.cobalt[800],\n roadMajorHalo: r.cobalt[25],\n ocean: r.cobalt[800],\n },\n\n pois: {\n blue: r.cobalt[700],\n green: r.cobalt[700],\n lapis: r.cobalt[700],\n pink: r.cobalt[700],\n red: r.cobalt[700],\n slategray: r.cobalt[700],\n tangerine: r.cobalt[700],\n turquoise: r.cobalt[700],\n },\n landcover: {\n grassland: r.cobalt[50],\n barren: r.cobalt[50],\n urban_area: r.cobalt[50],\n farmland: r.cobalt[50],\n glacier: r.cobalt[25],\n scrub: r.cobalt[50],\n forest: r.cobalt[100],\n },\n };\n\n /**\n * `blueprint` / `dark`. The native mode, modelled on the \"Cartogram\" look: a royal blue\n * field (`cobalt.700`), parks and buildings one lighter blue, water lighter still, and roads\n * as navy lines with a pale casing — ink on a blueprint. This is the one dark mode where\n * water is *lighter* than land, on purpose: the reference draws it that way, and a blueprint\n * with dark water would just be a night map. Labels are the palest steps; `state` sits one\n * step lighter than the reference's `#b9c6f5` because that grey-blue misses 4.5:1 on the\n * field.\n */\n const BLUEPRINT_DARK: Recipe = {\n background: r.cobalt[700],\n earth: r.cobalt[700],\n water: r.cobalt[400],\n parkA: r.cobalt[600],\n parkB: r.cobalt[600],\n woodA: r.cobalt[600],\n woodB: r.cobalt[600],\n scrubA: r.cobalt[600],\n scrubB: r.cobalt[600],\n sand: r.cobalt[600],\n beach: r.cobalt[600],\n glacier: r.cobalt[500],\n institutional: r.cobalt[600],\n pedestrian: r.cobalt[700],\n aerodrome: r.cobalt[600],\n runway: r.cobalt[800],\n pier: r.cobalt[800],\n buildings: r.cobalt[600],\n railway: r.cobalt[400],\n boundaries: r.cobalt[300],\n roads: {\n other: r.cobalt[800],\n otherCasing: r.cobalt[700],\n minor: r.cobalt[850],\n minorCasing: r.cobalt[600],\n service: r.cobalt[800],\n serviceCasing: r.cobalt[700],\n major: r.cobalt[900],\n majorCasing: r.cobalt[600],\n highway: r.cobalt[950],\n highwayCasing: r.cobalt[500],\n link: r.cobalt[900],\n linkCasing: r.cobalt[600],\n },\n tunnelFill: r.cobalt[800],\n tunnelCasing: r.cobalt[700],\n bridgeCasing: r.cobalt[500],\n labels: {\n city: r.cobalt[25],\n cityHalo: r.cobalt[700],\n state: r.cobalt[200],\n stateHalo: r.cobalt[700],\n country: r.cobalt[200],\n subplace: r.cobalt[300],\n subplaceHalo: r.cobalt[700],\n address: r.cobalt[300],\n addressHalo: r.cobalt[700],\n roadMinor: r.cobalt[300],\n roadMinorHalo: r.cobalt[700],\n roadMajor: r.cobalt[100],\n roadMajorHalo: r.cobalt[700],\n ocean: r.cobalt[900],\n },\n\n pois: {\n blue: r.cobalt[200],\n green: r.cobalt[200],\n lapis: r.cobalt[200],\n pink: r.cobalt[200],\n red: r.cobalt[200],\n slategray: r.cobalt[200],\n tangerine: r.cobalt[200],\n turquoise: r.cobalt[200],\n },\n landcover: {\n grassland: r.cobalt[600],\n barren: r.cobalt[600],\n urban_area: r.cobalt[700],\n farmland: r.cobalt[600],\n glacier: r.cobalt[500],\n scrub: r.cobalt[600],\n forest: r.cobalt[600],\n },\n };\n\n return {\n base: { light: BASE_LIGHT, dark: BASE_DARK },\n muted: { light: MUTED_LIGHT, dark: MUTED_DARK },\n outdoor: { light: OUTDOOR_LIGHT, dark: OUTDOOR_DARK },\n decimal: { light: DECIMAL_LIGHT, dark: DECIMAL_DARK },\n blueprint: { light: BLUEPRINT_LIGHT, dark: BLUEPRINT_DARK },\n };\n}\n\nexport const RECIPES: Record<\n ThemeBase,\n Record<ThemeMode, Recipe>\n> = buildRecipes(STOCK_RAMPS);\n","import { THEME_BASES, normalizeThemeBase } from \"./recipe\";\nimport { RECIPES } from \"./recipes\";\nimport type { ThemeDoc } from \"./doc\";\n\n/**\n * Validation failure. `detail` lists every bad path in one throw — collect-then-throw, so a\n * builder user fixing a hand-edited document sees all of it at once rather than one field per\n * round trip (the same reporting philosophy as the cartography contrast tests).\n */\nexport class ThemeError extends Error {\n readonly detail: string[];\n constructor(message: string, detail: string[]) {\n super(message);\n this.name = \"ThemeError\";\n this.detail = detail;\n }\n}\n\n/** 6- or 8-digit hex only. Hex-by-grammar is what makes \"no URLs, no expressions\" a property. */\nconst HEX = /^#[0-9a-fA-F]{6}([0-9a-fA-F]{2})?$/;\n\nconst MAX_NAME_LENGTH = 40;\n\n/** [min, max] bounds per numeric field. */\nconst MARKER_BOUNDS: Record<string, readonly [number, number]> = {\n scale: [0.5, 2],\n};\nconst ROUTE_BOUNDS: Record<string, readonly [number, number]> = {\n width: [1, 12],\n opacity: [0, 1],\n casingWidth: [0, 24],\n casingOpacity: [0, 1],\n};\n\nconst isRecord = (v: unknown): v is Record<string, unknown> =>\n typeof v === \"object\" && v !== null && !Array.isArray(v);\n\n/**\n * Validate a basemap override object against the Recipe shape, using a real recipe as the\n * schema: a key is legal iff it exists on the reference, objects recurse, strings must be hex.\n * The data is the schema, so the validator can never drift from what `mergeRecipe` accepts.\n */\nfunction walkBasemap(value: unknown, reference: unknown, path: string, errors: string[]): void {\n if (!isRecord(value)) {\n errors.push(`${path}: must be an object`);\n return;\n }\n const ref = reference as Record<string, unknown>;\n for (const [key, v] of Object.entries(value)) {\n const target = ref[key];\n const p = `${path}.${key}`;\n if (target === undefined) {\n errors.push(`${p}: unknown field`);\n } else if (typeof target === \"string\") {\n if (typeof v !== \"string\" || !HEX.test(v)) {\n errors.push(`${p}: must be a hex colour (#RRGGBB or #RRGGBBAA)`);\n }\n } else {\n walkBasemap(v, target, p, errors);\n }\n }\n}\n\n/** Validate a flat colour+number leaf object (marker/route) against a bounds table. */\nfunction walkLeaf(\n value: unknown,\n colorKeys: readonly string[],\n bounds: Record<string, readonly [number, number]>,\n path: string,\n errors: string[],\n): void {\n if (!isRecord(value)) {\n errors.push(`${path}: must be an object`);\n return;\n }\n for (const [key, v] of Object.entries(value)) {\n const p = `${path}.${key}`;\n if (colorKeys.includes(key)) {\n if (typeof v !== \"string\" || !HEX.test(v)) {\n errors.push(`${p}: must be a hex colour (#RRGGBB or #RRGGBBAA)`);\n }\n } else if (key in bounds) {\n const [lo, hi] = bounds[key]!;\n if (typeof v !== \"number\" || !Number.isFinite(v) || v < lo || v > hi) {\n errors.push(`${p}: out of bounds (${lo}–${hi})`);\n }\n } else {\n errors.push(`${p}: unknown field`);\n }\n }\n}\n\nconst HALF_KEYS = [\"basemap\", \"marker\", \"route\"] as const;\nconst DOC_KEYS = [\"v\", \"name\", \"base\", \"seeds\", \"light\", \"dark\"] as const;\nconst SEED_COLOR_KEYS = [\"land\", \"water\", \"nature\", \"accent\"] as const;\nconst REQUIRED_SEED_KEYS = [\"land\", \"water\", \"nature\"] as const;\n\n/**\n * Validate an untrusted value as a ThemeDoc. Returns the (unchanged) document on success;\n * throws a `ThemeError` naming every invalid path otherwise. Unknown fields anywhere are\n * errors — a theme is data only, and the reject-unknown posture is what keeps it that way.\n */\nexport function validateTheme(input: unknown): ThemeDoc {\n const errors: string[] = [];\n if (!isRecord(input)) {\n throw new ThemeError(\"invalid theme\", [\"theme must be a JSON object\"]);\n }\n\n for (const key of Object.keys(input)) {\n if (!(DOC_KEYS as readonly string[]).includes(key)) errors.push(`${key}: unknown field`);\n }\n\n if (input.v !== 1) errors.push(\"v: must be 1\");\n const base = typeof input.base === \"string\" ? normalizeThemeBase(input.base) : null;\n if (!base) {\n errors.push(`base: must be one of ${THEME_BASES.join(\", \")}`);\n }\n if (input.name !== undefined) {\n if (typeof input.name !== \"string\" || input.name.length > MAX_NAME_LENGTH) {\n errors.push(`name: must be a string of at most ${MAX_NAME_LENGTH} characters`);\n }\n }\n\n if (input.seeds !== undefined) {\n walkLeaf(input.seeds, SEED_COLOR_KEYS, {}, \"seeds\", errors);\n if (isRecord(input.seeds)) {\n for (const key of REQUIRED_SEED_KEYS) {\n if (input.seeds[key] === undefined) errors.push(`seeds.${key}: required`);\n }\n }\n }\n\n // Any complete recipe works as the schema reference; base.light is as good as any.\n const reference = RECIPES.base.light;\n\n for (const mode of [\"light\", \"dark\"] as const) {\n const half = input[mode];\n if (half === undefined) continue;\n if (!isRecord(half)) {\n errors.push(`${mode}: must be an object`);\n continue;\n }\n for (const key of Object.keys(half)) {\n if (!(HALF_KEYS as readonly string[]).includes(key)) {\n errors.push(`${mode}.${key}: unknown field`);\n }\n }\n if (half.basemap !== undefined) walkBasemap(half.basemap, reference, `${mode}.basemap`, errors);\n if (half.marker !== undefined) {\n walkLeaf(half.marker, [\"color\"], MARKER_BOUNDS, `${mode}.marker`, errors);\n }\n if (half.route !== undefined) {\n walkLeaf(half.route, [\"color\", \"casingColor\"], ROUTE_BOUNDS, `${mode}.route`, errors);\n }\n }\n\n if (errors.length > 0) throw new ThemeError(\"invalid theme\", errors);\n if (base && base !== input.base) return { ...(input as unknown as ThemeDoc), base };\n return input as unknown as ThemeDoc;\n}\n","import type { ThemeDoc } from \"./doc\";\nimport type { ThemeBase } from \"./recipe\";\n\n/**\n * The shipped styles as starting-point themes: zero overrides, so each is guaranteed identical\n * to its `flavor=` twin (asserted in the gateway theme tests). The builder opens on these.\n *\n * Named after the style itself — `base`, `muted`, `outdoor`, `decimal`, `blueprint` — the same word the homepage, the\n * SDK's `style` option and the gateway URL use. The theme presets (`process ink`, `boreal`, …)\n * are a separate set layered on a style; a style never borrows one's name.\n */\nexport const STYLE_THEMES: Record<ThemeBase, ThemeDoc> = {\n base: { v: 1, name: \"base\", base: \"base\" },\n muted: { v: 1, name: \"muted\", base: \"muted\" },\n outdoor: { v: 1, name: \"outdoor\", base: \"outdoor\" },\n decimal: { v: 1, name: \"decimal\", base: \"decimal\" },\n blueprint: { v: 1, name: \"blueprint\", base: \"blueprint\" },\n};\n","/**\n * Minimal sRGB ↔ OKLCH conversion (Björn Ottosson's OKLab constants), plus a chroma-reducing\n * gamut map. Zero dependencies — the generator is the only consumer and needs exactly this.\n *\n * OKLCH is the working space for the same reason the hand-built ramps in `palette.ts` were\n * generated in it: perceived lightness is carried almost entirely by L, so a generator can swap\n * hue and chroma while *preserving a ramp's lightness ladder* — which is where the label\n * contrast the cartography tests enforce actually lives.\n */\n\nexport interface Oklch {\n /** Perceptual lightness, 0–1. */\n l: number;\n /** Chroma, 0 upward (~0.37 max for sRGB). */\n c: number;\n /** Hue in degrees, 0–360. */\n h: number;\n}\n\nconst srgbToLinear = (v: number) => (v <= 0.04045 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4);\nconst linearToSrgb = (v: number) =>\n v <= 0.0031308 ? 12.92 * v : 1.055 * v ** (1 / 2.4) - 0.055;\n\nfunction hexToRgb(hex: string): [number, number, number] {\n const h = hex.replace(\"#\", \"\");\n return [\n parseInt(h.slice(0, 2), 16) / 255,\n parseInt(h.slice(2, 4), 16) / 255,\n parseInt(h.slice(4, 6), 16) / 255,\n ];\n}\n\n/** Parse #RRGGBB (or #RRGGBBAA — alpha ignored) into OKLCH. */\nexport function hexToOklch(hex: string): Oklch {\n const [r, g, b] = hexToRgb(hex).map(srgbToLinear) as [number, number, number];\n const l = Math.cbrt(0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b);\n const m = Math.cbrt(0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b);\n const s = Math.cbrt(0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b);\n const L = 0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s;\n const a = 1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s;\n const bb = 0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s;\n const c = Math.hypot(a, bb);\n let h = (Math.atan2(bb, a) * 180) / Math.PI;\n if (h < 0) h += 360;\n return { l: L, c, h };\n}\n\n/** OKLCH → linear sRGB triple (possibly out of gamut). */\nfunction oklchToLinear({ l: L, c, h }: Oklch): [number, number, number] {\n const hr = (h * Math.PI) / 180;\n const a = c * Math.cos(hr);\n const bb = c * Math.sin(hr);\n const l = (L + 0.3963377774 * a + 0.2158037573 * bb) ** 3;\n const m = (L - 0.1055613458 * a - 0.0638541728 * bb) ** 3;\n const s = (L - 0.0894841775 * a - 1.291485548 * bb) ** 3;\n return [\n 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s,\n -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s,\n -0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s,\n ];\n}\n\nconst inGamut = (rgb: [number, number, number]) =>\n rgb.every((v) => v >= -1e-6 && v <= 1 + 1e-6);\n\n/**\n * OKLCH → #RRGGBB. Out-of-gamut colours are mapped by *reducing chroma* at constant L and h\n * (bisection), never by clipping channels — clipping shifts perceived lightness, and the whole\n * generator contract is that L is preserved.\n */\nexport function oklchToHex(color: Oklch): string {\n let { c } = color;\n let rgb = oklchToLinear({ ...color, c });\n if (!inGamut(rgb)) {\n let lo = 0;\n let hi = c;\n for (let i = 0; i < 24; i++) {\n c = (lo + hi) / 2;\n rgb = oklchToLinear({ ...color, c });\n if (inGamut(rgb)) lo = c;\n else hi = c;\n }\n rgb = oklchToLinear({ ...color, c: lo });\n }\n const to255 = (v: number) => Math.round(Math.min(1, Math.max(0, linearToSrgb(v))) * 255);\n return (\n \"#\" +\n rgb\n .map((v) => to255(v).toString(16).padStart(2, \"0\"))\n .join(\"\")\n .toUpperCase()\n );\n}\n","import type { Flavor } from \"@protomaps/basemaps\";\nimport { makeFlavor, type Recipe, type ThemeBase, type ThemeMode } from \"./recipe\";\nimport { RECIPES } from \"./recipes\";\nimport type { BasemapOverrides, MarkerTheme, RouteTheme, ThemeDoc } from \"./doc\";\n\n/**\n * Platform drawing defaults for the two client-side overlays a theme styles. These are exactly\n * the convention the unmap.dev hero has always drawn: a magenta pin, and a route as a solid\n * line over a wide translucent casing so it stays legible on light and dark cartography alike.\n */\nexport const DEFAULT_MARKER: Required<MarkerTheme> = { color: \"#FF3E9A\", scale: 1 };\nexport const DEFAULT_ROUTE: Required<RouteTheme> = {\n color: \"#FF3E9A\",\n width: 3,\n opacity: 1,\n casingColor: \"#FF3E9A\",\n casingWidth: 10,\n casingOpacity: 0.2,\n};\n\nexport interface ResolvedTheme {\n /** `<base>-<mode>`, the flavour name — what selects sprites and terrain behaviour. */\n flavorName: `${ThemeBase}-${ThemeMode}`;\n flavor: Flavor;\n marker: Required<MarkerTheme>;\n route: Required<RouteTheme>;\n}\n\n/**\n * Merge sparse overrides onto a base recipe, walking the base's own shape. Composing from the\n * base's keys (never spreading the override object) means an unexpected key cannot ride along\n * even if a caller skipped validation — defence in depth behind `validateTheme`.\n */\nexport function mergeRecipe(base: Recipe, overrides?: BasemapOverrides): Recipe {\n if (!overrides) return structuredClone(base);\n const walk = (ref: Record<string, unknown>, over: Record<string, unknown>) => {\n const out: Record<string, unknown> = {};\n for (const [key, refValue] of Object.entries(ref)) {\n const o = over[key];\n if (refValue !== null && typeof refValue === \"object\") {\n out[key] =\n o !== null && typeof o === \"object\" && !Array.isArray(o)\n ? walk(refValue as Record<string, unknown>, o as Record<string, unknown>)\n : structuredClone(refValue);\n } else {\n out[key] = typeof o === \"string\" ? o : refValue;\n }\n }\n return out;\n };\n return walk(\n base as unknown as Record<string, unknown>,\n overrides as Record<string, unknown>,\n ) as unknown as Recipe;\n}\n\n/**\n * Resolve one half of a theme into everything a renderer needs: the expanded Flavor, the\n * flavour name, and marker/route styles with defaults filled in.\n */\nexport function resolveTheme(doc: ThemeDoc, mode: ThemeMode): ResolvedTheme {\n const half = doc[mode] ?? {};\n const recipe = mergeRecipe(RECIPES[doc.base][mode], half.basemap);\n return {\n flavorName: `${doc.base}-${mode}`,\n flavor: makeFlavor(recipe),\n marker: { ...DEFAULT_MARKER, ...half.marker },\n route: { ...DEFAULT_ROUTE, ...half.route },\n };\n}\n","import type { Flavor } from \"@protomaps/basemaps\";\nimport { MODES, type ThemeMode } from \"./recipe\";\nimport type { ThemeDoc } from \"./doc\";\nimport { resolveTheme } from \"./compose\";\n\n/**\n * Label-contrast checks for theme documents — the same WCAG maths and label/background pairs\n * `apps/gateway/test/cartography.test.ts` enforces on unmap's own flavors, exported as a\n * library so the builder can warn live.\n *\n * Warn, not reject: the gateway holds its own flavors to these floors, but a custom theme is\n * the customer's canvas. The builder surfaces every breach; shipping one anyway is a choice.\n */\n\nfunction parseHex(hex: string): [number, number, number] {\n const h = hex.replace(\"#\", \"\");\n return [\n parseInt(h.slice(0, 2), 16),\n parseInt(h.slice(2, 4), 16),\n parseInt(h.slice(4, 6), 16),\n ];\n}\n\nfunction luminance(hex: string): number {\n const toLinear = (v: number) => {\n const c = v / 255;\n return c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;\n };\n const [r, g, b] = parseHex(hex);\n return 0.2126 * toLinear(r) + 0.7152 * toLinear(g) + 0.0722 * toLinear(b);\n}\n\n/** WCAG contrast ratio between two hex colours (1–21). */\nexport function contrast(a: string, b: string): number {\n const la = luminance(a);\n const lb = luminance(b);\n const [hi, lo] = la > lb ? [la, lb] : [lb, la];\n return (hi + 0.05) / (lo + 0.05);\n}\n\n/**\n * Halo colour is the effective background wherever a halo is set, because that is what the\n * glyph actually sits on. Where there is no halo slot (country labels), the label sits on the\n * land; ocean labels sit on water.\n */\nconst PRIMARY: Array<[keyof Flavor, keyof Flavor]> = [\n [\"city_label\", \"city_label_halo\"],\n [\"state_label\", \"state_label_halo\"],\n [\"country_label\", \"earth\"],\n [\"roads_label_major\", \"roads_label_major_halo\"],\n];\n\nconst SECONDARY: Array<[keyof Flavor, keyof Flavor]> = [\n [\"subplace_label\", \"subplace_label_halo\"],\n [\"address_label\", \"address_label_halo\"],\n [\"roads_label_minor\", \"roads_label_minor_halo\"],\n [\"ocean_label\", \"water\"],\n];\n\n/** Every enforced pair with its floor — the generator's contrast-clamp iterates these. */\nexport const LABEL_PAIRS: Array<[keyof Flavor, keyof Flavor, number]> = [\n ...PRIMARY.map(([l, b]) => [l, b, 4.5] as [keyof Flavor, keyof Flavor, number]),\n ...SECONDARY.map(([l, b]) => [l, b, 3] as [keyof Flavor, keyof Flavor, number]),\n];\n\nexport interface ContrastWarning {\n mode: ThemeMode;\n /** The Flavor label slot that breaches, e.g. \"city_label\". */\n label: string;\n /** The Flavor slot it was checked against, e.g. \"city_label_halo\". */\n background: string;\n ratio: number;\n /** 4.5 for primary labels, 3 for secondary. */\n floor: number;\n}\n\n/** Every label-contrast breach in the theme, across both modes. Empty means clean. */\nexport function contrastWarnings(doc: ThemeDoc): ContrastWarning[] {\n const warnings: ContrastWarning[] = [];\n for (const mode of MODES) {\n const flavor = resolveTheme(doc, mode).flavor as unknown as Record<string, string>;\n const check = (pairs: Array<[keyof Flavor, keyof Flavor]>, floor: number) => {\n for (const [label, background] of pairs) {\n const ratio = contrast(flavor[label as string]!, flavor[background as string]!);\n if (ratio < floor) {\n warnings.push({ mode, label: String(label), background: String(background), ratio, floor });\n }\n }\n };\n check(PRIMARY, 4.5);\n check(SECONDARY, 3);\n }\n return warnings;\n}\n","import { hexToOklch, oklchToHex } from \"./oklch\";\nimport { buildRecipes, RECIPES, STOCK_RAMPS, type RampSet } from \"./recipes\";\nimport { makeFlavor, MODES, type Recipe, type ThemeBase } from \"./recipe\";\nimport type { BasemapOverrides, ThemeDoc, ThemeSeeds } from \"./doc\";\nimport { contrast, LABEL_PAIRS } from \"./contrast\";\n\n/**\n * The simple-mode generator: three seed colours in, a full light + dark theme out.\n *\n * The trick is the one the hand-built ramps were made with. Each stock ramp is a *lightness\n * ladder* — its steps were solved so the label-contrast floors hold — and hue/chroma merely\n * carry identity. So the generator keeps every step's OKLCH lightness exactly, swaps in the\n * seed's hue, scales chroma to the seed's vividness, and rebuilds the recipes through the same\n * `buildRecipes` factory the shipped cartography uses. Casing/tunnel/bridge coherence and the\n * figure/ground relationships come along for free; the seeds only ever recolour.\n *\n * The output is a plain, valid ThemeDoc (sparse overrides + the seeds themselves), so nothing\n * downstream — codec, gateway, SDK — knows generation exists.\n */\n\n/** Neutrals must stay a cast, not a colour, or the whole map shouts. */\nconst NEUTRAL_CHROMA_CAP = 0.045;\n/** `muted` exists to vanish under data; its cast cap is a whisper of the normal one. */\nconst MUTED_CHROMA_CAP = 0.012;\n/** Ceiling for chromatic families (water, vegetation) before gamut mapping. */\nconst CHROMA_CAP = 0.32;\n/** Below this mid-step chroma a ramp is greyscale and is re-hued from the seed directly. */\nconst NEUTRAL_RAMP_CHROMA = 0.005;\n\n/** The seeds that reproduce (approximately) the stock cartography. Simple mode opens on these. */\nexport const DEFAULT_SEEDS: Required<ThemeSeeds> = {\n land: STOCK_RAMPS.ink[500],\n water: STOCK_RAMPS.wave[500],\n nature: STOCK_RAMPS.verdant[500],\n accent: \"#FF3E9A\",\n};\n\ntype Ramp = Record<string | number, string>;\n\n/**\n * Re-emit a ramp in the seed's hue: every step keeps its stock lightness, chroma scales by the\n * seed's vividness relative to the ramp's own mid-step, clamped to `cap`.\n */\nfunction reRamp<T extends Ramp>(ref: T, seedHex: string, cap: number): T {\n const seed = hexToOklch(seedHex);\n const steps = Object.keys(ref);\n const midStep = steps[Math.floor(steps.length / 2)]!;\n const midChroma = hexToOklch(ref[midStep]!).c;\n // A greyscale ramp (`graphite`, `mist`) has no chroma to scale, so it takes the seed's\n // chroma outright at every step; the cap still decides how much of it survives.\n const neutral = midChroma < NEUTRAL_RAMP_CHROMA;\n const factor = Math.min(Math.max(seed.c / Math.max(midChroma, 0.005), 0.15), 3);\n const out: Ramp = {};\n for (const step of steps) {\n const refColor = hexToOklch(ref[step]!);\n out[step] = oklchToHex({\n l: refColor.l,\n c: Math.min(neutral ? seed.c : refColor.c * factor, cap),\n h: seed.h,\n });\n }\n return out as T;\n}\n\n/**\n * Enforce the label floors on a generated flavor's recipe. Lightness is preserved from the\n * stock ladders, which pass with margin, but WCAG contrast is computed in sRGB luminance and a\n * strong hue shift can erode that margin — so each breaching label slot has its OKLCH lightness\n * nudged away from its background until the pair clears. Bounded and deterministic.\n */\nfunction enforceLabelContrast(recipe: Recipe): Recipe {\n const fixed = structuredClone(recipe);\n for (const [labelSlot, bgSlot, floor] of LABEL_PAIRS) {\n for (let i = 0; i < 40; i++) {\n const flavor = makeFlavor(fixed) as unknown as Record<string, string>;\n const label = flavor[labelSlot as string]!;\n const bg = flavor[bgSlot as string]!;\n if (contrast(label, bg) >= floor) break;\n const l = hexToOklch(label);\n const direction = hexToOklch(bg).l > l.l ? -1 : 1;\n const nudged = oklchToHex({\n ...l,\n l: Math.min(1, Math.max(0, l.l + direction * 0.015)),\n });\n setLabelSlot(fixed, labelSlot as string, nudged);\n }\n }\n return fixed;\n}\n\n/** Map a Flavor label slot back to its Recipe field. Only slots LABEL_PAIRS can name. */\nconst LABEL_SLOT_TO_RECIPE: Record<string, (r: Recipe, hex: string) => void> = {\n city_label: (r, v) => (r.labels.city = v),\n state_label: (r, v) => (r.labels.state = v),\n country_label: (r, v) => (r.labels.country = v),\n roads_label_major: (r, v) => (r.labels.roadMajor = v),\n subplace_label: (r, v) => (r.labels.subplace = v),\n address_label: (r, v) => (r.labels.address = v),\n roads_label_minor: (r, v) => (r.labels.roadMinor = v),\n ocean_label: (r, v) => (r.labels.ocean = v),\n};\n\nfunction setLabelSlot(recipe: Recipe, slot: string, hex: string): void {\n LABEL_SLOT_TO_RECIPE[slot]?.(recipe, hex);\n}\n\n/** Diff a generated recipe against the stock one into sparse overrides. */\nfunction diffRecipe(\n stock: Recipe,\n generated: Recipe,\n): BasemapOverrides | undefined {\n const walk = (a: Record<string, unknown>, b: Record<string, unknown>) => {\n const out: Record<string, unknown> = {};\n for (const [key, stockValue] of Object.entries(a)) {\n const genValue = b[key];\n if (stockValue !== null && typeof stockValue === \"object\") {\n const nested = walk(\n stockValue as Record<string, unknown>,\n (genValue ?? {}) as Record<string, unknown>,\n );\n if (Object.keys(nested).length > 0) out[key] = nested;\n } else if (typeof genValue === \"string\" && genValue !== stockValue) {\n out[key] = genValue;\n }\n }\n return out;\n };\n const diff = walk(\n stock as unknown as Record<string, unknown>,\n generated as unknown as Record<string, unknown>,\n );\n return Object.keys(diff).length > 0 ? (diff as BasemapOverrides) : undefined;\n}\n\n/**\n * Generate a full theme from seed colours. Deterministic; the result always clears the label\n * floors in both modes (enforced, and asserted by the hue-sweep test).\n *\n * Family mapping: `land` recolours the land spines — `ink`, `base`'s `paper`, `muted`'s\n * `graphite` at a whisper of chroma (that style exists to vanish under data), and the\n * single-hue families of `decimal` (`jade`) and `blueprint` (`cobalt`) at full chroma, so a\n * seed can carry them to any hue. `water` recolours the wave, sky, and mist ramps (`mist` is\n * greyscale in stock `muted` and takes the water seed's hue outright), `nature` the verdant\n * ramp. Warm landcover (sandstone), POI accents and white road fills stay stock: they\n * are tuned relationships, not identity. `accent` styles the marker and route overlays only —\n * it never enters the basemap, same rule as the brand magenta.\n */\nexport function generateTheme(base: ThemeBase, seeds: ThemeSeeds): ThemeDoc {\n const ramps: RampSet = {\n ...STOCK_RAMPS,\n ink: reRamp(STOCK_RAMPS.ink, seeds.land, NEUTRAL_CHROMA_CAP),\n paper: reRamp(STOCK_RAMPS.paper, seeds.land, NEUTRAL_CHROMA_CAP),\n graphite: reRamp(STOCK_RAMPS.graphite, seeds.land, MUTED_CHROMA_CAP),\n jade: reRamp(STOCK_RAMPS.jade, seeds.land, CHROMA_CAP),\n cobalt: reRamp(STOCK_RAMPS.cobalt, seeds.land, CHROMA_CAP),\n wave: reRamp(STOCK_RAMPS.wave, seeds.water, CHROMA_CAP),\n sky: reRamp(STOCK_RAMPS.sky, seeds.water, CHROMA_CAP),\n mist: reRamp(STOCK_RAMPS.mist, seeds.water, CHROMA_CAP),\n verdant: reRamp(STOCK_RAMPS.verdant, seeds.nature, CHROMA_CAP),\n };\n const generated = buildRecipes(ramps);\n\n const doc: ThemeDoc = { v: 1, base, seeds: { ...seeds } };\n for (const mode of MODES) {\n const recipe = enforceLabelContrast(generated[base][mode]);\n const basemap = diffRecipe(RECIPES[base][mode], recipe);\n const half: NonNullable<ThemeDoc[\"light\"]> = {};\n if (basemap) half.basemap = basemap;\n if (seeds.accent) {\n half.marker = { color: seeds.accent };\n half.route = { color: seeds.accent, casingColor: seeds.accent };\n }\n if (Object.keys(half).length > 0) doc[mode] = half;\n }\n return doc;\n}\n","import { oklchToHex } from \"./oklch\";\nimport type { ThemeSeeds } from \"./doc\";\nimport { DEFAULT_SEEDS } from \"./generate\";\n\n/**\n * The named theme presets of the builder's simple mode — the hand-picked starting points, named\n * for Canadian landscapes. Each is just a seed trio + accent; `generateTheme` does the rest,\n * and its contrast guarantee holds for these like any other seeds (asserted in tests).\n */\nexport interface ThemePreset {\n /** Display name, lowercase like the style names. Not translated — these are names. */\n name: string;\n seeds: Required<ThemeSeeds>;\n}\n\nexport const THEME_PRESETS: ThemePreset[] = [\n { name: \"process ink\", seeds: DEFAULT_SEEDS },\n {\n name: \"boreal\",\n seeds: { land: \"#7D8B87\", water: \"#33606B\", nature: \"#3F6B4F\", accent: \"#E4572E\" },\n },\n {\n name: \"prairie\",\n seeds: { land: \"#A08D6B\", water: \"#4E7E99\", nature: \"#7C8A4D\", accent: \"#C33149\" },\n },\n {\n name: \"tundra\",\n seeds: { land: \"#8B9AA6\", water: \"#4A7BA6\", nature: \"#6E8B74\", accent: \"#FF3E9A\" },\n },\n {\n name: \"badlands\",\n seeds: { land: \"#A67B5B\", water: \"#3E7C8F\", nature: \"#6B7F53\", accent: \"#22577A\" },\n },\n {\n name: \"aurora\",\n seeds: { land: \"#8C86A3\", water: \"#4F6D9E\", nature: \"#56828A\", accent: \"#58E1C1\" },\n },\n {\n name: \"pacific\",\n seeds: { land: \"#7F9089\", water: \"#2E7D74\", nature: \"#38755B\", accent: \"#F25F5C\" },\n },\n {\n name: \"chinook\",\n seeds: { land: \"#9C8A5D\", water: \"#56789C\", nature: \"#8A9A5B\", accent: \"#D95D39\" },\n },\n];\n\n/** Wrap a hue into [0, 360). */\nconst wrap = (h: number) => ((h % 360) + 360) % 360;\n\n/**\n * A random but *harmonic* seed trio — the shuffle button. Hues are related (water lands\n * cool-of-complementary, nature analogous-of-triadic, the accent opposes the land) and chroma\n * stays inside a tasteful band, so shuffles read as designed rather than random; the\n * generator's contrast guarantee makes every one of them legible regardless.\n *\n * `rng` is injectable (returns [0,1)) so tests can drive it deterministically.\n */\nexport function shuffleSeeds(rng: () => number = Math.random): Required<ThemeSeeds> {\n const h = rng() * 360;\n return {\n land: oklchToHex({ l: 0.55, c: 0.03 + rng() * 0.05, h }),\n water: oklchToHex({ l: 0.5, c: 0.08 + rng() * 0.1, h: wrap(h + 150 + rng() * 60) }),\n nature: oklchToHex({ l: 0.5, c: 0.06 + rng() * 0.08, h: wrap(h + 60 + rng() * 80) }),\n accent: oklchToHex({ l: 0.65, c: 0.22 + rng() * 0.08, h: wrap(h + 170 + rng() * 40) }),\n };\n}\n","import { ThemeError } from \"./validate\";\nimport type { ThemeBase } from \"./recipe\";\nimport { STYLE_THEMES } from \"./presets\";\nimport { THEME_PRESETS } from \"./palettes\";\nimport { DEFAULT_SEEDS, generateTheme } from \"./generate\";\nimport type { ThemeDoc, ThemeSeeds } from \"./doc\";\n\n/**\n * Short preset codes, the same idea as shadcn's `b0` / `a2r6bw`: a versioned base62 packing of\n * enumerated choices that starts at three characters and grows only when the theme leaves the\n * curated set.\n *\n * u00, u01, u04 living styles from the original lineup (base, muted, outdoor)\n * u02, u03 retired styles (relief → outdoor, street → base)\n * u05, u06 styles added later (decimal, blueprint); u07 is the one spare slot\n * u08… named theme preset on one of the original style slots\n * u5K… named theme preset on one of the later slots\n * longer custom seed colours (4× RGB) on any style\n *\n * Advanced overrides — anything `generateTheme` would not emit — still use the `ut1.` deflate\n * document. `ut1.` is checked first on decode so an existing customer code never collides.\n *\n * Slot numbers are permanent once a code is published, which is why the layout below is a set\n * of appended regions rather than one formula: every code ever printed keeps decoding.\n */\n\nexport const PRESET_CODE_PREFIX = \"u\";\nexport const PRESET_CODE_RE = /^u[0-9A-Za-z]{2,24}$/;\n\nconst BASE62 = \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\";\nconst SEED_KEYS = [\"land\", \"water\", \"nature\", \"accent\"] as const;\n\n/** Encode slot per living style. 2 and 3 are retired, 7 is spare; 3 bits in a custom code. */\nconst STYLE_ENCODE: Record<ThemeBase, number> = {\n base: 0,\n muted: 1,\n outdoor: 4,\n decimal: 5,\n blueprint: 6,\n};\n/** Decode table for all eight slots. 2 was relief, 3 was street. */\nconst STYLE_DECODE: Array<ThemeBase | undefined> = [\n \"base\",\n \"muted\",\n \"outdoor\",\n \"base\",\n \"outdoor\",\n \"decimal\",\n \"blueprint\",\n undefined,\n];\n\n/*\n * Region layout, in code value (`u` + base62 of this number):\n *\n * 0 … 7 a bare style: the slot number\n * 8 … 327 preset p on an original slot s (0–4): 8 + p·5 + s (p < 64)\n * 328 … 1023 preset p on a later slot s (5–7): 328 + p·3 + (s−5) (p < 232)\n * 1024 … custom seeds on slot s: 1024 + s + rgb₄ << 3\n *\n * The original preset region was laid out before the later slots existed, with five slots per\n * preset; the later region is appended after it rather than widening it, so every `u0D`-style\n * code already in the wild keeps its meaning.\n */\nconst PRESET_OFFSET = 8n;\nconst ORIGINAL_SLOTS = 5n;\nconst ORIGINAL_PRESET_LIMIT = 64n;\nconst LATER_PRESET_OFFSET = PRESET_OFFSET + ORIGINAL_PRESET_LIMIT * ORIGINAL_SLOTS; // 328\nconst LATER_SLOT_BASE = 5;\nconst LATER_SLOTS = 3n;\n/** Anything at or above this is a packed custom-seed theme. */\nconst CUSTOM_OFFSET = 1024n;\nconst LATER_PRESET_LIMIT = (CUSTOM_OFFSET - LATER_PRESET_OFFSET) / LATER_SLOTS; // 232\n\nconst sameHex = (a: string, b: string) => a.toLowerCase() === b.toLowerCase();\n\nexport function isThemePresetCode(code: string): boolean {\n return PRESET_CODE_RE.test(code);\n}\n\n/** Registry key for a preset name: `process ink` → `processInk`. */\nexport function presetId(name: string): string {\n return name.replace(/\\s+([a-zA-Z])/g, (_, c: string) => c.toUpperCase()).replace(/\\s/g, \"\");\n}\n\nfunction toBase62(n: bigint, min = 2): string {\n if (n === 0n) return \"0\".repeat(min);\n let s = \"\";\n let x = n;\n while (x > 0n) {\n s = BASE62[Number(x % 62n)] + s;\n x /= 62n;\n }\n return s.padStart(min, \"0\");\n}\n\nfunction fromBase62(s: string): bigint {\n let n = 0n;\n for (const ch of s) {\n const i = BASE62.indexOf(ch);\n if (i < 0) {\n throw new ThemeError(\"invalid theme\", [\"code is not a valid preset\"]);\n }\n n = n * 62n + BigInt(i);\n }\n return n;\n}\n\nfunction rgb24(hex: string): bigint {\n return BigInt(parseInt(hex.replace(\"#\", \"\").slice(0, 6), 16));\n}\n\nfunction fromRgb24(n: bigint): string {\n return `#${n.toString(16).toUpperCase().padStart(6, \"0\")}`;\n}\n\n/** A bare style: no seeds, no overrides in either half. */\nfunction isBareStyle(doc: ThemeDoc): boolean {\n return doc.seeds === undefined && doc.light === undefined && doc.dark === undefined;\n}\n\nfunction deepEqual(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n if (typeof a !== typeof b) return false;\n if (a && b && typeof a === \"object\") {\n const ak = Object.keys(a as object).sort();\n const bk = Object.keys(b as object).sort();\n return ak.length === bk.length && ak.every((k, i) => k === bk[i] && deepEqual((a as Record<string, unknown>)[k], (b as Record<string, unknown>)[k]));\n }\n return false;\n}\n\nfunction seedsMatch(a: ThemeSeeds, b: ThemeSeeds): boolean {\n return SEED_KEYS.every((k) => {\n const left = a[k];\n const right = b[k];\n if (left === undefined && right === undefined) return true;\n if (typeof left !== \"string\" || typeof right !== \"string\") return left === right;\n return sameHex(left, right);\n });\n}\n\nfunction generatedMatch(doc: ThemeDoc): boolean {\n if (!doc.seeds) return false;\n const generated = generateTheme(doc.base, doc.seeds);\n return (\n generated.base === doc.base &&\n seedsMatch(generated.seeds!, doc.seeds) &&\n deepEqual(generated.light, doc.light) &&\n deepEqual(generated.dark, doc.dark)\n );\n}\n\nfunction findPresetIndex(seeds: ThemeSeeds): number {\n return THEME_PRESETS.findIndex((p) => seedsMatch(p.seeds, { ...DEFAULT_SEEDS, ...seeds }));\n}\n\nfunction encodeBits(bits: bigint): string {\n return PRESET_CODE_PREFIX + toBase62(bits);\n}\n\n/**\n * Pack a theme into a short preset code, or `null` when the document is not one of the\n * representable shapes (caller falls back to `ut1.`).\n */\nexport function encodePreset(doc: ThemeDoc): string | null {\n const slot = STYLE_ENCODE[doc.base];\n if (slot === undefined) return null;\n\n if (isBareStyle(doc)) {\n return encodeBits(BigInt(slot));\n }\n\n if (!doc.seeds || !generatedMatch(doc)) return null;\n\n const presetIndex = findPresetIndex(doc.seeds);\n if (presetIndex >= 0) {\n const p = BigInt(presetIndex);\n if (slot < LATER_SLOT_BASE) {\n if (p < ORIGINAL_PRESET_LIMIT) {\n return encodeBits(PRESET_OFFSET + p * ORIGINAL_SLOTS + BigInt(slot));\n }\n } else if (p < LATER_PRESET_LIMIT) {\n return encodeBits(LATER_PRESET_OFFSET + p * LATER_SLOTS + BigInt(slot - LATER_SLOT_BASE));\n }\n // A preset past the region's limit still encodes, as its seeds.\n }\n\n if (!doc.seeds.accent) return null;\n const filled: Required<ThemeSeeds> = { ...DEFAULT_SEEDS, ...doc.seeds };\n let bits = CUSTOM_OFFSET + BigInt(slot);\n let shift = 3n;\n for (const key of SEED_KEYS) {\n bits += rgb24(filled[key]) << shift;\n shift += 24n;\n }\n return encodeBits(bits);\n}\n\n/** Expand a short preset code to a validated ThemeDoc. Throws `ThemeError`. */\nexport function decodePreset(code: string): ThemeDoc {\n if (!isThemePresetCode(code)) {\n throw new ThemeError(\"invalid theme\", [\"code is not a valid preset\"]);\n }\n const bits = fromBase62(code.slice(PRESET_CODE_PREFIX.length));\n\n if (bits < PRESET_OFFSET) {\n const base = STYLE_DECODE[Number(bits)];\n if (!base) {\n throw new ThemeError(\"invalid theme\", [\"preset style slot is out of range\"]);\n }\n return structuredClone(STYLE_THEMES[base]);\n }\n\n if (bits < CUSTOM_OFFSET) {\n let slot: number;\n let presetIndex: number;\n if (bits < LATER_PRESET_OFFSET) {\n const n = bits - PRESET_OFFSET;\n slot = Number(n % ORIGINAL_SLOTS);\n presetIndex = Number(n / ORIGINAL_SLOTS);\n } else {\n const n = bits - LATER_PRESET_OFFSET;\n slot = LATER_SLOT_BASE + Number(n % LATER_SLOTS);\n presetIndex = Number(n / LATER_SLOTS);\n }\n const base = STYLE_DECODE[slot];\n const preset = THEME_PRESETS[presetIndex];\n if (!base || !preset) {\n throw new ThemeError(\"invalid theme\", [\"preset is out of range\"]);\n }\n return generateTheme(base, preset.seeds);\n }\n\n const payload = bits - CUSTOM_OFFSET;\n const base = STYLE_DECODE[Number(payload & 7n)];\n if (!base) {\n throw new ThemeError(\"invalid theme\", [\"preset style slot is out of range\"]);\n }\n let rest = payload >> 3n;\n const seeds: Required<ThemeSeeds> = { ...DEFAULT_SEEDS };\n for (const key of SEED_KEYS) {\n seeds[key] = fromRgb24(rest & 0xffffffn);\n rest >>= 24n;\n }\n if (rest !== 0n) {\n throw new ThemeError(\"invalid theme\", [\"preset payload has unused bits\"]);\n }\n return generateTheme(base, seeds);\n}\n\n/**\n * Registry key for a curated preset (`base`, `processInk`, `boreal`, …), or `undefined` when\n * the theme is a custom code that is not one of the named `MAP_THEMES` entries (named presets\n * are published on the `base` style only).\n */\nexport function registryThemeKey(doc: ThemeDoc): string | undefined {\n if (isBareStyle(doc)) return STYLE_THEMES[doc.base]?.name;\n if (!doc.seeds || doc.base !== \"base\" || !generatedMatch(doc)) return undefined;\n const presetIndex = findPresetIndex(doc.seeds);\n if (presetIndex < 0) return undefined;\n return presetId(THEME_PRESETS[presetIndex]!.name);\n}\n","import { ThemeError, validateTheme } from \"./validate\";\nimport type { ThemeDoc } from \"./doc\";\nimport { decodePreset, encodePreset, isThemePresetCode } from \"./preset\";\n\n/**\n * The compact theme code: `ut1.` + base64url(deflate(minified JSON)).\n *\n * Web-standard streams only (CompressionStream/DecompressionStream, Blob, btoa/atob) so the\n * same module runs in Workers, browsers and Node 18+. `deflate` (zlib) rather than\n * `deflate-raw`, which Node 20 — the repo floor — does not implement; the wrapper costs six\n * bytes and buys a checksum.\n *\n * `ut1` is the wire version. Bump it only for a breaking change, and keep decoding old\n * prefixes forever: codes get hardcoded into customers' pages.\n */\n\nexport const THEME_CODE_PREFIX = \"ut1.\";\nexport const MAX_CODE_LENGTH = 4096;\nconst MAX_JSON_BYTES = 16 * 1024;\n\n/** Drain a stream into one buffer, refusing to grow past `cap` (the zip-bomb guard). */\nasync function pump(stream: ReadableStream<Uint8Array>, cap: number): Promise<Uint8Array> {\n const reader = stream.getReader();\n const chunks: Uint8Array[] = [];\n let size = 0;\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n size += value.byteLength;\n if (size > cap) {\n // Cancelling releases the underlying decompressor before we throw.\n await reader.cancel().catch(() => {});\n throw new ThemeError(\"invalid theme\", [\"theme document too large\"]);\n }\n chunks.push(value);\n }\n const out = new Uint8Array(size);\n let off = 0;\n for (const c of chunks) {\n out.set(c, off);\n off += c.byteLength;\n }\n return out;\n}\n\nconst toB64url = (b: Uint8Array): string => {\n let bin = \"\";\n // Chunked: String.fromCharCode(...whole) overflows the argument limit on large arrays.\n for (let i = 0; i < b.length; i += 0x8000) {\n bin += String.fromCharCode(...b.subarray(i, i + 0x8000));\n }\n return btoa(bin).replaceAll(\"+\", \"-\").replaceAll(\"/\", \"_\").replace(/=+$/, \"\");\n};\n\nconst fromB64url = (s: string): Uint8Array => {\n const bin = atob(s.replaceAll(\"-\", \"+\").replaceAll(\"_\", \"/\"));\n return Uint8Array.from(bin, (c) => c.charCodeAt(0));\n};\n\nasync function through(\n bytes: Uint8Array,\n transform: CompressionStream | DecompressionStream,\n cap: number,\n): Promise<Uint8Array> {\n const stream = new Blob([bytes as BlobPart]).stream().pipeThrough(transform);\n return pump(stream, cap);\n}\n\n/** Validate and encode a theme document. Curated/simple themes become a short `u…` preset; anything else is `ut1.` + deflate. Throws `ThemeError`. */\nexport async function encodeTheme(doc: ThemeDoc): Promise<string> {\n const valid = validateTheme(doc);\n const preset = encodePreset(valid);\n if (preset) return preset;\n const json = new TextEncoder().encode(JSON.stringify(valid));\n const packed = await through(json, new CompressionStream(\"deflate\"), Number.POSITIVE_INFINITY);\n const code = THEME_CODE_PREFIX + toB64url(packed);\n if (code.length > MAX_CODE_LENGTH) {\n throw new ThemeError(\"invalid theme\", [\n `encoded theme exceeds ${MAX_CODE_LENGTH} characters`,\n ]);\n }\n return code;\n}\n\n/** Decode and validate a compact theme code (`u…` preset or `ut1.` document). Every failure lands as `ThemeError`. */\nexport async function decodeTheme(code: string): Promise<ThemeDoc> {\n if (code.length > MAX_CODE_LENGTH) {\n throw new ThemeError(\"invalid theme\", [`code exceeds ${MAX_CODE_LENGTH} characters`]);\n }\n if (code.startsWith(THEME_CODE_PREFIX)) {\n return decodeDeflate(code);\n }\n if (isThemePresetCode(code)) {\n return validateTheme(decodePreset(code));\n }\n throw new ThemeError(\"invalid theme\", [\n `code must start with \"${THEME_CODE_PREFIX}\" or be a short preset`,\n ]);\n}\n\nasync function decodeDeflate(code: string): Promise<ThemeDoc> {\n let bytes: Uint8Array;\n try {\n const packed = fromB64url(code.slice(THEME_CODE_PREFIX.length));\n bytes = await through(packed, new DecompressionStream(\"deflate\"), MAX_JSON_BYTES);\n } catch (e) {\n if (e instanceof ThemeError) throw e;\n throw new ThemeError(\"invalid theme\", [\"code is not valid base64url deflate data\"]);\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(new TextDecoder().decode(bytes));\n } catch {\n throw new ThemeError(\"invalid theme\", [\"decoded payload is not JSON\"]);\n }\n return validateTheme(parsed);\n}\n"],"mappings":"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","names":["base"]}
|