@unmap/themes 0.7.0 → 0.9.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/README.md CHANGED
@@ -20,7 +20,7 @@ import { encodeTheme, decodeTheme, validateTheme, ThemeError } from '@unmap/them
20
20
  const code = await encodeTheme({
21
21
  v: 1,
22
22
  name: 'copper',
23
- base: 'outdoor', // base | muted | outdoor | decimal | blueprint | blush | orchid | canopy | lagoon
23
+ base: 'outdoor', // base | muted | outdoor | blueprint | blush | orchid | canopy | lagoon | tropic | sunset | bold | pastel
24
24
  light: { basemap: { water: '#9CCFD2' }, route: { color: '#B85C00', width: 4 } },
25
25
  dark: { basemap: { water: '#12303A' }, route: { color: '#FFA24D', width: 4 } },
26
26
  })
@@ -31,7 +31,7 @@ const doc = await decodeTheme(code) // validated ThemeDoc, or th
31
31
 
32
32
  ## What is in a theme
33
33
 
34
- - `base` picks the style: `base`, `muted`, `outdoor`, `decimal`, `blueprint`, `blush`, `orchid`, `canopy` or `lagoon`. Each of `light` and `dark` carries
34
+ - `base` picks the style: `base`, `muted`, `outdoor`, `blueprint`, `blush`, `orchid`, `canopy`, `lagoon`, `tropic`, `sunset`, `bold` or `pastel`. Each of `light` and `dark` carries
35
35
  sparse overrides on that style, so a theme with no overrides renders exactly like its
36
36
  `flavor=` twin.
37
37
  - `basemap` overrides are colours on the style's recipe (land, water, vegetation, roads, labels,
package/dist/index.d.ts CHANGED
@@ -108,6 +108,25 @@ declare const verdant: {
108
108
  readonly 800: "#1E4128";
109
109
  readonly 900: "#0B2815";
110
110
  };
111
+ /**
112
+ * Leaf green, hue 136: `outdoor`'s vegetation (2026-09-09). `verdant` is a mint that reads cool
113
+ * and flat once it has to stand for a forest rather than a city park; the outdoor maps people
114
+ * already read use a yellower, fuller green. Generated from verdant's own lightness step for
115
+ * step (chroma ×1.6, capped at 0.14 to stay in gamut), so every contrast property the ramps were
116
+ * solved for carries over and only the hue and chroma move. Outdoor alone; the street styles
117
+ * keep verdant, where a park is a tint and a mint is right.
118
+ */
119
+ declare const fern: {
120
+ readonly 100: "#D3F3C5";
121
+ readonly 200: "#C3E6B3";
122
+ readonly 300: "#AFD59E";
123
+ readonly 400: "#96BF83";
124
+ readonly 500: "#76A560";
125
+ readonly 600: "#518535";
126
+ readonly 700: "#37621E";
127
+ readonly 800: "#1E4305";
128
+ readonly 900: "#0F2900";
129
+ };
111
130
  /** Warm landcover, hue 82: sand, beach, farmland. */
