@tileflow/core 0.1.0-alpha.41 → 0.1.0-alpha.43

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.
Files changed (51) hide show
  1. package/README.md +51 -69
  2. package/THIRD_PARTY_NOTICES.md +1 -1
  3. package/dist/{3d-CzLTD0RK.d.ts → 3d-CW5Ls0An.d.ts} +32 -2
  4. package/dist/3d.d.ts +1 -1
  5. package/dist/3d.js +337 -34
  6. package/dist/browser.d.ts +119 -7
  7. package/dist/browser.js +754 -61
  8. package/dist/build.d.ts +8 -4
  9. package/dist/build.js +284 -4
  10. package/dist/config-reference.json +4005 -2284
  11. package/dist/{icon-composition-HUh_Lj8Z.d.ts → icon-composition-Bbw9umUA.d.ts} +46 -3
  12. package/dist/index.d.ts +22 -5
  13. package/dist/index.js +254 -6
  14. package/dist/{manifest-types-DnhSJjCM.d.ts → manifest-types-CwjHd4qc.d.ts} +10 -0
  15. package/dist/manifest.d.ts +2 -2
  16. package/dist/native-profile.d.ts +4 -0
  17. package/dist/native-profile.js +2 -0
  18. package/dist/native.d.ts +87 -1
  19. package/dist/native.js +980 -460
  20. package/dist/runtime.d.ts +1 -1
  21. package/dist/worker/camera-tile-worker.global.js +2 -2
  22. package/package.json +4 -5
  23. package/docs/application-tile-reading.md +0 -86
  24. package/docs/authoring-model.md +0 -269
  25. package/docs/boundary-areas-and-choropleths.md +0 -217
  26. package/docs/buildings-3d.md +0 -608
  27. package/docs/camera-moves-and-tile-cache.md +0 -112
  28. package/docs/capture-scenes.md +0 -40
  29. package/docs/capture-shots.md +0 -173
  30. package/docs/cartographic-defaults.md +0 -210
  31. package/docs/compiled-style-performance.md +0 -286
  32. package/docs/data-is-separate-from-design.md +0 -610
  33. package/docs/depth-markers.md +0 -65
  34. package/docs/dynamic-style-images.md +0 -100
  35. package/docs/globe-atmosphere.md +0 -113
  36. package/docs/hosted-session-authorization.md +0 -106
  37. package/docs/map-and-terrain-examples.md +0 -156
  38. package/docs/map-emphasis.md +0 -89
  39. package/docs/native-artifact-profile.md +0 -152
  40. package/docs/native-resource-urls.md +0 -369
  41. package/docs/nautical-marks.md +0 -308
  42. package/docs/public-api-and-browser-subpath.md +0 -101
  43. package/docs/route-drawing.md +0 -191
  44. package/docs/shared-visual-primitives.md +0 -101
  45. package/docs/street-lights.md +0 -127
  46. package/docs/street-sky.md +0 -156
  47. package/docs/style-states.md +0 -73
  48. package/docs/sun-and-light.md +0 -167
  49. package/docs/theme-transitions-and-blends.md +0 -317
  50. package/docs/themes-and-module-styles.md +0 -156
  51. package/docs/trees-3d.md +0 -295
package/dist/build.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { T as TileflowCaptureScene, a as TileflowCaptureShot } from './capture-shot-ChPQvPyi.js';
2
- import { T as TileflowRenderedIconIdentity, a as TileflowIconCompositionV1, R as ResolvedTileflowMap, b as TileflowDataRequirementsV1, c as TileflowSourceRequirementsV1, d as TileflowMap, e as TileflowStyleOptions, f as TileflowInspectedStyle, g as TileflowPreparedMapAssets } from './icon-composition-HUh_Lj8Z.js';
3
- export { h as TileflowDataCompatibilityIssue, i as TileflowDataFieldRequirement, j as TileflowDataFieldType, k as TileflowDataLayerRequirement, l as TileflowObservedDataContractV1, m as TileflowStyleInspection, n as TileflowStyleInspectionContribution, o as TileflowStyleInspectionLayer, p as TileflowStyleInspectionRenderOperation, q as collectMapLineage, r as inferTileflowDataRequirements, s as inferTileflowSourceRequirements, t as tileflowStyleInspectionSchemaVersion, v as validateTileflowDataCompatibility } from './icon-composition-HUh_Lj8Z.js';
4
- import { M as MapLibreStyle, f as TileflowTimeOfDayVariants, T as TileflowRuntimeManifest } from './manifest-types-DnhSJjCM.js';
2
+ import { T as TileflowRenderedIconIdentity, a as TileflowIconCompositionV1, R as ResolvedTileflowMap, b as TileflowDataRequirementsV1, c as TileflowSourceRequirementsV1, d as TileflowMap, e as TileflowStyleOptions, f as TileflowInspectedStyle, g as TileflowPreparedMapAssets } from './icon-composition-Bbw9umUA.js';
3
+ export { h as TileflowDataCompatibilityIssue, i as TileflowDataFieldRequirement, j as TileflowDataFieldType, k as TileflowDataLayerRequirement, l as TileflowObservedDataContractV1, m as TileflowStyleInspection, n as TileflowStyleInspectionContribution, o as TileflowStyleInspectionLayer, p as TileflowStyleInspectionRenderOperation, q as collectMapLineage, r as inferTileflowDataRequirements, s as inferTileflowSourceRequirements, t as tileflowStyleInspectionSchemaVersion, v as validateTileflowDataCompatibility } from './icon-composition-Bbw9umUA.js';
4
+ import { M as MapLibreStyle, f as TileflowTimeOfDayVariants, T as TileflowRuntimeManifest } from './manifest-types-CwjHd4qc.js';
5
5
  import { z } from 'zod';
