@tileflow/core 0.1.0-alpha.42 → 0.1.0-alpha.44

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 (50) hide show
  1. package/README.md +56 -69
  2. package/THIRD_PARTY_NOTICES.md +3 -3
  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 +425 -50
  6. package/dist/browser.d.ts +95 -5
  7. package/dist/browser.js +866 -101
  8. package/dist/build.d.ts +8 -4
  9. package/dist/build.js +250 -3
  10. package/dist/config-reference.json +3395 -2140
  11. package/dist/{icon-composition-B1A2udKb.d.ts → icon-composition-Bbw9umUA.d.ts} +37 -2
  12. package/dist/index.d.ts +13 -4
  13. package/dist/index.js +193 -3
  14. package/dist/{manifest-types-B0lQjabX.d.ts → manifest-types-CwjHd4qc.d.ts} +8 -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.js +789 -462
  19. package/dist/runtime.d.ts +1 -1
  20. package/dist/worker/camera-tile-worker.global.js +2 -2
  21. package/package.json +5 -6
  22. package/docs/application-tile-reading.md +0 -86
  23. package/docs/authoring-model.md +0 -269
  24. package/docs/boundary-areas-and-choropleths.md +0 -230
  25. package/docs/buildings-3d.md +0 -624
  26. package/docs/camera-moves-and-tile-cache.md +0 -112
  27. package/docs/capture-scenes.md +0 -40
  28. package/docs/capture-shots.md +0 -173
  29. package/docs/cartographic-defaults.md +0 -214
  30. package/docs/compiled-style-performance.md +0 -286
  31. package/docs/data-is-separate-from-design.md +0 -610
  32. package/docs/depth-markers.md +0 -65
  33. package/docs/dynamic-style-images.md +0 -100
  34. package/docs/globe-atmosphere.md +0 -113
  35. package/docs/hosted-session-authorization.md +0 -106
  36. package/docs/map-and-terrain-examples.md +0 -156
  37. package/docs/map-emphasis.md +0 -89
  38. package/docs/native-artifact-profile.md +0 -152
  39. package/docs/native-resource-urls.md +0 -369
  40. package/docs/nautical-marks.md +0 -308
  41. package/docs/public-api-and-browser-subpath.md +0 -101
  42. package/docs/route-drawing.md +0 -191
  43. package/docs/shared-visual-primitives.md +0 -101
  44. package/docs/street-lights.md +0 -127
  45. package/docs/street-sky.md +0 -156
  46. package/docs/style-states.md +0 -73
  47. package/docs/sun-and-light.md +0 -167
  48. package/docs/theme-transitions-and-blends.md +0 -317
  49. package/docs/themes-and-module-styles.md +0 -156
  50. 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-B1A2udKb.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-B1A2udKb.js';
