@tileflow/core 0.1.0-alpha.29 → 0.1.0-alpha.30

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.
@@ -189,9 +189,26 @@ type TileflowTextPaint = {
189
189
  haloWidth?: TileflowNumberStyleValue;
190
190
  opacity?: TileflowNumberStyleValue;
191
191
  };
192
+ /**
193
+ * One opaque strip behind each shaped line of a label. Tileflow lowers it to a derived glyph stack
194
+ * whose cells MapLibre's text halo paints, so placement, wrapping and collision stay native.
195
+ */
196
+ type TileflowTextBackground = {
197
+ /** Strip colour. Cells overlap at their joins, so the colour must be opaque. */
198
+ color: TileflowColorStyleValue;
199
+ /** `lines` fits one strip to each shaped line. */
200
+ fit: 'lines';
201
+ /** Strip extension beyond the first and last glyph of each line, in ems. Defaults to 0.33. */
202
+ padding?: TileflowThemeNumberValue;
203
+ };
192
204
  type TileflowTextLayout = {
193
205
  allowOverlap?: boolean;
194
206
  anchor?: TileflowTextAnchor;
207
+ /**
208
+ * Replaces the text halo with line-fitted strips. Requires a map `glyphs` provider that serves
209
+ * derived stacks, one font without fallbacks, and constant `letterSpacing` and `lineHeight`.
210
+ */
211
+ background?: TileflowTextBackground;
195
212
  field?: TileflowStringStyleValue;
196
213
  font?: TileflowThemeFontValue;
197
214
  fallbacks?: readonly TileflowThemeFontValue[];
@@ -653,6 +670,30 @@ declare function shouldLoadTileflowManifest(options: TileflowManifestLoadOptions
653
670
  declare function validateTileflowRuntimeSource(source: unknown): TileflowRuntimeSourceValidation;
654
671
  /** Validate the only runtime selection grammar: one concrete portable name or `system`. */
655
672
  declare function validateTileflowThemeSelection(value: unknown): value is TileflowThemeSelection;
673
+ /**
674
+ * A continuous blend of named themes of one Tileflow map. `position` places the map between
675
+ * neighbouring themes: 0 is the first, 1 the second, and 1.25 a quarter of the way from the second
676
+ * to the third.
677
+ */
678
+ type TileflowThemeBlendSelection = Readonly<{
679
+ /** From 0 to `themes.length - 1`. */
680
+ position: number;
681
+ /** Two to eight concrete theme names of the map, in blend order. */
682
+ themes: readonly string[];
683
+ }>;
684
+ declare const tileflowThemeBlendLimits: Readonly<{
685
+ maximumThemes: 8;
686
+ minimumThemes: 2;
687
+ }>;
688
+ declare function validateTileflowThemeBlendSelection(value: unknown): value is TileflowThemeBlendSelection;
689
+ /** The theme nearest to a blend position, which a blend shows when it cannot blend. */
690
+ declare function nearestTileflowBlendTheme(blend: TileflowThemeBlendSelection): string;
691
+ /** Resolves every theme of a blend to its published runtime style, in blend order. */
692
+ declare function resolveTileflowRuntimeThemeBlend(options: {
693
+ blend: TileflowThemeBlendSelection;
694
+ manifestMap: TileflowRuntimeManifestMap;
695
+ source: TileflowRuntimeSource;
696
+ }): TileflowRuntimeStyle[];
656
697
  declare function assertValidTileflowRuntimeSource(source: unknown): asserts source is TileflowRuntimeSource;
657
698
  declare function resolveTileflowRuntimeStyle(options: TileflowRuntimeStyleOptions): TileflowRuntimeStyle | null;
658
699
  /** Resolve one concrete published theme without consulting ambient browser state. */
@@ -746,4 +787,4 @@ type TileflowRuntimeManifest = {
746
787
  version: typeof tileflowRuntimeManifestVersion;
747
788
  };
748
789
 
749
- export { type TileflowManifestFetchOptions as $, type TileflowAreaStyle as A, type TileflowBackgroundPaint as B, type TileflowCirclePaint as C, type TileflowColor as D, type TileflowColorStyleValue as E, type TileflowExtrusionPaint as F, type TileflowFillPaint as G, type TileflowIconAnchor as H, type TileflowIconLayout as I, type TileflowIconPaint as J, type TileflowIconStyle as K, type TileflowIconTextFit as L, type MapLibreStyle as M, type TileflowImageStyleValue as N, type TileflowLabelDetail as O, type TileflowLabelLanguage as P, type TileflowLabelStyles as Q, type TileflowLayerRange as R, type TileflowLight as S, type TileflowRuntimeManifest as T, type TileflowLineCap as U, type ValidationMessage as V, type TileflowLineHatchStyle as W, type TileflowLineJoin as X, type TileflowLineLayout as Y, type TileflowLinePaint as Z, type TileflowLineStackStyle as _, type TileflowRuntimeColorScheme as a, type TileflowTextJustify as a$, type TileflowManifestLoadOptions as a0, type TileflowMapMode as a1, type TileflowMapModeOptions as a2, type TileflowMarkerSymbolStyle as a3, type TileflowMountainBikeScale as a4, type TileflowNumberInsetsStyleValue as a5, type TileflowNumberStyleValue as a6, type TileflowPlaceLabelClass as a7, type TileflowPoiCategory as a8, type TileflowPoiCategoryStyle as a9, type TileflowRoadWeight as aA, type TileflowRuntimeCenterLike as aB, type TileflowRuntimeManifestMap as aC, type TileflowRuntimeSource as aD, type TileflowRuntimeSourceValidation as aE, type TileflowRuntimeStyle as aF, type TileflowRuntimeStyleOptions as aG, type TileflowRuntimeViewOptions as aH, type TileflowSessionController as aI, type TileflowSessionGrantResponse as aJ, type TileflowStringStyleValue as aK, type TileflowStructuralStyleValue as aL, type TileflowStyleFontFace as aM, type TileflowStyleValue as aN, type TileflowSymbolPlacement as aO, type TileflowSymbolPlacementStyle as aP, type TileflowSymbolZOrder as aQ, type TileflowTerrain as aR, type TileflowTerrainConfig as aS, type TileflowTerrainContourLabelStyle as aT, type TileflowTerrainContourLineStyle as aU, type TileflowTerrainContoursConfig as aV, type TileflowTerrainEncoding as aW, type TileflowTerrainHillshadeStyle as aX, type TileflowTerrainLayerRange as aY, type TileflowTerrainMode as aZ, type TileflowTextAnchor as a_, type TileflowPoiColorMode as aa, type TileflowPoiDensity as ab, type TileflowPriorityOrder as ac, type TileflowProjection as ad, type TileflowResolvedRuntimeTheme as ae, type TileflowRoadAreaStyle as af, type TileflowRoadClass as ag, type TileflowRoadClassStyle as ah, type TileflowRoadCrossingStyle as ai, type TileflowRoadDetail as aj, type TileflowRoadExtras as ak, type TileflowRoadHierarchy as al, type TileflowRoadLabelDetail as am, type TileflowRoadLayerStyle as an, type TileflowRoadModifier as ao, type TileflowRoadOutline as ap, type TileflowRoadRestriction as aq, type TileflowRoadRoundaboutStyle as ar, type TileflowRoadServiceType as as, type TileflowRoadShieldDetail as at, type TileflowRoadShieldStyles as au, type TileflowRoadSidewalkStyle as av, type TileflowRoadStructure as aw, type TileflowRoadTreatmentLayerStyle as ax, type TileflowRoadTreatmentLineStyle as ay, type TileflowRoadTreatmentStyle as az, type TileflowRuntimeManifestMapEntry as b, type TileflowTextLayout as b0, type TileflowTextPaint as b1, type TileflowTextStyle as b2, type TileflowThemeColorAlpha as b3, type TileflowThemeColorMix as b4, type TileflowThemeColorValue as b5, type TileflowThemeFontValue as b6, type TileflowThemeImageValue as b7, type TileflowThemeNumberValue as b8, type TileflowThemeSelection as b9, resolveTileflowRuntimeStyle as bA, resolveTileflowRuntimeTheme as bB, resolveTileflowRuntimeView as bC, resolveTileflowStaticImageUrl as bD, shouldLoadTileflowManifest as bE, startTileflowSession as bF, tileflowPoiCategories as bG, tileflowStyleFontFaceLimits as bH, tileflowStyleFontFacesMetadataKey as bI, tileflowThemeTokenCategories as bJ, token as bK, validateTileflowRuntimeSource as bL, validateTileflowThemeSelection as bM, zoom as bN, type TileflowTypographyStyle as bO, type ResolvedTileflowTypography as bP, normalizeTileflowSurfaceId as bQ, type TileflowThemeTokenCategory as ba, type TileflowThemeValue as bb, type TileflowViewConfig as bc, type TileflowWaterLabelClass as bd, type TileflowZoomInterpolation as be, type TileflowZoomValue as bf, type ValidationResult as bg, assertValidTileflowRuntimeSource as bh, clearTileflowManifestCache as bi, color as bj, createTileflowSessionController as bk, createTileflowSessionId as bl, defaultTileflowManifestUrl as bm, defaultTileflowRuntimeView as bn, fixed as bo, getTileflowAnalyticsApiUrl as bp, getTileflowStyleFontFaces as bq, inferTileflowAnalyticsFromStyleUrl as br, loadTileflowManifest as bs, mergeTileflowAnalytics as bt, normalizeTileflowRuntimeCenter as bu, normalizeTileflowStaticImageSize as bv, normalizeTileflowUrl as bw, resolveTileflowAnalyticsRequestUrl as bx, resolveTileflowManifestMap as by, resolveTileflowMapMode as bz, type TileflowRuntimeManifestTheme as c, type TileflowRuntimeSystemThemes as d, tileflowRuntimeManifestVersion as e, type TileflowExpression as f, type TileflowFixedValue as g, type TileflowThemeTokenReference as h, type TileflowThemeColorOperation as i, type TileflowBackgroundStyle as j, type TileflowCircleStyle as k, type TileflowExtrusionStyle as l, type TileflowFillStyle as m, type TileflowLineStyle as n, type TileflowSymbolStyle as o, type TileflowRoadsModuleOptions as p, type TileflowRoadsModuleConfig as q, type TileflowLabelsModuleOptions as r, type TileflowLabelsModuleConfig as s, tileflowRuntimeManifestLimits as t, type TileflowPoiModuleOptions as u, type TileflowPoiModuleConfig as v, type MapLibreSprite as w, type TileflowAerodromeCodeDetail as x, type TileflowAlignment as y, type TileflowAnalytics as z };
790
+ export { type TileflowManifestFetchOptions as $, type TileflowAreaStyle as A, type TileflowBackgroundPaint as B, type TileflowCirclePaint as C, type TileflowColor as D, type TileflowColorStyleValue as E, type TileflowExtrusionPaint as F, type TileflowFillPaint as G, type TileflowIconAnchor as H, type TileflowIconLayout as I, type TileflowIconPaint as J, type TileflowIconStyle as K, type TileflowIconTextFit as L, type MapLibreStyle as M, type TileflowImageStyleValue as N, type TileflowLabelDetail as O, type TileflowLabelLanguage as P, type TileflowLabelStyles as Q, type TileflowLayerRange as R, type TileflowLight as S, type TileflowRuntimeManifest as T, type TileflowLineCap as U, type ValidationMessage as V, type TileflowLineHatchStyle as W, type TileflowLineJoin as X, type TileflowLineLayout as Y, type TileflowLinePaint as Z, type TileflowLineStackStyle as _, type TileflowRuntimeColorScheme as a, type TileflowTextBackground as a$, type TileflowManifestLoadOptions as a0, type TileflowMapMode as a1, type TileflowMapModeOptions as a2, type TileflowMarkerSymbolStyle as a3, type TileflowMountainBikeScale as a4, type TileflowNumberInsetsStyleValue as a5, type TileflowNumberStyleValue as a6, type TileflowPlaceLabelClass as a7, type TileflowPoiCategory as a8, type TileflowPoiCategoryStyle as a9, type TileflowRoadWeight as aA, type TileflowRuntimeCenterLike as aB, type TileflowRuntimeManifestMap as aC, type TileflowRuntimeSource as aD, type TileflowRuntimeSourceValidation as aE, type TileflowRuntimeStyle as aF, type TileflowRuntimeStyleOptions as aG, type TileflowRuntimeViewOptions as aH, type TileflowSessionController as aI, type TileflowSessionGrantResponse as aJ, type TileflowStringStyleValue as aK, type TileflowStructuralStyleValue as aL, type TileflowStyleFontFace as aM, type TileflowStyleValue as aN, type TileflowSymbolPlacement as aO, type TileflowSymbolPlacementStyle as aP, type TileflowSymbolZOrder as aQ, type TileflowTerrain as aR, type TileflowTerrainConfig as aS, type TileflowTerrainContourLabelStyle as aT, type TileflowTerrainContourLineStyle as aU, type TileflowTerrainContoursConfig as aV, type TileflowTerrainEncoding as aW, type TileflowTerrainHillshadeStyle as aX, type TileflowTerrainLayerRange as aY, type TileflowTerrainMode as aZ, type TileflowTextAnchor as a_, type TileflowPoiColorMode as aa, type TileflowPoiDensity as ab, type TileflowPriorityOrder as ac, type TileflowProjection as ad, type TileflowResolvedRuntimeTheme as ae, type TileflowRoadAreaStyle as af, type TileflowRoadClass as ag, type TileflowRoadClassStyle as ah, type TileflowRoadCrossingStyle as ai, type TileflowRoadDetail as aj, type TileflowRoadExtras as ak, type TileflowRoadHierarchy as al, type TileflowRoadLabelDetail as am, type TileflowRoadLayerStyle as an, type TileflowRoadModifier as ao, type TileflowRoadOutline as ap, type TileflowRoadRestriction as aq, type TileflowRoadRoundaboutStyle as ar, type TileflowRoadServiceType as as, type TileflowRoadShieldDetail as at, type TileflowRoadShieldStyles as au, type TileflowRoadSidewalkStyle as av, type TileflowRoadStructure as aw, type TileflowRoadTreatmentLayerStyle as ax, type TileflowRoadTreatmentLineStyle as ay, type TileflowRoadTreatmentStyle as az, type TileflowRuntimeManifestMapEntry as b, type TileflowTextJustify as b0, type TileflowTextLayout as b1, type TileflowTextPaint as b2, type TileflowTextStyle as b3, type TileflowThemeBlendSelection as b4, type TileflowThemeColorAlpha as b5, type TileflowThemeColorMix as b6, type TileflowThemeColorValue as b7, type TileflowThemeFontValue as b8, type TileflowThemeImageValue as b9, resolveTileflowAnalyticsRequestUrl as bA, resolveTileflowManifestMap as bB, resolveTileflowMapMode as bC, resolveTileflowRuntimeStyle as bD, resolveTileflowRuntimeTheme as bE, resolveTileflowRuntimeThemeBlend as bF, resolveTileflowRuntimeView as bG, resolveTileflowStaticImageUrl as bH, shouldLoadTileflowManifest as bI, startTileflowSession as bJ, tileflowPoiCategories as bK, tileflowStyleFontFaceLimits as bL, tileflowStyleFontFacesMetadataKey as bM, tileflowThemeBlendLimits as bN, tileflowThemeTokenCategories as bO, token as bP, validateTileflowRuntimeSource as bQ, validateTileflowThemeBlendSelection as bR, validateTileflowThemeSelection as bS, zoom as bT, type TileflowTypographyStyle as bU, type ResolvedTileflowTypography as bV, normalizeTileflowSurfaceId as bW, type TileflowThemeNumberValue as ba, type TileflowThemeSelection as bb, type TileflowThemeTokenCategory as bc, type TileflowThemeValue as bd, type TileflowViewConfig as be, type TileflowWaterLabelClass as bf, type TileflowZoomInterpolation as bg, type TileflowZoomValue as bh, type ValidationResult as bi, assertValidTileflowRuntimeSource as bj, clearTileflowManifestCache as bk, color as bl, createTileflowSessionController as bm, createTileflowSessionId as bn, defaultTileflowManifestUrl as bo, defaultTileflowRuntimeView as bp, fixed as bq, getTileflowAnalyticsApiUrl as br, getTileflowStyleFontFaces as bs, inferTileflowAnalyticsFromStyleUrl as bt, loadTileflowManifest as bu, mergeTileflowAnalytics as bv, nearestTileflowBlendTheme as bw, normalizeTileflowRuntimeCenter as bx, normalizeTileflowStaticImageSize as by, normalizeTileflowUrl as bz, type TileflowRuntimeManifestTheme as c, type TileflowRuntimeSystemThemes as d, tileflowRuntimeManifestVersion as e, type TileflowExpression as f, type TileflowFixedValue as g, type TileflowThemeTokenReference as h, type TileflowThemeColorOperation as i, type TileflowBackgroundStyle as j, type TileflowCircleStyle as k, type TileflowExtrusionStyle as l, type TileflowFillStyle as m, type TileflowLineStyle as n, type TileflowSymbolStyle as o, type TileflowRoadsModuleOptions as p, type TileflowRoadsModuleConfig as q, type TileflowLabelsModuleOptions as r, type TileflowLabelsModuleConfig as s, tileflowRuntimeManifestLimits as t, type TileflowPoiModuleOptions as u, type TileflowPoiModuleConfig as v, type MapLibreSprite as w, type TileflowAerodromeCodeDetail as x, type TileflowAlignment as y, type TileflowAnalytics as z };
@@ -1,6 +1,6 @@
1
1
  import { z } from 'zod';
2
- import { T as TileflowRuntimeManifest } from './manifest-types-BZU4zbmI.js';
3
- export { a as TileflowRuntimeColorScheme, b as TileflowRuntimeManifestMapEntry, c as TileflowRuntimeManifestTheme, d as TileflowRuntimeSystemThemes, t as tileflowRuntimeManifestLimits, e as tileflowRuntimeManifestVersion } from './manifest-types-BZU4zbmI.js';
2
+ import { T as TileflowRuntimeManifest } from './manifest-types-CTT2eLbp.js';
3
+ export { a as TileflowRuntimeColorScheme, b as TileflowRuntimeManifestMapEntry, c as TileflowRuntimeManifestTheme, d as TileflowRuntimeSystemThemes, t as tileflowRuntimeManifestLimits, e as tileflowRuntimeManifestVersion } from './manifest-types-CTT2eLbp.js';
4
4
 
5
5
  declare const tileflowRuntimeManifestSchema: z.ZodType<TileflowRuntimeManifest>;
6
6
  declare function parseTileflowRuntimeManifest(input: unknown): TileflowRuntimeManifest;
package/dist/native.js CHANGED
@@ -4605,6 +4605,7 @@ var manifestCache = new globalThis.Map();
4605
4605
  function validateTileflowThemeSelection(value) {
4606
4606
  return value === "system" || isTileflowThemeName(value);
4607
4607
  }
4608
+ var tileflowThemeBlendLimits = Object.freeze({ maximumThemes: 8, minimumThemes: 2 });
4608
4609
  function resolveTileflowRuntimeTheme(map2, selection, colorScheme) {
4609
4610
  let name;
4610
4611
  if (selection === void 0) {
package/dist/runtime.d.ts CHANGED
@@ -1 +1 @@
1
- export { z as TileflowAnalytics, $ as TileflowManifestFetchOptions, a0 as TileflowManifestLoadOptions, a1 as TileflowMapMode, a2 as TileflowMapModeOptions, ae as TileflowResolvedRuntimeTheme, aB as TileflowRuntimeCenterLike, a as TileflowRuntimeColorScheme, T as TileflowRuntimeManifest, aC as TileflowRuntimeManifestMap, b as TileflowRuntimeManifestMapEntry, c as TileflowRuntimeManifestTheme, aD as TileflowRuntimeSource, aE as TileflowRuntimeSourceValidation, aF as TileflowRuntimeStyle, aG as TileflowRuntimeStyleOptions, d as TileflowRuntimeSystemThemes, aH as TileflowRuntimeViewOptions, aI as TileflowSessionController, aJ as TileflowSessionGrantResponse, aM as TileflowStyleFontFace, b9 as TileflowThemeSelection, bh as assertValidTileflowRuntimeSource, bi as clearTileflowManifestCache, bk as createTileflowSessionController, bl as createTileflowSessionId, bm as defaultTileflowManifestUrl, bn as defaultTileflowRuntimeView, bp as getTileflowAnalyticsApiUrl, bq as getTileflowStyleFontFaces, br as inferTileflowAnalyticsFromStyleUrl, bs as loadTileflowManifest, bt as mergeTileflowAnalytics, bu as normalizeTileflowRuntimeCenter, bv as normalizeTileflowStaticImageSize, bQ as normalizeTileflowSurfaceId, bw as normalizeTileflowUrl, bx as resolveTileflowAnalyticsRequestUrl, by as resolveTileflowManifestMap, bz as resolveTileflowMapMode, bA as resolveTileflowRuntimeStyle, bB as resolveTileflowRuntimeTheme, bC as resolveTileflowRuntimeView, bD as resolveTileflowStaticImageUrl, bE as shouldLoadTileflowManifest, bF as startTileflowSession, bH as tileflowStyleFontFaceLimits, bI as tileflowStyleFontFacesMetadataKey, bL as validateTileflowRuntimeSource, bM as validateTileflowThemeSelection } from './manifest-types-BZU4zbmI.js';
1
+ export { z as TileflowAnalytics, $ as TileflowManifestFetchOptions, a0 as TileflowManifestLoadOptions, a1 as TileflowMapMode, a2 as TileflowMapModeOptions, ae as TileflowResolvedRuntimeTheme, aB as TileflowRuntimeCenterLike, a as TileflowRuntimeColorScheme, T as TileflowRuntimeManifest, aC as TileflowRuntimeManifestMap, b as TileflowRuntimeManifestMapEntry, c as TileflowRuntimeManifestTheme, aD as TileflowRuntimeSource, aE as TileflowRuntimeSourceValidation, aF as TileflowRuntimeStyle, aG as TileflowRuntimeStyleOptions, d as TileflowRuntimeSystemThemes, aH as TileflowRuntimeViewOptions, aI as TileflowSessionController, aJ as TileflowSessionGrantResponse, aM as TileflowStyleFontFace, b4 as TileflowThemeBlendSelection, bb as TileflowThemeSelection, bj as assertValidTileflowRuntimeSource, bk as clearTileflowManifestCache, bm as createTileflowSessionController, bn as createTileflowSessionId, bo as defaultTileflowManifestUrl, bp as defaultTileflowRuntimeView, br as getTileflowAnalyticsApiUrl, bs as getTileflowStyleFontFaces, bt as inferTileflowAnalyticsFromStyleUrl, bu as loadTileflowManifest, bv as mergeTileflowAnalytics, bw as nearestTileflowBlendTheme, bx as normalizeTileflowRuntimeCenter, by as normalizeTileflowStaticImageSize, bW as normalizeTileflowSurfaceId, bz as normalizeTileflowUrl, bA as resolveTileflowAnalyticsRequestUrl, bB as resolveTileflowManifestMap, bC as resolveTileflowMapMode, bD as resolveTileflowRuntimeStyle, bE as resolveTileflowRuntimeTheme, bF as resolveTileflowRuntimeThemeBlend, bG as resolveTileflowRuntimeView, bH as resolveTileflowStaticImageUrl, bI as shouldLoadTileflowManifest, bJ as startTileflowSession, bL as tileflowStyleFontFaceLimits, bM as tileflowStyleFontFacesMetadataKey, bN as tileflowThemeBlendLimits, bQ as validateTileflowRuntimeSource, bR as validateTileflowThemeBlendSelection, bS as validateTileflowThemeSelection } from './manifest-types-CTT2eLbp.js';
package/dist/runtime.js CHANGED
@@ -496,6 +496,30 @@ function validateTileflowRuntimeSource(source) {
496
496
  function validateTileflowThemeSelection(value) {
497
497
  return value === "system" || isTileflowThemeName(value);
498
498
  }
499
+ var tileflowThemeBlendLimits = Object.freeze({ maximumThemes: 8, minimumThemes: 2 });
500
+ function validateTileflowThemeBlendSelection(value) {
501
+ if (!value || typeof value !== "object") return false;
502
+ const { position, themes } = value;
503
+ return Array.isArray(themes) && themes.length >= tileflowThemeBlendLimits.minimumThemes && themes.length <= tileflowThemeBlendLimits.maximumThemes && themes.every((theme) => isTileflowThemeName(theme)) && typeof position === "number" && Number.isFinite(position) && position >= 0 && position <= themes.length - 1;
504
+ }
505
+ function nearestTileflowBlendTheme(blend) {
506
+ const index = Math.min(blend.themes.length - 1, Math.max(0, Math.round(blend.position)));
507
+ return blend.themes[index];
508
+ }
509
+ function resolveTileflowRuntimeThemeBlend(options) {
510
+ if (!validateTileflowThemeBlendSelection(options.blend)) {
511
+ throw new TypeError(
512
+ "A Tileflow theme blend requires two to eight concrete themes and a position."
513
+ );
514
+ }
515
+ return options.blend.themes.map(
516
+ (theme) => resolveTileflowRuntimeStyle({
517
+ manifestMap: options.manifestMap,
518
+ source: options.source,
519
+ theme
520
+ })
521
+ );
522
+ }
499
523
  function assertValidTileflowRuntimeSource(source) {
500
524
  const validation = validateTileflowRuntimeSource(source);
501
525
  if (!validation.ok) {
@@ -1269,6 +1293,7 @@ export {
1269
1293
  inferTileflowAnalyticsFromStyleUrl,
1270
1294
  loadTileflowManifest,
1271
1295
  mergeTileflowAnalytics,
1296
+ nearestTileflowBlendTheme,
1272
1297
  normalizeTileflowRuntimeCenter,
1273
1298
  normalizeTileflowStaticImageSize,
1274
1299
  normalizeTileflowSurfaceId,
@@ -1278,12 +1303,15 @@ export {
1278
1303
  resolveTileflowMapMode,
1279
1304
  resolveTileflowRuntimeStyle,
1280
1305
  resolveTileflowRuntimeTheme,
1306
+ resolveTileflowRuntimeThemeBlend,
1281
1307
  resolveTileflowRuntimeView,
1282
1308
  resolveTileflowStaticImageUrl,
1283
1309
  shouldLoadTileflowManifest,
1284
1310
  startTileflowSession,
1285
1311
  tileflowStyleFontFaceLimits,
1286
1312
  tileflowStyleFontFacesMetadataKey,
1313
+ tileflowThemeBlendLimits,
1287
1314
  validateTileflowRuntimeSource,
1315
+ validateTileflowThemeBlendSelection,
1288
1316
  validateTileflowThemeSelection
1289
1317
  };
@@ -158,6 +158,21 @@ Structural controls such as presets, visibility, and zoom gates remain ordinary
158
158
  controls address stable concepts such as `roads.classes.primary.surface.fill`, not renderer layer
159
159
  IDs.
160
160
 
161
+ `expr.id()` reads the source-owned feature identifier: a string, number, or `null` when absent.
162
+ It performs no I/O and does not derive an identifier from geometry. `expr.modulo(dividend, divisor)`
163
+ uses native numeric remainder, including its sign behavior. Normalize input and provide a deliberate
164
+ fallback before using numeric IDs for decorative variation; missing or non-numeric IDs must not
165
+ silently imply distinct features. Identity stability across data releases belongs to the producer.
166
+
167
+ <!-- docs:check -->
168
+
169
+ ```ts
170
+ import {expr} from '@tileflow/core';
171
+
172
+ const numericIdentity = expr.abs(expr.toNumber(expr.id(), 0));
173
+ const decorativeBucket = expr.modulo(numericIdentity, 7);
174
+ ```
175
+
161
176
  The `land` module exposes stable land-use targets for `cemetery`, `civic`, `commercial`,
162
177
  `education`, `government`, `industrial`, `medical`, `military`, `parking`, `railway`,
163
178
  `recreation`, and `residential`. Its land-cover taxonomy distinguishes physical cover from authored
@@ -194,6 +209,18 @@ broadleaf and conifer palettes, and independent height and crown scales. The leg
194
209
  shortcut remains available; `flat.minZoom` takes precedence when both are present. The binding
195
210
  includes height, crown diameter, genus, leaf type, and species fields so compatible runtimes can
196
211
  preserve source measurements and botanical form without hard-coding raw property names. The
197
- pitched-scene stack follows physical height: pedestrian and transport surfaces, transport markings
198
- and road names, buildings, then vegetation. Place, water, aerodrome, and POI annotations remain
199
- last so geographic names stay readable without making street paint or text float over 3D geometry.
212
+ pitched-scene stack follows physical height: pedestrian and transport surfaces, transport markings,
213
+ buildings, then vegetation, so street paint never floats over 3D geometry. Text draws last: road
214
+ names, route shields, junction numbers, and place, water, aerodrome, and POI annotations stay above
215
+ every ground layer, so building fills, boundaries, and trees cannot cover them.
216
+ `labels.collisionPriority` only orders labels within that final stack.
217
+
218
+ Render passes, and refinements that move a target their module owns, share one `placement`
219
+ vocabulary. A band edge is `below-` or `above-` one of `land`, `relief`, `water`, `roads`,
220
+ `boundaries`, `buildings`, `vegetation`, and `labels`; it needs no anchor, so a vegetation pass can
221
+ draw `'above-relief'` without depending on another module. `{above: target}` and `{below: target}`
222
+ draw beside one semantic target and inherit its band and, without their own `feature`, its vector
223
+ data; passes placed beside a moved target follow it. Operations sharing a placement paint in
224
+ declaration order, the first lowest. For symbols, a higher layer is also placed first in MapLibre
225
+ collisions, so placement decides both drawing and precedence. An owner whose layers are all
226
+ render passes still satisfies other operations' `requirements`.
@@ -116,7 +116,8 @@ to right; a later exact name replaces an earlier face and case-only collisions f
116
116
  faces used by the final style become content-addressed assets and strict `tileflow:fontFaces`
117
117
  metadata. `font` names an exact OpenType full name or glyph face; local `fallbacks` name exact faces
118
118
  or explicit CSS generic families. Tileflow never appends a weight suffix or derives one face from
119
- another. Browser adapters load local faces before MapLibre. Native releases use a locked PBF
119
+ another; the only derived stacks are line-fitted text backgrounds on a `glyphs` provider, which keep
120
+ their source faces' shapes. Browser adapters load local faces before MapLibre. Native releases use a locked PBF
120
121
  `glyphs` URL provider instead, which enumerates the exact comma-joined MapLibre request keys in
121
122
  `fontStacks`.
122
123
 
@@ -10,8 +10,9 @@ having to learn different spellings for the same MapLibre behavior:
10
10
  - `LineStyle`: color, width, opacity, dash, blur, gap, offset, pattern, caps, joins, and zoom range.
11
11
  - `LineHatchStyle`: repeated diagonal detail with color, opacity, spacing, size, angle, and zoom
12
12
  range for a road structure.
13
- - `TextStyle`: field, exact font face, exact fallback faces, size, color, halo, spacing metrics, transform,
14
- collision policy, rotation, fixed/variable anchoring, line constraints, and zoom range.
13
+ - `TextStyle`: field, exact font face, exact fallback faces, size, color, halo, line-fitted
14
+ background, spacing metrics, transform, collision policy, rotation, fixed/variable anchoring, line
15
+ constraints, and zoom range.
15
16
  - `IconStyle`: image, size, color, halo, rotation/alignment, collision policy, and zoom range.
16
17
  - `CircleStyle`: radius, fill/stroke appearance, blur, opacity, pitch behavior, and zoom range.
17
18
  - `ExtrusionStyle`: color, height, base, opacity, pattern, vertical gradient, and zoom range.
@@ -20,3 +21,61 @@ Compounds express common cartographic structures: `AreaStyle` has `fill` and `ou
20
21
  `LineStackStyle` has `shadow`, `casing`, and `fill`, and `SymbolStyle` combines placement with
21
22
  optional `text`, `icon`, and `marker`. Geographic selection remains owned by semantic modules;
22
23
  ordinary visual styles intentionally do not accept raw source filters.
24
+
25
+ ## Line-fitted text backgrounds
26
+
27
+ `text.background` draws one opaque strip behind each shaped line of a label, fitted to that line's
28
+ own width. Use it for captions whose lines differ in length, where a stretched icon plate
29
+ (`icon.textFit`) would cover the whole block.
30
+
31
+ <!-- docs:check -->
32
+
33
+ ```ts
34
+ import {fixed, poi, zoom} from '@tileflow/core';
35
+
36
+ export const captions = poi({
37
+ categories: ['arts-entertainment'],
38
+ styles: {
39
+ 'arts-entertainment': {
40
+ text: {
41
+ background: {
42
+ color: fixed('#080E11', {reason: 'Caption strip'}),
43
+ fit: 'lines',
44
+ padding: 0.33,
45
+ },
46
+ color: fixed('#ECEEE9', {reason: 'Caption text'}),
47
+ font: fixed('Noto Sans Bold', {reason: 'Caption face'}),
48
+ letterSpacing: fixed(0.08, {reason: 'Caption tracking'}),
49
+ lineHeight: fixed(1.2, {reason: 'Caption leading'}),
50
+ size: zoom.linear([
51
+ [14, 11],
52
+ [18, 14],
53
+ ]),
54
+ },
55
+ },
56
+ },
57
+ });
58
+ ```
59
+
60
+ Tileflow lowers the background to MapLibre properties only. `text-font` becomes a derived stack,
61
+ such as `Noto Sans Bold lines-v1-t80-l1200-p330`. Its glyphs keep the source advances and shapes and
62
+ add a rectangular cell, which the text halo paints. The halo width tracks `text-size / 6`, including
63
+ zoom curves. Shaping, wrapping, collision, variable anchors, fading and right-to-left text therefore
64
+ stay native, and the compiled style needs no runtime extension.
65
+
66
+ - The colour must be opaque. Neighbouring cells overlap where they join.
67
+ - `font` must name one stack served by the map's `glyphs` provider, without `fallbacks`. Maps that
68
+ use browser-rendered `fonts` reject backgrounds.
69
+ - `letterSpacing` and `lineHeight` must be constants. The derived stack encodes them in thousandths
70
+ of an em, and the layer uses those rounded values. Tracking runs from 0 to 0.5em, leading from 0.8
71
+ to 3 and padding from 0 to 1em.
72
+ - The background replaces the text halo. While a background is active, `haloWidth` and `haloBlur`
73
+ are derived, and `haloColor` is the strip colour. Later refinements of size, tracking, leading or
74
+ font re-derive the stack and halo.
75
+ - Collision still reserves the shaped block. Padding beyond it is drawn outside that box, so keep
76
+ `padding` (text padding) at least as large as the strip padding in pixels.
77
+
78
+ The map's `glyphs` provider must serve derived stacks. `deriveTileflowLineBackgroundGlyphs`
79
+ computes any range from the source stack's range, and `parseTileflowLineBackgroundFontStack`
80
+ recognises derived requests. Local previews and captures derive ranges themselves; hosted and
81
+ self-hosted providers must do the same.
@@ -0,0 +1,165 @@
1
+ # Theme transitions and blends
2
+
3
+ Start with the [@tileflow/core guide](https://github.com/tileflow/tileflow-sdk/blob/main/packages/core/README.md) for installation and a complete first example.
4
+
5
+ A Tileflow map can change theme with a cross-fade, or show any point between two or more of its
6
+ themes. Use a transition when people switch between appearances, such as light and dark. Use a
7
+ blend when the application controls the appearance continuously, such as a slider or a day that
8
+ passes from night to day.
9
+
10
+ Both work on the one MapLibre map the application already has. They create no second map, add no
11
+ map views, and request the same tiles as a map that does not change theme. They need a browser
12
+ document and MapLibre GL JS; the React Native package does not offer them.
13
+
14
+ ## Cross-fade a theme change
15
+
16
+ Pass `themeTransition` to the React, Vue, or Svelte map. This React example assumes a map named
17
+ `city` with `light` and `dark` themes in the published manifest:
18
+
19
+ ```tsx
20
+ import {Map} from '@tileflow/react';
21
+ import {useState} from 'react';
22
+
23
+ export function CityMap() {
24
+ const [theme, setTheme] = useState<'dark' | 'light'>('light');
25
+ return (
26
+ <>
27
+ <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>Switch theme</button>
28
+ <Map source={{map: 'city'}} theme={theme} themeTransition={{duration: 450}} />
29
+ </>
30
+ );
31
+ }
32
+ ```
33
+
34
+ When the theme changes, a snapshot of the current frame covers the map. The snapshot follows the
35
+ camera while people pan, zoom, rotate, or tilt, and fades out once the new theme is drawn. The map
36
+ stays interactive throughout. `onThemeChange` reports `preloading`, `applying`, and finally `ready`
37
+ after the fade. A `theme="system"` change, entering a blend, and leaving one use the same
38
+ transition.
39
+
40
+ `duration` is in milliseconds, from 0 to 5000. It defaults to 0, which changes the theme at once.
41
+ When the browser asks for reduced motion, every change happens at once.
42
+
43
+ ## Blend themes
44
+
45
+ Pass `themeBlend` with the themes to blend, in order, and a `position` between them. Position 0
46
+ shows the first theme, 1 the second, and 1.25 a quarter of the way from the second to the third:
47
+
48
+ ```tsx
49
+ import {Map} from '@tileflow/react';
50
+ import {useState} from 'react';
51
+
52
+ export function DayMap() {
53
+ const [position, setPosition] = useState(0);
54
+ return (
55
+ <>
56
+ <input
57
+ aria-label="Time of day"
58
+ max={2}
59
+ min={0}
60
+ onChange={(event) => setPosition(Number(event.target.value))}
61
+ step={0.01}
62
+ type="range"
63
+ value={position}
64
+ />
65
+ <Map source={{map: 'city'}} themeBlend={{position, themes: ['night', 'dusk', 'day']}} />
66
+ </>
67
+ );
68
+ }
69
+ ```
70
+
71
+ The first blend of a set of themes loads each theme's style and fonts, prepares one style that
72
+ holds every theme, and replaces the map's style once, with `themeTransition` if set. Until then the
73
+ map shows the theme nearest to the position. After that, changing `position` updates the map at
74
+ once without loading anything, so it can follow a slider, a clock, or an animation frame by frame.
75
+ Changing `themes` prepares a new blend. Removing `themeBlend` returns to `theme`.
76
+
77
+ While a blend is shown, `data-tileflow-theme` names the theme nearest to the position.
78
+ `onThemeChange` reports the preparation of a blend; moving its position reports nothing.
79
+
80
+ ### What follows the position
81
+
82
+ - Colours and numbers of the ground, such as land, water, roads, buildings, and their widths and
83
+ opacities, follow the position continuously. Colours mix in the OKLab colour space, so halfway
84
+ between two themes looks halfway to the eye.
85
+ - Patterns, the sky, and light follow the position too. Pattern artwork is mixed in its pixels.
86
+ - Labels, icons, and other symbols change when the nearest theme changes, with a short cross-fade.
87
+ Light lettering on a dark plate and dark lettering on a light plate would meet in the same grey
88
+ halfway, so symbols do not follow the position.
89
+ - A value that depends on feature state, such as a caption that changes colour when highlighted,
90
+ changes with the nearest theme. MapLibre lays its source out again for that change; a cross-fade
91
+ covers it.
92
+
93
+ ### Which themes can be blended
94
+
95
+ Blend themes of the same map. Every theme of a map exposes the same token keys, so its compiled
96
+ styles share sources, layers, filters, and expressions, and differ only in colours, numbers, and
97
+ image names. Up to eight themes can be blended. A blend fails, and the map keeps its current
98
+ appearance, when the styles differ in structure, sources, sprite, or glyphs.
99
+
100
+ Icon and pattern artwork is mixed in place of the first theme's image when every theme's version
101
+ has the same size. Otherwise that image changes with the nearest theme instead.
102
+
103
+ ### Cost
104
+
105
+ The prepared style holds every theme. A value that depends on feature data, such as a land-use
106
+ colour chosen by class, becomes one layer per class while the blend is shown, so the prepared
107
+ style has more layers than one theme. Physical layer IDs are diagnostic, not stable; semantic
108
+ interactions are not affected.
109
+
110
+ Entering a blend replaces the map's style once. MapLibre then takes about as long as it takes to
111
+ load the map: for a detailed city map, around half a second on a desktop computer and longer on a
112
+ phone, while the transition snapshot, if any, covers the map. Start a blend before people need it
113
+ to move, for example when the map loads.
114
+
115
+ Each position change after that sets the map's themed values directly, without expression parsing.
116
+ For a detailed city map this takes a few milliseconds on a mid-range phone. Positions closer than a
117
+ four-hundredth of a theme are not applied, so a slowly moving position leaves the map at rest
118
+ between changes.
119
+
120
+ ## Use the core controller
121
+
122
+ Framework adapters use `createTileflowThemeController` from `@tileflow/core/browser`. A direct
123
+ MapLibre integration can use it too. Resolve runtime styles from the published manifest with
124
+ `resolveTileflowRuntimeStyle` and `resolveTileflowRuntimeThemeBlend` from `@tileflow/core/runtime`:
125
+
126
+ ```ts
127
+ import {createTileflowThemeController} from '@tileflow/core/browser';
128
+ import {
129
+ resolveTileflowRuntimeStyle,
130
+ resolveTileflowRuntimeThemeBlend,
131
+ } from '@tileflow/core/runtime';
132
+ import type {Map as MapLibreMap} from 'maplibre-gl';
133
+ import type {TileflowRuntimeManifestMap} from '@tileflow/core/runtime';
134
+
135
+ export async function moveThroughTheDay(map: MapLibreMap, manifestMap: TileflowRuntimeManifestMap) {
136
+ const source = {map: 'city'};
137
+ const styleOf = (theme: string) => {
138
+ const style = resolveTileflowRuntimeStyle({manifestMap, source, theme});
139
+ if (!style) throw new Error(`The manifest has no ${theme} theme for ${source.map}.`);
140
+ return style;
141
+ };
142
+ // `initial` is the runtime style the map was created with.
143
+ const controller = createTileflowThemeController({initial: styleOf('day'), map});
144
+
145
+ await controller.setTheme(styleOf('night'), {transition: {duration: 450}});
146
+
147
+ const themes = resolveTileflowRuntimeThemeBlend({
148
+ blend: {position: 0, themes: ['night', 'dusk', 'day']},
149
+ manifestMap,
150
+ source,
151
+ });
152
+ await controller.setBlend({position: 0.5, themes});
153
+ // The same themes: the position applies at once.
154
+ await controller.setBlend({position: 0.6, themes});
155
+ return controller.getBlend(); // {position: 0.6, themes: ['night', 'dusk', 'day']}
156
+ }
157
+ ```
158
+
159
+ `setTheme` and `setBlend` accept `{transition: {duration}}`;
160
+ `createTileflowThemeController({transition})` sets a default. Requests are serialized and the
161
+ latest wins. A failed change restores the previous appearance and reports `failed` with its error.
162
+
163
+ The controller loads blended themes' style documents with the same request policy it uses for
164
+ style font metadata: same-origin credentials, no redirects, and a bounded size. Pass `loadStyle`
165
+ when styles need another loader.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tileflow/core",
3
- "version": "0.1.0-alpha.29",
3
+ "version": "0.1.0-alpha.30",
4
4
  "license": "Apache-2.0",
5
5
  "description": "Typed Tileflow config and MapLibre style compiler.",
6
6
  "type": "module",