112
131
  declare const sandstone: {
113
132
  readonly 100: "#F5E8D0";
@@ -258,6 +277,92 @@ declare const aqua: {
258
277
  readonly 950: "#081B1D";
259
278
  readonly 980: "#060E0F";
260
279
  };
280
+ /** Cream neutrals, hue 90, chroma 0.022: `tropic`'s and `sunset`'s land and labels. `paper`'s ladder. */
281
+ declare const linen: {
282
+ readonly 25: "#FCF6E6";
283
+ readonly 50: "#F6F0E0";
284
+ readonly 100: "#EDE7D7";
285
+ readonly 200: "#E2DCCC";
286
+ readonly 300: "#D5CFC0";
287
+ readonly 400: "#C4BEAF";
288
+ readonly 500: "#AAA495";
289
+ readonly 600: "#8B8677";
290
+ readonly 700: "#696457";
291
+ readonly 800: "#4B4639";
292
+ readonly 850: "#383427";
293
+ readonly 900: "#272317";
294
+ readonly 950: "#1B170B";
295
+ readonly 1000: "#0F0B03";
296
+ };
297
+ /** Coral, hue 28, on `rose`'s ladder at 1.3× its chroma: the highway on `tropic`, `sunset` and `pastel`. */
298
+ declare const coral: {
299
+ readonly 25: "#FFF3F1";
300
+ readonly 50: "#FFEBE8";
301
+ readonly 100: "#FFDFDB";
302
+ readonly 200: "#FFCFC8";
303
+ readonly 300: "#FFBDB3";
304
+ readonly 400: "#FFA195";
305
+ readonly 500: "#F47C6E";
306
+ readonly 600: "#C76559";
307
+ readonly 700: "#974A42";
308
+ readonly 800: "#6C332D";
309
+ readonly 850: "#512520";
310
+ readonly 900: "#391814";
311
+ readonly 950: "#270F0C";
312
+ readonly 1000: "#170705";
313
+ };
314
+ /** Peach, hue 58, on `verdant`'s ladder: `sunset`'s vegetation, which is not green on purpose. */
315
+ declare const peach: {
316
+ readonly 100: "#FFE2CC";
317
+ readonly 200: "#FFCEAA";
318
+ readonly 300: "#F4B98D";
319
+ readonly 400: "#E0A171";
320
+ readonly 500: "#CA8248";
321
+ readonly 600: "#AC5E0D";
322
+ readonly 700: "#804300";
323
+ readonly 800: "#572B00";
324
+ readonly 900: "#361900";
325
+ };
326
+ /** Indigo, hue 295, on `cobalt`'s ladder at 0.7× its chroma: `sunset`'s water and night, and the boundary purple elsewhere. */
327
+ declare const indigo: {
328
+ readonly 25: "#F7F6F9";
329
+ readonly 50: "#F0EFF6";
330
+ readonly 100: "#E8E6F1";
331
+ readonly 200: "#DDD9EC";
332
+ readonly 300: "#D0CBE6";
333
+ readonly 400: "#C0B8DE";
334
+ readonly 500: "#A89BD3";
335
+ readonly 600: "#8B76C5";
336
+ readonly 700: "#6D4BB5";
337
+ readonly 800: "#4B3977";
338
+ readonly 850: "#362C53";
339
+ readonly 900: "#251F36";
340
+ readonly 950: "#181422";
341
+ readonly 1000: "#0C0A11";
342
+ };
343
+ /** Azure, hue 245, on `wave`'s ladder at 1.7× its chroma: `bold`'s clear blue water. */
344
+ declare const azure: {
345
+ readonly 100: "#D4EBFF";
346
+ readonly 200: "#B6DDFF";
347
+ readonly 300: "#92CBFB";
348
+ readonly 400: "#74B3E8";
349
+ readonly 500: "#5299D2";
350
+ readonly 600: "#227AB9";
351
+ readonly 700: "#005B91";
352
+ readonly 800: "#003D64";
353
+ readonly 900: "#002641";
354
+ readonly 950: "#00192D";
355
+ readonly 980: "#000E1C";
356
+ };
357
+ /** Amber, hue 85, on `ember`'s ladder: `bold`'s highway. */
358
+ declare const amber: {
359
+ readonly 200: "#FEEAC1";
360
+ readonly 300: "#F3C96F";
361
+ readonly 400: "#E7AF0E";
362
+ readonly 500: "#C99700";
363
+ readonly 600: "#C19100";
364
+ readonly 700: "#916D00";
365
+ };
261
366
 
262
367
  /**
263
368
  * The unmap cartography authoring surface, moved here from apps/gateway/src/flavors.ts so the
@@ -273,10 +378,11 @@ declare const aqua: {
273
378
  * the unmap.dev builder, so inserting a style mid-array silently reorders a control people have
274
379
  * already learned.
275
380
  *
276
- * `relief` and `street` were retired; they are not listed here. Short preset codes still
277
- * decode those slots via `normalizeThemeBase` / the slot table in `preset.ts`.
381
+ * `relief`, `street` and `decimal` were retired; they are not listed here. Short preset codes
382
+ * still decode those slots via `normalizeThemeBase` / the slot table in `preset.ts`. `decimal`
383
+ * (2026-09-09) maps onto `blueprint`: the two single-hue styles read as the same map.
278
384
  */
279
- declare const THEME_BASES: readonly ["base", "muted", "outdoor", "decimal", "blueprint", "blush", "orchid", "canopy", "lagoon"];
385
+ declare const THEME_BASES: readonly ["base", "muted", "outdoor", "blueprint", "blush", "orchid", "canopy", "lagoon", "tropic", "sunset", "bold", "pastel"];
280
386
  type ThemeBase = (typeof THEME_BASES)[number];
281
387
  /** Map a theme `base` — living or retired — onto a shipped style. `null` if unknown. */
282
388
  declare function normalizeThemeBase(base: string): ThemeBase | null;
@@ -371,6 +477,7 @@ interface RampSet {
371
477
  wave: typeof wave;
372
478
  sky: typeof sky;
373
479
  verdant: typeof verdant;
480
+ fern: typeof fern;
374
481
  sandstone: typeof sandstone;
375
482
  graphite: typeof graphite;
376
483
  mist: typeof mist;
@@ -380,6 +487,12 @@ interface RampSet {
380
487
  lilac: typeof lilac;
381
488
  aqua: typeof aqua;
382
489
  ember: typeof ember;
490
+ linen: typeof linen;
491
+ coral: typeof coral;
492
+ peach: typeof peach;
493
+ indigo: typeof indigo;
494
+ azure: typeof azure;
495
+ amber: typeof amber;
383
496
  }
384
497
  declare const STOCK_RAMPS: RampSet;
385
498
  /** Build the shipped recipes from a ramp set. Stock ramps in → the shipped cartography out. */
@@ -522,8 +635,10 @@ declare function decodeTheme(code: string): Promise<ThemeDoc>;
522
635
  * enumerated choices that starts at three characters and grows only when the theme leaves the
523
636
  * curated set.
524
637
  *
525
- * u00 … u08 the nine styles, in lineup order
526
- * u0W, u4e, … a named theme preset on a style (three characters for every pair)
638
+ * u00 … u0C the style slots, in lineup order (`u03` was `decimal`, retired 2026-09-09;
639
+ * it decodes to `blueprint`, and `blueprint` still encodes as `u04`)
640
+ * u0W, u4e, … a named theme preset on a style (three characters for every pair, which
641
+ * holds for up to fifteen presets; the sixteenth would take four)
527
642
  * six to eight a style or preset with layer groups hidden or reordered
528
643
  * up to 23 custom seed colours (4× RGB) on any style, layers included
529
644
  *
@@ -663,7 +778,7 @@ declare function contrastWarnings(doc: ThemeDoc): ContrastWarning[];
663
778
  * The shipped styles as starting-point themes: zero overrides, so each is guaranteed identical
664
779
  * to its `flavor=` twin (asserted in the gateway theme tests). The builder opens on these.
665
780
  *
666
- * Named after the style itself — `base`, `muted`, `outdoor`, `decimal`, `blueprint`, `blush`, … — the same word the homepage, the
781
+ * Named after the style itself — `base`, `muted`, `outdoor`, `blueprint`, `blush`, … — the same word the homepage, the
667
782
  * SDK's `style` option and the gateway URL use. The theme presets (`process ink`, `boreal`, …)
668
783
  * are a separate set layered on a style; a style never borrows one's name.
669
784
  */
@@ -703,11 +818,12 @@ declare const DEFAULT_SEEDS: Required<ThemeSeeds>;
703
818
  *
704
819
  * Family mapping: `land` recolours the land spines — `ink`, `base`'s `paper`, `muted`'s
705
820
  * `graphite` at a whisper of chroma (that style exists to vanish under data), and the
706
- * single-hue families of `decimal` (`jade`) and `blueprint` (`cobalt`) at full chroma, so a
707
- * seed can carry them to any hue, plus `blush`'s `rose` and `orchid`'s `lilac`. `nature`
708
- * recolours `verdant` and the teal `aqua` of `orchid` and `lagoon`. `water` recolours the wave, sky, and mist ramps (`mist` is
821
+ * single-hue family of `blueprint` (`cobalt`) at full chroma (and `jade`, which `orchid` and `lagoon` borrow), so a
822
+ * seed can carry them to any hue, plus `blush`'s `rose`, `orchid`'s `lilac`, the cream `linen` of
823
+ * `tropic` and `sunset`, and `sunset`'s `indigo`. `nature` recolours `verdant`, `sunset`'s `peach`
824
+ * and the teal `aqua` of `orchid` and `lagoon`. `water` recolours the wave, sky, azure and mist ramps (`mist` is
709
825
  * greyscale in stock `muted` and takes the water seed's hue outright), `nature` the verdant
710
- * ramp. Warm landcover (sandstone), POI accents and white road fills stay stock: they
826
+ * ramp. Warm landcover (sandstone), the highway ramps (ember, coral, amber), POI accents and white road fills stay stock: they
711
827
  * are tuned relationships, not identity. `accent` styles the marker and route overlays only —
712
828
  * it never enters the basemap, same rule as the brand magenta.
713
829
  */
@@ -734,4 +850,19 @@ declare const THEME_PRESETS: ThemePreset[];
734
850
  */
735
851
  declare function shuffleSeeds(rng?: () => number): Required<ThemeSeeds>;
736
852
 
737
- export { BUILDINGS_3D_LAYER_ID, type BasemapOverrides, type ContrastWarning, DEFAULT_LAYER_VISIBILITY, DEFAULT_MARKER, DEFAULT_ROUTE, DEFAULT_SEEDS, type DeepPartial, LABEL_PAIRS, LAYER_GROUPS, type LabelRamp, type LayerGroup, MAX_CODE_LENGTH, MODES, type MarkerTheme, type Oklch, PRESET_CODE_PREFIX, PRESET_CODE_RE, RECIPES, type RampSet, type Recipe, type ResolvedTheme, type RoadRamp, type RouteTheme, STOCK_RAMPS, STYLE_THEMES, THEME_BASES, THEME_CODE_PREFIX, THEME_PRESETS, type ThemeBase, type ThemeDoc, ThemeError, type ThemeHalf, type ThemeLayers, type ThemeMode, type ThemePreset, type ThemeSeeds, applyThemeLayers, aqua, buildRecipes, cobalt, contrast, contrastWarnings, decodePreset, decodeTheme, effectiveLayerOrder, ember, encodePreset, encodeTheme, generateTheme, graphite, hexToOklch, ink, isLayerVisible, isStockLayerOrder, isStockLayers, isThemePresetCode, jade, layerGroupOf, lilac, makeFlavor, mergeRecipe, mist, normalizeThemeBase, oklchToHex, paper, presetId, registryThemeKey, resolveTheme, rose, sandstone, shuffleSeeds, sky, validateTheme, verdant, wave };
853
+ /**
854
+ * Map an extracted image palette onto the four simple-mode seeds. Deterministic: the same
855
+ * colours always produce the same seeds, and `generateTheme` then carries the contrast
856
+ * guarantee. Lightness on land/water/nature is display-only (the generator re-hues stock
857
+ * ladders); accent is used verbatim for the marker and route.
858
+ */
859
+ interface PaletteColor {
860
+ hex: string;
861
+ proportion: number;
862
+ }
863
+ /**
864
+ * Brand colours in, the four simple-mode seeds out. Empty input falls back to the stock seeds.
865
+ */
866
+ declare function seedsFromPalette(colors: PaletteColor[]): Required<ThemeSeeds>;
867
+
868
+ export { BUILDINGS_3D_LAYER_ID, type BasemapOverrides, type ContrastWarning, DEFAULT_LAYER_VISIBILITY, DEFAULT_MARKER, DEFAULT_ROUTE, DEFAULT_SEEDS, type DeepPartial, LABEL_PAIRS, LAYER_GROUPS, type LabelRamp, type LayerGroup, MAX_CODE_LENGTH, MODES, type MarkerTheme, type Oklch, PRESET_CODE_PREFIX, PRESET_CODE_RE, type PaletteColor, RECIPES, type RampSet, type Recipe, type ResolvedTheme, type RoadRamp, type RouteTheme, STOCK_RAMPS, STYLE_THEMES, THEME_BASES, THEME_CODE_PREFIX, THEME_PRESETS, type ThemeBase, type ThemeDoc, ThemeError, type ThemeHalf, type ThemeLayers, type ThemeMode, type ThemePreset, type ThemeSeeds, amber, applyThemeLayers, aqua, azure, buildRecipes, cobalt, contrast, contrastWarnings, coral, decodePreset, decodeTheme, effectiveLayerOrder, ember, encodePreset, encodeTheme, fern, generateTheme, graphite, hexToOklch, indigo, ink, isLayerVisible, isStockLayerOrder, isStockLayers, isThemePresetCode, jade, layerGroupOf, lilac, linen, makeFlavor, mergeRecipe, mist, normalizeThemeBase, oklchToHex, paper, peach, presetId, registryThemeKey, resolveTheme, rose, sandstone, seedsFromPalette, shuffleSeeds, sky, validateTheme, verdant, wave };