@unmap/themes 0.0.1

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.
@@ -0,0 +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":[]}
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@unmap/themes",
3
+ "version": "0.0.1",
4
+ "description": "unmap theme documents: types, recipes, validation, codec (data-only map themes)",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "sideEffects": false,
19
+ "publishConfig": {
20
+ "access": "public"
21
+ },
22
+ "dependencies": {
23
+ "@protomaps/basemaps": "^5.7.0"
24
+ },
25
+ "devDependencies": {
26
+ "tsup": "^8.3.0",
27
+ "typescript": "^5.6.0",
28
+ "vitest": "^2.1.0"
29
+ },
30
+ "scripts": {
31
+ "build": "tsup",
32
+ "test": "vitest run",
33
+ "typecheck": "tsc --noEmit",
34
+ "preset-codes": "node scripts/preset-codes.mjs"
35
+ }
36
+ }