6
6
 
7
7
  declare const tileflowMapRevisionSchemaVersion: 1;
@@ -141,6 +141,9 @@ declare function hashTileflowAssetSetIdentities(input: readonly TileflowBuildAss
141
141
  */
142
142
  declare function createStyleWithInspection(config: TileflowMap, options?: TileflowStyleOptions): TileflowInspectedStyle;
143
143
 
144
+ /** Native keeps the complete ground stroke; its renderer cannot derive clipped vector tiles. */
145
+ declare function prepareTileflowNativePathGround(style: MapLibreStyle): MapLibreStyle;
146
+
144
147
  /** These are transport/validation bounds, not renderer or commercial quotas. */
145
148
  declare const tileflowRendererDeploymentLimits: Readonly<{
146
149
  maximumBytes: number;
@@ -507,6 +510,7 @@ declare const tileflowRendererDeploymentArtifactSchema: z.ZodObject<{
507
510
  none: "none";
508
511
  }>;
509
512
  sky: z.ZodOptional<z.ZodLiteral<"removed">>;
513
+ pathGround: z.ZodOptional<z.ZodLiteral<"ground-fallback">>;
510
514
  layers: z.ZodArray<z.ZodLazy<z.core.$ZodObject<{
511
515
  inputLayer: z.ZodNumber;
512
516
  outputStart: z.ZodNumber;
@@ -592,4 +596,4 @@ declare function createManifest(catalog: TileflowBuildCatalog, options?: {
592
596
  manifestVersion?: 1 | 2;
593
597
  }): TileflowRuntimeManifest;
594
598
 
595
- export { type TileflowBuildAssetIdentity, type TileflowBuildCatalog, type TileflowBuildInspectedStyles, type TileflowBuildStyles, type TileflowCompiledMapMetadata, TileflowDataRequirementsV1, type TileflowEffectiveFontSourceIdentity, type TileflowEffectiveIconSourceIdentity, type TileflowEffectiveMapSourceAssets, type TileflowEffectiveModelSourceIdentity, type TileflowHashableBuildAsset, TileflowInspectedStyle, type TileflowMapBuildInput, type TileflowMapBuildLineageEntry, type TileflowMapBuildManifestEntryV1, type TileflowMapBuildManifestV1, type TileflowMapBuildProvenanceV1, TileflowPreparedMapAssets, type TileflowRendererDeploymentArtifact, TileflowRendererDeploymentError, type TileflowRendererDeploymentResponse, TileflowSourceRequirementsV1, type TileflowThemeBuildManifestEntryV1, collectTileflowMapBuildLineage, createManifest, createStyleFromCatalog, createStyleFromCatalogWithInspection, createStyleWithInspection, createStylesFromCatalog, createStylesFromCatalogWithInspection, createTileflowMapBuildManifest, hashTileflowAssetSet, hashTileflowAssetSetIdentities, hashTileflowMapRevision, parseTileflowRendererDeploymentArtifact, tileflowMapBuildManifestFileName, tileflowMapBuildManifestSchemaVersion, tileflowMapRevisionCanonicalization, tileflowMapRevisionSchemaVersion, tileflowRendererDeploymentArtifactSchema, tileflowRendererDeploymentLimits, tileflowRendererDeploymentResponseSchema, tileflowSharedIconMapRevisionSchemaVersion };
599
+ export { type TileflowBuildAssetIdentity, type TileflowBuildCatalog, type TileflowBuildInspectedStyles, type TileflowBuildStyles, type TileflowCompiledMapMetadata, TileflowDataRequirementsV1, type TileflowEffectiveFontSourceIdentity, type TileflowEffectiveIconSourceIdentity, type TileflowEffectiveMapSourceAssets, type TileflowEffectiveModelSourceIdentity, type TileflowHashableBuildAsset, TileflowInspectedStyle, type TileflowMapBuildInput, type TileflowMapBuildLineageEntry, type TileflowMapBuildManifestEntryV1, type TileflowMapBuildManifestV1, type TileflowMapBuildProvenanceV1, TileflowPreparedMapAssets, type TileflowRendererDeploymentArtifact, TileflowRendererDeploymentError, type TileflowRendererDeploymentResponse, TileflowSourceRequirementsV1, type TileflowThemeBuildManifestEntryV1, collectTileflowMapBuildLineage, createManifest, createStyleFromCatalog, createStyleFromCatalogWithInspection, createStyleWithInspection, createStylesFromCatalog, createStylesFromCatalogWithInspection, createTileflowMapBuildManifest, hashTileflowAssetSet, hashTileflowAssetSetIdentities, hashTileflowMapRevision, parseTileflowRendererDeploymentArtifact, prepareTileflowNativePathGround, tileflowMapBuildManifestFileName, tileflowMapBuildManifestSchemaVersion, tileflowMapRevisionCanonicalization, tileflowMapRevisionSchemaVersion, tileflowRendererDeploymentArtifactSchema, tileflowRendererDeploymentLimits, tileflowRendererDeploymentResponseSchema, tileflowSharedIconMapRevisionSchemaVersion };
package/dist/build.js CHANGED
@@ -2536,6 +2536,28 @@ function compileLand(request, context) {
2536
2536
  target: "land.background"
2537
2537
  });
2538
2538
  }
2539
+ if (config.globalLandcoverUnderlay && schema.layers.globalLandcover && config.globalLandcover?.visible !== false) {
2540
+ const underlay = config.globalLandcoverUnderlay;
2541
+ contributions.push({
2542
+ kind: "layer",
2543
+ owner: "land",
2544
+ slot: "land",
2545
+ localOrder: 9,
2546
+ target: "land.globalLandcoverUnderlay",
2547
+ layer: {
2548
+ id: "tileflow-global-landcover-underlay",
2549
+ type: "raster",
2550
+ source: "tileflow-landcover-underlay",
2551
+ minzoom: underlay.minZoom ?? 0,
2552
+ maxzoom: underlay.maxZoom ?? 11,
2553
+ paint: {
2554
+ "raster-opacity": toMapLibreStyleValue(underlay.opacity ?? 1),
2555
+ "raster-fade-duration": 0,
2556
+ "raster-resampling": "linear"
2557
+ }
2558
+ }
2559
+ });
2560
+ }
2539
2561
  if (schema.layers.globalLandcover && config.globalLandcover?.visible !== false) {
2540
2562
  contributions.push({
2541
2563
  kind: "layer",
@@ -5161,6 +5183,7 @@ function resolvePoi(request) {
5161
5183
  density: request?.density ?? 2,
5162
5184
  detailZoom: request?.detailZoom ?? 17,
5163
5185
  densityByCategory: { ...request?.densityByCategory },
5186
+ maxRankByType: { ...request?.maxRankByType },
5164
5187
  icons: request?.icons ?? true,
5165
5188
  labels: request?.labels ?? true,
5166
5189
  minZoom: request?.minZoom ?? 0,
@@ -5644,6 +5667,9 @@ function compileCategory(category, request, semantics, context, language, select
5644
5667
  }
5645
5668
  function createPoiSelection(semantics, context, language) {
5646
5669
  const { fields: fields2 } = context.data.schema;
5670
+ const typeRankCaps = Object.entries(semantics.maxRankByType).sort(
5671
+ ([a], [b]) => a.localeCompare(b)
5672
+ );
5647
5673
  const shown = /* @__PURE__ */ new Map();
5648
5674
  const iconOnlyTypes = [...new Set(semantics.placement.iconOnlyTypes)];
5649
5675
  const iconOnly = () => iconOnlyTypes.length ? ["match", ["get", fields2.poiType], iconOnlyTypes, true, false] : ["literal", false];
@@ -5679,6 +5705,14 @@ function createPoiSelection(semantics, context, language) {
5679
5705
  [">=", sizeRank, 0],
5680
5706
  ["<=", sizeRank, 16]
5681
5707
  ];
5708
+ if (typeRankCaps.length) {
5709
+ result.push([
5710
+ "match",
5711
+ ["get", fields2.poiType],
5712
+ ...typeRankCaps.flatMap(([type, rank]) => [type, ["<=", filterRank, rank]]),
5713
+ true
5714
+ ]);
5715
+ }
5682
5716
  if (!semantics.icons || !semantics.labels) return result;
5683
5717
  const textless = categories.filter((category) => !shown.get(category)?.text);
5684
5718
  const iconless = categories.filter((category) => !shown.get(category)?.icon);
@@ -5909,6 +5943,9 @@ var visualNumberProperties = /* @__PURE__ */ new Set([
5909
5943
  "blur",
5910
5944
  "brightnessScale",
5911
5945
  "crownScale",
5946
+ "crownAnchor",
5947
+ "sizeAnchor",
5948
+ "sizeCompression",
5912
5949
  "contrast",
5913
5950
  "dash",
5914
5951
  "exaggeration",
@@ -5916,6 +5953,7 @@ var visualNumberProperties = /* @__PURE__ */ new Set([
5916
5953
  "emissiveVariation",
5917
5954
  "emissiveHeight",
5918
5955
  "colorMix",
5956
+ "colorScale",
5919
5957
  "metallic",
5920
5958
  "roughness",
5921
5959
  "horizonBlend",
@@ -5924,6 +5962,8 @@ var visualNumberProperties = /* @__PURE__ */ new Set([
5924
5962
  "lightness",
5925
5963
  "fadeDuration",
5926
5964
  "gapWidth",
5965
+ "groundOcclusion",
5966
+ "groundOcclusionRadius",
5927
5967
  "haloBlur",
5928
5968
  "haloWidth",
5929
5969
  "height",
@@ -9478,6 +9518,14 @@ function tileflowVegetationDescription(request, context) {
9478
9518
  {
9479
9519
  heightScale: number(own?.heightScale),
9480
9520
  crownScale: number(own?.crownScale),
9521
+ ...own?.sizeAnchor === void 0 ? {} : { sizeAnchor: number(own.sizeAnchor) },
9522
+ ...own?.crownAnchor === void 0 ? {} : { crownAnchor: number(own.crownAnchor) },
9523
+ ...own?.sizeCompression === void 0 ? {} : {
9524
+ sizeCompression: Math.max(
9525
+ 0,
9526
+ Math.min(1, Number(toMapLibreStyleValue(own.sizeCompression)) || 0)
9527
+ )
9528
+ },
9481
9529
  ...own?.models?.length ? { models: [...own.models] } : {}
9482
9530
  }
9483
9531
  ])
@@ -10972,8 +11020,12 @@ function readModelRoleLighting(value) {
10972
11020
  ...typeof entry.emissiveColor === "string" ? { emissiveColor: entry.emissiveColor } : {},
10973
11021
  ...typeof entry.color === "string" ? { color: entry.color } : {},
10974
11022
  ...entry.colorMix === void 0 ? {} : { colorMix: bounded(entry.colorMix, 0, 1, 1) },
11023
+ ...entry.colorScale === void 0 ? {} : { colorScale: bounded(entry.colorScale, 0, 1, 1) },
10975
11024
  ...entry.metallic === void 0 ? {} : { metallic: bounded(entry.metallic, 0, 1, 0) },
10976
11025
  ...entry.roughness === void 0 ? {} : { roughness: bounded(entry.roughness, 0, 1, 1) },
11026
+ ...entry.shading === "map" || entry.shading === "physical" ? { shading: entry.shading } : {},
11027
+ ...entry.ambientOcclusion === void 0 ? {} : { ambientOcclusion: bounded(entry.ambientOcclusion, 0, 1, 1) },
11028
+ ...entry.partColorMix === void 0 ? {} : { partColorMix: bounded(entry.partColorMix, 0, 1, 1) },
10977
11029
  ...readRoleColorVariation(entry.colorVariation),
10978
11030
  emissiveHeight: Array.isArray(gradient) && gradient.length === 5 && gradient.every(
10979
11031
  (v, i) => typeof v === "number" && Number.isFinite(v) && v <= 1 && v >= (i === 4 ? -1 : 0)
@@ -11057,6 +11109,8 @@ var tileflowDefaultBuildings3DDesign = Object.freeze({
11057
11109
  windows: false,
11058
11110
  shadows: true,
11059
11111
  occlusion: true,
11112
+ groundOcclusion: 0.16,
11113
+ groundOcclusionRadius: 3,
11060
11114
  modelOcclusion: 0.75
11061
11115
  });
11062
11116
  function tileflowBuildingsMetadata(design) {
@@ -11073,6 +11127,9 @@ function isRecord5(value) {
11073
11127
  return typeof value === "object" && value !== null && !Array.isArray(value);
11074
11128
  }
11075
11129
 
11130
+ // src/camera.ts
11131
+ var tileflowCameraMetadataKey = "tileflow:camera";
11132
+
11076
11133
  // src/data/requirements.ts
11077
11134
  import { convertFilter } from "@maplibre/maplibre-gl-style-spec";
11078
11135
  function inferTileflowDataRequirements(style, options = {}) {
@@ -11239,6 +11296,60 @@ function compareCodeUnits4(left, right) {
11239
11296
  return left < right ? -1 : left > right ? 1 : 0;
11240
11297
  }
11241
11298
 
11299
+ // src/modules/roads/path-ground.ts
11300
+ var pathTarget = /^roads\.classes\.(pathway|footway|pedestrian|steps|cycleway)\.(surface|bridge|tunnel)\.(fill|casing|shadow)$/;
11301
+ function compilePathGroundFamilies(input, options) {
11302
+ if (!options || Number(options.opacity ?? 1) === 0) return { families: input, active: false };
11303
+ const scale = Number(options.widthScale ?? 1);
11304
+ const scaled = (value) => {
11305
+ if (Array.isArray(value) && value[0] === "interpolate" && Array.isArray(value[2]) && value[2][0] === "zoom")
11306
+ return value.map((v, i) => i >= 4 && i % 2 === 0 ? ["*", v, scale] : v);
11307
+ return ["*", value ?? 1, scale];
11308
+ };
11309
+ let active = false;
11310
+ let families = input.flatMap((family) => {
11311
+ const match3 = pathTarget.exec(family.target);
11312
+ if (!match3 || match3[2] !== "surface") return [family];
11313
+ const [, kind, , phase] = match3;
11314
+ const appearance = { ...family.style.appearance };
11315
+ if (phase === "casing") appearance["line-opacity"] = 0;
11316
+ else {
11317
+ appearance["line-color"] = options.groundColor;
11318
+ appearance["line-width"] = scaled(appearance["line-width"]);
11319
+ appearance["line-opacity"] = kind === "cycleway" && phase === "fill" ? 0 : Number(options.opacity ?? 1);
11320
+ }
11321
+ const base = { ...family, style: { ...family.style, appearance } };
11322
+ if (phase === "casing" || kind === "cycleway" && phase === "fill") return [base];
11323
+ active = true;
11324
+ const overlay = {
11325
+ ...base,
11326
+ family: void 0,
11327
+ key: base.key + ".onGreen",
11328
+ target: base.target + ".onGreen",
11329
+ feature: { ...base.feature, dataSource: "tileflow-path-ground" },
11330
+ style: { ...base.style, appearance: { ...appearance, "line-color": options.greenColor } },
11331
+ origins: base.origins.map((origin) => ({ ...origin, target: base.target + ".onGreen" }))
11332
+ };
11333
+ return [base, overlay];
11334
+ });
11335
+ for (const structure of ["surface", "bridge", "tunnel"]) {
11336
+ const move = (family) => {
11337
+ const match3 = pathTarget.exec(family.target.replace(/\.onGreen$/, ""));
11338
+ return match3?.[2] === structure && (match3[3] === "fill" || structure === "surface" && match3[3] === "shadow");
11339
+ };
11340
+ const paths = families.filter(move);
11341
+ families = families.filter((f) => !move(f));
11342
+ const anchor = families.findIndex(
11343
+ (f) => new RegExp(
11344
+ `^roads\\.classes\\.(track|service|minor|tertiary|secondary|primary|trunk|motorway)\\.${structure}\\.casing$`
11345
+ ).test(f.target)
11346
+ );
11347
+ if (anchor >= 0) families.splice(anchor, 0, ...paths);
11348
+ else families.push(...paths);
11349
+ }
11350
+ return { families, active };
11351
+ }
11352
+
11242
11353
  // src/notices.ts
11243
11354
  var tileflowNoticesMetadataKey = "tileflow:notices";
11244
11355
  var tileflowNoticeLimits = Object.freeze({
@@ -11247,6 +11358,52 @@ var tileflowNoticeLimits = Object.freeze({
11247
11358
  maxTextLength: 120
11248
11359
  });
11249
11360
 
11361
+ // src/path-ground-protocol.ts
11362
+ var tileflowPathGroundProtocol = "tileflow-path-ground";
11363
+ var tileflowPathGroundSource = "tileflow-path-ground";
11364
+ function pathGroundSourceConfig(data) {
11365
+ return {
11366
+ ...data.url ? { url: data.url } : { tiles: data.tiles },
11367
+ minzoom: Math.max(12, data.minzoom ?? 0),
11368
+ maxzoom: data.maxzoom ?? 15,
11369
+ road: data.schema.layers.road,
11370
+ landcover: data.schema.layers.landcover,
11371
+ landuse: data.schema.layers.landuse,
11372
+ class: data.schema.fields.class,
11373
+ subclass: data.schema.fields.subclass,
11374
+ brunnel: data.schema.fields.brunnel
11375
+ };
11376
+ }
11377
+ function pathGroundProtocolUrl(source, tile = false) {
11378
+ return `${tileflowPathGroundProtocol}://source/${tile ? "{z}/{x}/{y}.pbf" : "index.json"}?source=${encodeURIComponent(JSON.stringify(source))}`;
11379
+ }
11380
+ function parsePathGroundRequest(value) {
11381
+ if (value.length > 16e3) throw new Error("Path context URL is too long");
11382
+ const url = new URL(value);
11383
+ if (url.protocol !== `${tileflowPathGroundProtocol}:` || url.hostname !== "source" || url.username || url.password || url.hash)
11384
+ throw new Error("Invalid path context URL");
11385
+ const source = JSON.parse(url.searchParams.get("source") ?? "null");
11386
+ if (!source || !["road", "landcover", "landuse", "class", "subclass", "brunnel"].every(
11387
+ (k) => typeof source[k] === "string"
11388
+ ))
11389
+ throw new Error("Invalid path context bindings");
11390
+ if (!source.url && !source.tiles?.length) throw new Error("Missing path context source");
11391
+ for (const endpoint of [source.url, ...source.tiles ?? []].filter((s) => !!s)) {
11392
+ const u = new URL(
11393
+ endpoint.replaceAll("{z}", "0").replaceAll("{x}", "0").replaceAll("{y}", "0")
11394
+ );
11395
+ if (!["https:", "http:"].includes(u.protocol) || u.username || u.password)
11396
+ throw new Error("Path context requires an HTTP(S) vector source");
11397
+ }
11398
+ if (url.pathname === "/index.json") return { source };
11399
+ const match3 = /^\/(\d{1,2})\/(\d+)\/(\d+)\.pbf$/.exec(url.pathname);
11400
+ if (!match3) throw new Error("Invalid path context tile");
11401
+ const [z16, x, y] = match3.slice(1).map(Number);
11402
+ if (z16 < 0 || z16 > 24 || x < 0 || y < 0 || x >= 2 ** z16 || y >= 2 ** z16)
11403
+ throw new Error("Invalid path context coordinates");
11404
+ return { source, tile: { z: z16, x, y } };
11405
+ }
11406
+
11250
11407
  // src/resolved-map-schema.ts
11251
11408
  import { Color as Color3 } from "@maplibre/maplibre-gl-style-spec";
11252
11409
  import { z as z5 } from "zod";
@@ -12119,10 +12276,18 @@ function physicalLayerIdForSemanticKey(semanticKey) {
12119
12276
  semanticKey
12120
12277
  );
12121
12278
  if (match3) return `tileflow-${match3[1]}-render-${match3[2].replaceAll(".", "-")}`;
12279
+ match3 = /^roads\.classes\.(pathway|footway|pedestrian|steps|cycleway)\.surface\.(shadow|fill)-on-green$/u.exec(
12280
+ semanticKey
12281
+ );
12282
+ if (match3) return `tileflow-road-surface-${match3[1]}-${match3[2]}-on-green`;
12122
12283
  match3 = /^roads\.classes\.([^.]+)\.(tunnel|surface|bridge)\.(shadow|casing|fill|hatch|rampFill)$/u.exec(
12123
12284
  semanticKey
12124
12285
  );
12125
12286
  if (match3) return `tileflow-road-${match3[2]}-${match3[1]}-${match3[3]}`;
12287
+ match3 = /^roads\.classes\.(pathway|footway|pedestrian|steps|cycleway)\.surface\.(shadow|fill)\.onGreen$/u.exec(
12288
+ semanticKey
12289
+ );
12290
+ if (match3) return `tileflow-road-surface-${match3[1]}-${match3[2]}-on-green`;
12126
12291
  match3 = /^roads\.cohorts\.(tunnel|surface|bridge)\.([^.]+)\.(shadow|casing|fill|rampFill)$/u.exec(
12127
12292
  semanticKey
12128
12293
  );
@@ -12210,6 +12375,7 @@ var exactPhysicalLayerIds = Object.freeze({
12210
12375
  "labels.junctions": "tileflow-label-road-junction",
12211
12376
  "land.background": "tileflow-background",
12212
12377
  "land.globalLandcover": "tileflow-global-landcover",
12378
+ "land.globalLandcoverUnderlay": "tileflow-global-landcover-underlay",
12213
12379
  poi: "tileflow-poi",
12214
12380
  "landforms.classes": "tileflow-landforms",
12215
12381
  "roads.crossings": "tileflow-road-crossing",
@@ -14305,6 +14471,19 @@ var landModuleSchema = z5.object({
14305
14471
  }).strict().optional(),
14306
14472
  enabled: z5.boolean().optional(),
14307
14473
  globalLandcover: fillStyleSchema.optional(),
14474
+ globalLandcoverUnderlay: z5.object({
14475
+ url: z5.string().min(1),
14476
+ coordinates: z5.tuple([
14477
+ z5.tuple([z5.number(), z5.number()]),
14478
+ z5.tuple([z5.number(), z5.number()]),
14479
+ z5.tuple([z5.number(), z5.number()]),
14480
+ z5.tuple([z5.number(), z5.number()])
14481
+ ]),
14482
+ attribution: z5.string().min(1),
14483
+ opacity: numberValueSchema.optional(),
14484
+ minZoom: z5.number().min(0).max(24).optional(),
14485
+ maxZoom: z5.number().min(0).max(24).optional()
14486
+ }).strict().optional(),
14308
14487
  landcover: z5.object({
14309
14488
  farmland: areaStyleSchema.optional(),
14310
14489
  flowerbed: areaStyleSchema.optional(),
@@ -14373,8 +14552,12 @@ var modelRoleLightingSchema = z5.object({
14373
14552
  emissiveColor: themeColorValueSchema.optional(),
14374
14553
  color: themeColorValueSchema.optional(),
14375
14554
  colorMix: boundedThemeNumberSchema(0, 1).optional(),
14555
+ colorScale: boundedThemeNumberSchema(0, 1).optional(),
14376
14556
  metallic: boundedThemeNumberSchema(0, 1).optional(),
14377
14557
  roughness: boundedThemeNumberSchema(0, 1).optional(),
14558
+ shading: z5.enum(["physical", "map"]).optional(),
14559
+ ambientOcclusion: boundedThemeNumberSchema(0, 1).optional(),
14560
+ partColorMix: boundedThemeNumberSchema(0, 1).optional(),
14378
14561
  colorVariation: z5.object({
14379
14562
  hue: z5.tuple([boundedThemeNumberSchema(0, 360), boundedThemeNumberSchema(0, 360)]),
14380
14563
  saturation: z5.tuple([boundedThemeNumberSchema(0, 100), boundedThemeNumberSchema(0, 100)]),
@@ -14401,7 +14584,7 @@ var buildingsModuleSchema = z5.object({
14401
14584
  lighting: z5.enum(["style", "sun"]).optional(),
14402
14585
  colorVariation: boundedThemeNumberSchema(0, 1).optional(),
14403
14586
  edges: boundedThemeNumberSchema(0, 1).optional(),
14404
- edgeRadius: z5.number().min(0).max(1).optional(),
14587
+ edgeRadius: z5.number().min(0).max(1.5).optional(),
14405
14588
  edgeColor: themeColorValueSchema.optional(),
14406
14589
  nightLight: boundedThemeNumberSchema(0, 2).optional(),
14407
14590
  floodLight: z5.object({
@@ -14423,7 +14606,10 @@ var buildingsModuleSchema = z5.object({
14423
14606
  logo: modelRoleLightingSchema.optional()
14424
14607
  }).strict().optional(),
14425
14608
  entrance: z5.object({ buildings: entranceBandSchema.optional(), models: entranceBandSchema.optional() }).strict().optional(),
14609
+ flatFootprints: z5.boolean().optional(),
14426
14610
  occlusion: z5.boolean().optional(),
14611
+ groundOcclusion: boundedThemeNumberSchema(0, 1).optional(),
14612
+ groundOcclusionRadius: boundedThemeNumberSchema(0, 20).optional(),
14427
14613
  modelOcclusion: boundedThemeNumberSchema(0, 1).optional(),
14428
14614
  shadows: z5.boolean().optional(),
14429
14615
  windows: z5.boolean().optional(),
@@ -14571,6 +14757,12 @@ var roadsModuleSchema = z5.object({
14571
14757
  "6": roadTreatmentStyleSchema.optional()
14572
14758
  }).strict().optional(),
14573
14759
  oneWayMarkers: z5.boolean().optional(),
14760
+ pathGround: z5.object({
14761
+ greenColor: themeColorValueSchema,
14762
+ groundColor: themeColorValueSchema,
14763
+ opacity: themeNumberValueSchema.optional(),
14764
+ widthScale: themeNumberValueSchema.optional()
14765
+ }).strict().optional(),
14574
14766
  outline: z5.enum(["none", "subtle", "strong"]).optional(),
14575
14767
  rampOrder: z5.enum(["below-roads", "by-class"]).describe(
14576
14768
  "Ramp fills draw below receiving roads by default. Use by-class to keep ramp fills in their road class order."
@@ -14672,6 +14864,17 @@ var poiModuleSchema = z5.object({
14672
14864
  type: z5.literal("poi"),
14673
14865
  detailZoom: z5.number().finite().gt(16).max(24).optional(),
14674
14866
  categories: z5.array(z5.enum(tileflowPoiCategories)).optional(),
14867
+ maxRankByType: z5.record(
14868
+ z5.string().regex(/^[a-z0-9]+(?:_[a-z0-9]+)*$/u, "Expected a World POI type"),
14869
+ z5.union([
14870
+ z5.literal(0),
14871
+ z5.literal(1),
14872
+ z5.literal(2),
14873
+ z5.literal(3),
14874
+ z5.literal(4),
14875
+ z5.literal(5)
14876
+ ])
14877
+ ).describe("Fixed maximum World filter rank per POI type, independent of zoom detail.").optional(),
14675
14878
  color: z5.enum(["uniform", "category"]).optional(),
14676
14879
  density: z5.union([z5.literal(1), z5.literal(2), z5.literal(3), z5.literal(4), z5.literal(5)]).describe(
14677
14880
  "POI density from 1 to 5. Defaults to 2; native collisions determine which eligible names fit."
@@ -14783,6 +14986,9 @@ var modulesSchema = z5.object({
14783
14986
  z5.object({
14784
14987
  crownScale: boundedThemeNumberSchema(0.1, 10).optional(),
14785
14988
  heightScale: boundedThemeNumberSchema(0.1, 10).optional(),
14989
+ sizeAnchor: boundedThemeNumberSchema(1, 45).optional(),
14990
+ crownAnchor: boundedThemeNumberSchema(1, 25).optional(),
14991
+ sizeCompression: boundedThemeNumberSchema(0, 1).optional(),
14786
14992
  models: z5.array(
14787
14993
  z5.string().max(64).regex(
14788
14994
  tileflowTreeModelIdPattern,
@@ -15438,6 +15644,7 @@ var systemThemesSchema = z5.object({ dark: tileflowThemeNameSchema, light: tilef
15438
15644
  var resolvedTileflowMapSchema = z5.object({
15439
15645
  atmosphere: atmosphereSchema.optional(),
15440
15646
  boundaryAreas: boundaryAreasSchema.optional(),
15647
+ camera: z5.object({ adaptivePerspective: z5.boolean().optional() }).strict().optional(),
15441
15648
  data: dataSchema.optional(),
15442
15649
  defaultTheme: tileflowThemeNameSchema,
15443
15650
  fonts: fontDirectoriesSchema.optional(),
@@ -17557,7 +17764,7 @@ function tileflowBuildings3DDesignOf(module, context, layers2, buildingModels, t
17557
17764
  ...own,
17558
17765
  emissiveStrength: number(own.emissiveStrength, 0),
17559
17766
  ...Object.fromEntries(
17560
- ["emissiveVariation", "colorMix", "metallic", "roughness"].filter((key) => own[key] !== void 0).map((key) => [key, number(own[key], 0)])
17767
+ ["emissiveVariation", "colorMix", "colorScale", "metallic", "roughness"].filter((key) => own[key] !== void 0).map((key) => [key, number(own[key], 0)])
17561
17768
  ),
17562
17769
  ...Array.isArray(own.emissiveHeight) ? { emissiveHeight: own.emissiveHeight.map((v) => number(v, 0)) } : {},
17563
17770
  ...isRecord10(own.colorVariation) ? {
@@ -17586,7 +17793,14 @@ function tileflowBuildings3DDesignOf(module, context, layers2, buildingModels, t
17586
17793
  ...readTileflowBuildingsEntrance(style.entrance),
17587
17794
  shadows: typeof style.shadows === "boolean" ? style.shadows : defaults4.shadows,
17588
17795
  occlusion: typeof style.occlusion === "boolean" ? style.occlusion : defaults4.occlusion,
17796
+ groundOcclusion: number(style.groundOcclusion, defaults4.groundOcclusion),
17797
+ groundOcclusionRadius: number(style.groundOcclusionRadius, defaults4.groundOcclusionRadius),
17589
17798
  modelOcclusion: number(style.modelOcclusion, defaults4.modelOcclusion),
17799
+ ...style.flatFootprints === false ? {
17800
+ flatLayers: layers2.filter(
17801
+ (layer) => layer.id.startsWith("tileflow-buildings-") && (layer.type === "fill" || layer.type === "line") && layer.metadata?.["tileflow:3d-toggle"] === void 0
17802
+ ).map((layer) => ({ id: layer.id, visible: layer.layout?.visibility !== "none" }))
17803
+ } : {},
17590
17804
  ...placedModels(style.models, buildingModels),
17591
17805
  ...modelColours(style.modelColors),
17592
17806
  ...landmarksOf(style.landmarks, tileflowLandmarks)
@@ -17758,6 +17972,7 @@ function compileSemanticStyleInternal(input, options, inspect, onReport) {
17758
17972
  });
17759
17973
  const platformSourceIds = [
17760
17974
  data.sourceId,
17975
+ tileflowPathGroundSource,
17761
17976
  ...terrainSources.map(({ sourceId }) => sourceId),
17762
17977
  ...marineSources.map(({ sourceId }) => sourceId),
17763
17978
  ...boundaryAreas ? [boundaryAreas.sourceId] : []
@@ -17854,9 +18069,13 @@ function compileSemanticStyleInternal(input, options, inspect, onReport) {
17854
18069
  buildingTargetsOfOtherModes(modules.buildings)
17855
18070
  )
17856
18071
  );
18072
+ const pathGround = compilePathGroundFamilies(
18073
+ stackedFamilies,
18074
+ modules.roads?.enabled === false ? void 0 : modules.roads?.pathGround
18075
+ );
17857
18076
  const plannedFamilies = runCompilationPhase(
17858
18077
  "physical-planner",
17859
- () => planTileflowLayerFamilies(stackedFamilies)
18078
+ () => planTileflowLayerFamilies(pathGround.families)
17860
18079
  );
17861
18080
  const loweredDomainIR = runCompilationPhase(
17862
18081
  "lowering",
@@ -18013,7 +18232,10 @@ function compileSemanticStyleInternal(input, options, inspect, onReport) {
18013
18232
  const primarySource = {
18014
18233
  type: "vector",
18015
18234
  ...data.url !== void 0 ? { url: data.url } : { tiles: data.tiles },
18016
- attribution: data.attribution,
18235
+ attribution: [
18236
+ data.attribution,
18237
+ ...modules.land?.globalLandcoverUnderlay ? [modules.land.globalLandcoverUnderlay.attribution] : []
18238
+ ].filter(Boolean).join(" | "),
18017
18239
  ...data.bounds ? { bounds: data.bounds } : {},
18018
18240
  ...data.maxzoom === void 0 ? {} : { maxzoom: data.maxzoom },
18019
18241
  ...data.minzoom === void 0 ? {} : { minzoom: data.minzoom }
@@ -18024,6 +18246,19 @@ function compileSemanticStyleInternal(input, options, inspect, onReport) {
18024
18246
  };
18025
18247
  const sources = {
18026
18248
  [data.sourceId]: primarySource,
18249
+ ...pathGround.active ? {
18250
+ [tileflowPathGroundSource]: {
18251
+ type: "vector",
18252
+ url: pathGroundProtocolUrl(pathGroundSourceConfig(data))
18253
+ }
18254
+ } : {},
18255
+ ...modules.land?.enabled !== false && modules.land?.globalLandcoverUnderlay && data.schema.layers.globalLandcover && modules.land.globalLandcover?.visible !== false ? {
18256
+ "tileflow-landcover-underlay": {
18257
+ type: "image",
18258
+ url: modules.land.globalLandcoverUnderlay.url,
18259
+ coordinates: modules.land.globalLandcoverUnderlay.coordinates
18260
+ }
18261
+ } : {},
18027
18262
  ...marine?.bathymetry?.vector ? { [marine.bathymetry.vector.sourceId]: marine.bathymetry.vector.source } : {},
18028
18263
  ...marine?.bathymetry?.relief ? { [marine.bathymetry.relief.sourceId]: marine.bathymetry.relief.source } : {},
18029
18264
  ...marine?.nautical ? { [marine.nautical.sourceId]: marine.nautical.source } : {},
@@ -18131,6 +18366,12 @@ function compileSemanticStyleInternal(input, options, inspect, onReport) {
18131
18366
  [tileflowOverlayPlacementManifestMetadataKey]: overlayPlacementManifest,
18132
18367
  "tileflow:modules": Object.entries(modules).filter(([, module]) => !isRecord11(module) || module.enabled !== false).map(([name]) => name).sort(),
18133
18368
  ...config.view ? { "tileflow:view": config.view } : {},
18369
+ ...config.camera?.adaptivePerspective !== void 0 ? {
18370
+ [tileflowCameraMetadataKey]: {
18371
+ version: 1,
18372
+ adaptivePerspective: config.camera.adaptivePerspective
18373
+ }
18374
+ } : {},
18134
18375
  ...notices.length > 0 ? { [tileflowNoticesMetadataKey]: notices } : {},
18135
18376
  ...nauticalLights ? { [tileflowNauticalLightsMetadataKey]: nauticalLights } : {}
18136
18377
  }
@@ -19000,6 +19241,7 @@ var TileflowMapResolutionError = class extends Error {
19000
19241
  var tileflowMapMergeStrategies = {
19001
19242
  atmosphere: "atomic",
19002
19243
  boundaryAreas: "atomic",
19244
+ camera: "deep",
19003
19245
  data: "atomic",
19004
19246
  defaultTheme: "atomic",
19005
19247
  extends: "lineage",
@@ -20045,6 +20287,41 @@ function assertIconCompositionMatchesMap(map, sources) {
20045
20287
  }
20046
20288
  }
20047
20289
 
20290
+ // src/path-ground-native.ts
20291
+ function prepareTileflowNativePathGround(style) {
20292
+ const derived = style.sources[tileflowPathGroundSource];
20293
+ if (derived?.type !== "vector" || typeof derived.url !== "string" || !derived.url.startsWith("tileflow-path-ground:"))
20294
+ return style;
20295
+ let source;
20296
+ try {
20297
+ const parsed = parsePathGroundRequest(derived.url);
20298
+ if (parsed.tile) return style;
20299
+ source = parsed.source;
20300
+ } catch {
20301
+ return style;
20302
+ }
20303
+ const overlays = style.layers.filter(
20304
+ (layer) => "source" in layer && layer.source === tileflowPathGroundSource
20305
+ );
20306
+ if (!overlays.length || overlays.some((layer) => layer.type !== "line")) return style;
20307
+ return {
20308
+ ...style,
20309
+ sources: {
20310
+ ...style.sources,
20311
+ [tileflowPathGroundSource]: {
20312
+ type: "vector",
20313
+ ...source.url ? { url: source.url } : { tiles: source.tiles },
20314
+ ...source.minzoom === void 0 ? {} : { minzoom: source.minzoom },
20315
+ ...source.maxzoom === void 0 ? {} : { maxzoom: source.maxzoom }
20316
+ }
20317
+ },
20318
+ // Keep indices and metadata references stable while the complete ground paths remain visible.
20319
+ layers: style.layers.map(
20320
+ (layer) => layer.type === "line" && layer.source === tileflowPathGroundSource ? { ...layer, paint: { ...layer.paint, "line-opacity": 0 } } : layer
20321
+ )
20322
+ };
20323
+ }
20324
+
20048
20325
  // src/style-inspection.ts
20049
20326
  function createStyleWithInspection(config, options = {}) {
20050
20327
  const compiled = parseTileflowMap(config);
@@ -20202,6 +20479,8 @@ var tileflowNativeStyleTransformationSchema = strictNativeObject({
20202
20479
  projection: z13.enum(["none", "mercator-to-implicit", "globe-to-mercator"]),
20203
20480
  /** Present when preparation removed a browser sky, which Native does not draw. */
20204
20481
  sky: z13.literal("removed").optional(),
20482
+ /** Native keeps complete ground paths without the browser-derived green overlay. */
20483
+ pathGround: z13.literal("ground-fallback").optional(),
20205
20484
  layers: z13.array(layerTransformationSchema).max(tileflowNativeProfileLimits.maximumLayers),
20206
20485
  symbolOverlap: z13.array(symbolOverlapTransformationSchema).max(tileflowNativeProfileLimits.maximumLayers)
20207
20486
  }).superRefine((style, context) => {
@@ -29724,6 +30003,7 @@ export {
29724
30003
  inferTileflowDataRequirements,
29725
30004
  inferTileflowSourceRequirements,
29726
30005
  parseTileflowRendererDeploymentArtifact,
30006
+ prepareTileflowNativePathGround,
29727
30007
  tileflowMapBuildManifestFileName,
29728
30008
  tileflowMapBuildManifestSchemaVersion,
29729
30009
  tileflowMapRevisionCanonicalization,