4
- import { M as MapLibreStyle, f as TileflowTimeOfDayVariants, T as TileflowRuntimeManifest } from './manifest-types-B0lQjabX.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",
@@ -5921,6 +5943,9 @@ var visualNumberProperties = /* @__PURE__ */ new Set([
5921
5943
  "blur",
5922
5944
  "brightnessScale",
5923
5945
  "crownScale",
5946
+ "crownAnchor",
5947
+ "sizeAnchor",
5948
+ "sizeCompression",
5924
5949
  "contrast",
5925
5950
  "dash",
5926
5951
  "exaggeration",
@@ -5928,6 +5953,7 @@ var visualNumberProperties = /* @__PURE__ */ new Set([
5928
5953
  "emissiveVariation",
5929
5954
  "emissiveHeight",
5930
5955
  "colorMix",
5956
+ "colorScale",
5931
5957
  "metallic",
5932
5958
  "roughness",
5933
5959
  "horizonBlend",
@@ -5937,6 +5963,7 @@ var visualNumberProperties = /* @__PURE__ */ new Set([
5937
5963
  "fadeDuration",
5938
5964
  "gapWidth",
5939
5965
  "groundOcclusion",
5966
+ "groundOcclusionRadius",
5940
5967
  "haloBlur",
5941
5968
  "haloWidth",
5942
5969
  "height",
@@ -9491,6 +9518,14 @@ function tileflowVegetationDescription(request, context) {
9491
9518
  {
9492
9519
  heightScale: number(own?.heightScale),
9493
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
+ },
9494
9529
  ...own?.models?.length ? { models: [...own.models] } : {}
9495
9530
  }
9496
9531
  ])
@@ -10985,6 +11020,7 @@ function readModelRoleLighting(value) {
10985
11020
  ...typeof entry.emissiveColor === "string" ? { emissiveColor: entry.emissiveColor } : {},
10986
11021
  ...typeof entry.color === "string" ? { color: entry.color } : {},
10987
11022
  ...entry.colorMix === void 0 ? {} : { colorMix: bounded(entry.colorMix, 0, 1, 1) },
11023
+ ...entry.colorScale === void 0 ? {} : { colorScale: bounded(entry.colorScale, 0, 1, 1) },
10988
11024
  ...entry.metallic === void 0 ? {} : { metallic: bounded(entry.metallic, 0, 1, 0) },
10989
11025
  ...entry.roughness === void 0 ? {} : { roughness: bounded(entry.roughness, 0, 1, 1) },
10990
11026
  ...entry.shading === "map" || entry.shading === "physical" ? { shading: entry.shading } : {},
@@ -11074,6 +11110,7 @@ var tileflowDefaultBuildings3DDesign = Object.freeze({
11074
11110
  shadows: true,
11075
11111
  occlusion: true,
11076
11112
  groundOcclusion: 0.16,
11113
+ groundOcclusionRadius: 3,
11077
11114
  modelOcclusion: 0.75
11078
11115
  });
11079
11116
  function tileflowBuildingsMetadata(design) {
@@ -11090,6 +11127,9 @@ function isRecord5(value) {
11090
11127
  return typeof value === "object" && value !== null && !Array.isArray(value);
11091
11128
  }
11092
11129
 
11130
+ // src/camera.ts
11131
+ var tileflowCameraMetadataKey = "tileflow:camera";
11132
+
11093
11133
  // src/data/requirements.ts
11094
11134
  import { convertFilter } from "@maplibre/maplibre-gl-style-spec";
11095
11135
  function inferTileflowDataRequirements(style, options = {}) {
@@ -11256,6 +11296,60 @@ function compareCodeUnits4(left, right) {
11256
11296
  return left < right ? -1 : left > right ? 1 : 0;
11257
11297
  }
11258
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
+
11259
11353
  // src/notices.ts
11260
11354
  var tileflowNoticesMetadataKey = "tileflow:notices";
11261
11355
  var tileflowNoticeLimits = Object.freeze({
@@ -11264,6 +11358,52 @@ var tileflowNoticeLimits = Object.freeze({
11264
11358
  maxTextLength: 120
11265
11359
  });
11266
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
+
11267
11407
  // src/resolved-map-schema.ts
11268
11408
  import { Color as Color3 } from "@maplibre/maplibre-gl-style-spec";
11269
11409
  import { z as z5 } from "zod";
@@ -12136,10 +12276,18 @@ function physicalLayerIdForSemanticKey(semanticKey) {
12136
12276
  semanticKey
12137
12277
  );
12138
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`;
12139
12283
  match3 = /^roads\.classes\.([^.]+)\.(tunnel|surface|bridge)\.(shadow|casing|fill|hatch|rampFill)$/u.exec(
12140
12284
  semanticKey
12141
12285
  );
12142
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`;
12143
12291
  match3 = /^roads\.cohorts\.(tunnel|surface|bridge)\.([^.]+)\.(shadow|casing|fill|rampFill)$/u.exec(
12144
12292
  semanticKey
12145
12293
  );
@@ -12227,6 +12375,7 @@ var exactPhysicalLayerIds = Object.freeze({
12227
12375
  "labels.junctions": "tileflow-label-road-junction",
12228
12376
  "land.background": "tileflow-background",
12229
12377
  "land.globalLandcover": "tileflow-global-landcover",
12378
+ "land.globalLandcoverUnderlay": "tileflow-global-landcover-underlay",
12230
12379
  poi: "tileflow-poi",
12231
12380
  "landforms.classes": "tileflow-landforms",
12232
12381
  "roads.crossings": "tileflow-road-crossing",
@@ -14322,6 +14471,19 @@ var landModuleSchema = z5.object({
14322
14471
  }).strict().optional(),
14323
14472
  enabled: z5.boolean().optional(),
14324
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(),
14325
14487
  landcover: z5.object({
14326
14488
  farmland: areaStyleSchema.optional(),
14327
14489
  flowerbed: areaStyleSchema.optional(),
@@ -14390,6 +14552,7 @@ var modelRoleLightingSchema = z5.object({
14390
14552
  emissiveColor: themeColorValueSchema.optional(),
14391
14553
  color: themeColorValueSchema.optional(),
14392
14554
  colorMix: boundedThemeNumberSchema(0, 1).optional(),
14555
+ colorScale: boundedThemeNumberSchema(0, 1).optional(),
14393
14556
  metallic: boundedThemeNumberSchema(0, 1).optional(),
14394
14557
  roughness: boundedThemeNumberSchema(0, 1).optional(),
14395
14558
  shading: z5.enum(["physical", "map"]).optional(),
@@ -14443,8 +14606,10 @@ var buildingsModuleSchema = z5.object({
14443
14606
  logo: modelRoleLightingSchema.optional()
14444
14607
  }).strict().optional(),
14445
14608
  entrance: z5.object({ buildings: entranceBandSchema.optional(), models: entranceBandSchema.optional() }).strict().optional(),
14609
+ flatFootprints: z5.boolean().optional(),
14446
14610
  occlusion: z5.boolean().optional(),
14447
14611
  groundOcclusion: boundedThemeNumberSchema(0, 1).optional(),
14612
+ groundOcclusionRadius: boundedThemeNumberSchema(0, 20).optional(),
14448
14613
  modelOcclusion: boundedThemeNumberSchema(0, 1).optional(),
14449
14614
  shadows: z5.boolean().optional(),
14450
14615
  windows: z5.boolean().optional(),
@@ -14592,6 +14757,12 @@ var roadsModuleSchema = z5.object({
14592
14757
  "6": roadTreatmentStyleSchema.optional()
14593
14758
  }).strict().optional(),
14594
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(),
14595
14766
  outline: z5.enum(["none", "subtle", "strong"]).optional(),
14596
14767
  rampOrder: z5.enum(["below-roads", "by-class"]).describe(
14597
14768
  "Ramp fills draw below receiving roads by default. Use by-class to keep ramp fills in their road class order."
@@ -14815,6 +14986,9 @@ var modulesSchema = z5.object({
14815
14986
  z5.object({
14816
14987
  crownScale: boundedThemeNumberSchema(0.1, 10).optional(),
14817
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(),
14818
14992
  models: z5.array(
14819
14993
  z5.string().max(64).regex(
14820
14994
  tileflowTreeModelIdPattern,
@@ -15470,6 +15644,7 @@ var systemThemesSchema = z5.object({ dark: tileflowThemeNameSchema, light: tilef
15470
15644
  var resolvedTileflowMapSchema = z5.object({
15471
15645
  atmosphere: atmosphereSchema.optional(),
15472
15646
  boundaryAreas: boundaryAreasSchema.optional(),
15647
+ camera: z5.object({ adaptivePerspective: z5.boolean().optional() }).strict().optional(),
15473
15648
  data: dataSchema.optional(),
15474
15649
  defaultTheme: tileflowThemeNameSchema,
15475
15650
  fonts: fontDirectoriesSchema.optional(),
@@ -17589,7 +17764,7 @@ function tileflowBuildings3DDesignOf(module, context, layers2, buildingModels, t
17589
17764
  ...own,
17590
17765
  emissiveStrength: number(own.emissiveStrength, 0),
17591
17766
  ...Object.fromEntries(
17592
- ["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)])
17593
17768
  ),
17594
17769
  ...Array.isArray(own.emissiveHeight) ? { emissiveHeight: own.emissiveHeight.map((v) => number(v, 0)) } : {},
17595
17770
  ...isRecord10(own.colorVariation) ? {
@@ -17619,7 +17794,13 @@ function tileflowBuildings3DDesignOf(module, context, layers2, buildingModels, t
17619
17794
  shadows: typeof style.shadows === "boolean" ? style.shadows : defaults4.shadows,
17620
17795
  occlusion: typeof style.occlusion === "boolean" ? style.occlusion : defaults4.occlusion,
17621
17796
  groundOcclusion: number(style.groundOcclusion, defaults4.groundOcclusion),
17797
+ groundOcclusionRadius: number(style.groundOcclusionRadius, defaults4.groundOcclusionRadius),
17622
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
+ } : {},
17623
17804
  ...placedModels(style.models, buildingModels),
17624
17805
  ...modelColours(style.modelColors),
17625
17806
  ...landmarksOf(style.landmarks, tileflowLandmarks)
@@ -17791,6 +17972,7 @@ function compileSemanticStyleInternal(input, options, inspect, onReport) {
17791
17972
  });
17792
17973
  const platformSourceIds = [
17793
17974
  data.sourceId,
17975
+ tileflowPathGroundSource,
17794
17976
  ...terrainSources.map(({ sourceId }) => sourceId),
17795
17977
  ...marineSources.map(({ sourceId }) => sourceId),
17796
17978
  ...boundaryAreas ? [boundaryAreas.sourceId] : []
@@ -17887,9 +18069,13 @@ function compileSemanticStyleInternal(input, options, inspect, onReport) {
17887
18069
  buildingTargetsOfOtherModes(modules.buildings)
17888
18070
  )
17889
18071
  );
18072
+ const pathGround = compilePathGroundFamilies(
18073
+ stackedFamilies,
18074
+ modules.roads?.enabled === false ? void 0 : modules.roads?.pathGround
18075
+ );
17890
18076
  const plannedFamilies = runCompilationPhase(
17891
18077
  "physical-planner",
17892
- () => planTileflowLayerFamilies(stackedFamilies)
18078
+ () => planTileflowLayerFamilies(pathGround.families)
17893
18079
  );
17894
18080
  const loweredDomainIR = runCompilationPhase(
17895
18081
  "lowering",
@@ -18046,7 +18232,10 @@ function compileSemanticStyleInternal(input, options, inspect, onReport) {
18046
18232
  const primarySource = {
18047
18233
  type: "vector",
18048
18234
  ...data.url !== void 0 ? { url: data.url } : { tiles: data.tiles },
18049
- attribution: data.attribution,
18235
+ attribution: [
18236
+ data.attribution,
18237
+ ...modules.land?.globalLandcoverUnderlay ? [modules.land.globalLandcoverUnderlay.attribution] : []
18238
+ ].filter(Boolean).join(" | "),
18050
18239
  ...data.bounds ? { bounds: data.bounds } : {},
18051
18240
  ...data.maxzoom === void 0 ? {} : { maxzoom: data.maxzoom },
18052
18241
  ...data.minzoom === void 0 ? {} : { minzoom: data.minzoom }
@@ -18057,6 +18246,19 @@ function compileSemanticStyleInternal(input, options, inspect, onReport) {
18057
18246
  };
18058
18247
  const sources = {
18059
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
+ } : {},
18060
18262
  ...marine?.bathymetry?.vector ? { [marine.bathymetry.vector.sourceId]: marine.bathymetry.vector.source } : {},
18061
18263
  ...marine?.bathymetry?.relief ? { [marine.bathymetry.relief.sourceId]: marine.bathymetry.relief.source } : {},
18062
18264
  ...marine?.nautical ? { [marine.nautical.sourceId]: marine.nautical.source } : {},
@@ -18164,6 +18366,12 @@ function compileSemanticStyleInternal(input, options, inspect, onReport) {
18164
18366
  [tileflowOverlayPlacementManifestMetadataKey]: overlayPlacementManifest,
18165
18367
  "tileflow:modules": Object.entries(modules).filter(([, module]) => !isRecord11(module) || module.enabled !== false).map(([name]) => name).sort(),
18166
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
+ } : {},
18167
18375
  ...notices.length > 0 ? { [tileflowNoticesMetadataKey]: notices } : {},
18168
18376
  ...nauticalLights ? { [tileflowNauticalLightsMetadataKey]: nauticalLights } : {}
18169
18377
  }
@@ -19033,6 +19241,7 @@ var TileflowMapResolutionError = class extends Error {
19033
19241
  var tileflowMapMergeStrategies = {
19034
19242
  atmosphere: "atomic",
19035
19243
  boundaryAreas: "atomic",
19244
+ camera: "deep",
19036
19245
  data: "atomic",
19037
19246
  defaultTheme: "atomic",
19038
19247
  extends: "lineage",
@@ -20078,6 +20287,41 @@ function assertIconCompositionMatchesMap(map, sources) {
20078
20287
  }
20079
20288
  }
20080
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
+
20081
20325
  // src/style-inspection.ts
20082
20326
  function createStyleWithInspection(config, options = {}) {
20083
20327
  const compiled = parseTileflowMap(config);
@@ -20235,6 +20479,8 @@ var tileflowNativeStyleTransformationSchema = strictNativeObject({
20235
20479
  projection: z13.enum(["none", "mercator-to-implicit", "globe-to-mercator"]),
20236
20480
  /** Present when preparation removed a browser sky, which Native does not draw. */
20237
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(),
20238
20484
  layers: z13.array(layerTransformationSchema).max(tileflowNativeProfileLimits.maximumLayers),
20239
20485
  symbolOverlap: z13.array(symbolOverlapTransformationSchema).max(tileflowNativeProfileLimits.maximumLayers)
20240
20486
  }).superRefine((style, context) => {
@@ -29757,6 +30003,7 @@ export {
29757
30003
  inferTileflowDataRequirements,
29758
30004
  inferTileflowSourceRequirements,
29759
30005
  parseTileflowRendererDeploymentArtifact,
30006
+ prepareTileflowNativePathGround,
29760
30007
  tileflowMapBuildManifestFileName,
29761
30008
  tileflowMapBuildManifestSchemaVersion,
29762
30009
  tileflowMapRevisionCanonicalization,