@tileflow/core 0.1.0-alpha.36 → 0.1.0-alpha.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/build.js CHANGED
@@ -45,6 +45,112 @@ function compileTileflowSky(options) {
45
45
  };
46
46
  }
47
47
 
48
+ // src/models-3d-model.ts
49
+ var tileflowModelParts = Object.freeze({
50
+ surface: 0,
51
+ secondary: 1,
52
+ glass: 2,
53
+ accent: 3,
54
+ roof: 4
55
+ });
56
+ var tileflowModelLightingRoles = Object.freeze({
57
+ unclassified: 0,
58
+ wall: 1,
59
+ door: 2,
60
+ roof: 3,
61
+ window: 4,
62
+ lamp: 5,
63
+ logo: 6
64
+ });
65
+ var tileflowModelDefaultLightingRoles = Object.freeze([1, 1, 4, 1, 3]);
66
+ var tileflowModelLimits = Object.freeze({
67
+ /** Levels of detail, nearest first. */
68
+ levels: 3,
69
+ /** Vertices of one level. */
70
+ vertices: 2e5,
71
+ /** Triangles of one level. */
72
+ triangles: 2e5,
73
+ /** Points of the footprint's rings, together. */
74
+ footprintPoints: 4096,
75
+ /** Half the model's widest extent, in metres. */
76
+ radius: 2e3,
77
+ /** The model's height, in metres. */
78
+ height: 1e3,
79
+ /** Models in one prepared file, as a landmark tile holds them. */
80
+ models: 512,
81
+ /** Bytes of one prepared file. */
82
+ bytes: 16 * 1024 * 1024
83
+ });
84
+
85
+ // src/building-illumination.ts
86
+ var defaultBuildingFloodLight = Object.freeze({
87
+ intensity: 0,
88
+ brightnessScale: 1,
89
+ color: "#f5cfa8",
90
+ groundRadius: [30, 100],
91
+ minGroundHeight: 30,
92
+ minWallHeight: 200,
93
+ wallHeightRatio: 1 / 3
94
+ });
95
+ var defaultModelEmissionGradient = [0, 1, 1, 1, 0];
96
+ function readBuildingFloodLight(value) {
97
+ if (!record(value)) return void 0;
98
+ const defaults4 = defaultBuildingFloodLight;
99
+ const radius = value.groundRadius;
100
+ return {
101
+ intensity: bounded(value.intensity, 0, 1, 0),
102
+ brightnessScale: bounded(value.brightnessScale, 0, 16, 1),
103
+ color: typeof value.color === "string" ? value.color : defaults4.color,
104
+ groundRadius: Array.isArray(radius) && radius.length === 2 && radius.every((v) => typeof v === "number" && Number.isFinite(v) && v >= 0 && v <= 2048) && radius[0] <= radius[1] ? [radius[0], radius[1]] : defaults4.groundRadius,
105
+ minGroundHeight: bounded(value.minGroundHeight, 0, 6e3, defaults4.minGroundHeight),
106
+ minWallHeight: bounded(value.minWallHeight, 0, 6e3, defaults4.minWallHeight),
107
+ wallHeightRatio: bounded(value.wallHeightRatio, 0, 1, defaults4.wallHeightRatio)
108
+ };
109
+ }
110
+ function readModelRoleLighting(value) {
111
+ if (!record(value)) return void 0;
112
+ const result = {};
113
+ for (const role of Object.keys(tileflowModelLightingRoles)) {
114
+ const entry = value[role];
115
+ if (!record(entry)) continue;
116
+ const gradient = entry.emissiveHeight;
117
+ result[role] = {
118
+ emissiveStrength: bounded(entry.emissiveStrength, 0, 5, 0),
119
+ ...entry.emissiveVariation === void 0 ? {} : { emissiveVariation: bounded(entry.emissiveVariation, 0, 1, 0) },
120
+ ...typeof entry.emissiveColor === "string" ? { emissiveColor: entry.emissiveColor } : {},
121
+ ...typeof entry.color === "string" ? { color: entry.color } : {},
122
+ ...entry.colorMix === void 0 ? {} : { colorMix: bounded(entry.colorMix, 0, 1, 1) },
123
+ ...entry.metallic === void 0 ? {} : { metallic: bounded(entry.metallic, 0, 1, 0) },
124
+ ...entry.roughness === void 0 ? {} : { roughness: bounded(entry.roughness, 0, 1, 1) },
125
+ ...readRoleColorVariation(entry.colorVariation),
126
+ emissiveHeight: Array.isArray(gradient) && gradient.length === 5 && gradient.every(
127
+ (v, i) => typeof v === "number" && Number.isFinite(v) && v <= 1 && v >= (i === 4 ? -1 : 0)
128
+ ) ? gradient : defaultModelEmissionGradient
129
+ };
130
+ }
131
+ return Object.keys(result).length ? result : void 0;
132
+ }
133
+ function readRoleColorVariation(value) {
134
+ if (!record(value)) return {};
135
+ for (const [key, max] of [
136
+ ["hue", 360],
137
+ ["saturation", 100],
138
+ ["lightness", 100]
139
+ ]) {
140
+ const range2 = value[key];
141
+ if (!Array.isArray(range2) || range2.length !== 2 || range2[0] > range2[1] || !range2.every((v) => typeof v === "number" && Number.isFinite(v) && v >= 0 && v <= max))
142
+ return {};
143
+ }
144
+ if (value.space !== void 0 && value.space !== "srgb" && value.space !== "linear") return {};
145
+ return { colorVariation: value };
146
+ }
147
+ function bounded(value, min, max, fallback) {
148
+ return typeof value === "number" && Number.isFinite(value) && value >= min && value <= max ? value : fallback;
149
+ }
150
+ function record(value) {
151
+ return typeof value === "object" && value !== null && !Array.isArray(value);
152
+ }
153
+
48
154
  // src/buildings-3d-design.ts
49
155
  var tileflowBuildingsMetadataKey = "tileflow:buildings";
50
156
  var tileflowDefaultBuildings3DDesign = Object.freeze({
@@ -59,7 +165,8 @@ var tileflowDefaultBuildings3DDesign = Object.freeze({
59
165
  nightLight: 0,
60
166
  windows: false,
61
167
  shadows: true,
62
- occlusion: true
168
+ occlusion: true,
169
+ modelOcclusion: 0.75
63
170
  });
64
171
  function tileflowBuildingsMetadata(design) {
65
172
  return { version: 1, ...design };
@@ -183,26 +290,26 @@ var canonicalFields = {
183
290
  };
184
291
  var worldAttribution = '<a href="https://tileflow.dev/copyright">\xA9 Tileflow</a> <a href="https://www.openmaptiles.org/">\xA9 OpenMapTiles</a> <a href="https://www.openstreetmap.org/copyright">\xA9 OpenStreetMap</a>';
185
292
  function openMapTiles(options = {}) {
186
- const layers = { ...canonicalLayers, ...options.layers };
187
- const fields = { ...canonicalFields, ...options.fields };
188
- if (options.capabilities?.businessCorridor === false) delete layers.businessCorridor;
293
+ const layers2 = { ...canonicalLayers, ...options.layers };
294
+ const fields2 = { ...canonicalFields, ...options.fields };
295
+ if (options.capabilities?.businessCorridor === false) delete layers2.businessCorridor;
189
296
  if (options.capabilities?.bathymetry === true) {
190
- layers.bathymetry ??= "bathymetry";
191
- fields.bathymetryMinDepth ??= "min_depth";
192
- fields.bathymetrySortKey ??= "sort_key";
297
+ layers2.bathymetry ??= "bathymetry";
298
+ fields2.bathymetryMinDepth ??= "min_depth";
299
+ fields2.bathymetrySortKey ??= "sort_key";
193
300
  } else {
194
- delete layers.bathymetry;
195
- delete fields.bathymetryMinDepth;
196
- delete fields.bathymetrySortKey;
301
+ delete layers2.bathymetry;
302
+ delete fields2.bathymetryMinDepth;
303
+ delete fields2.bathymetrySortKey;
197
304
  }
198
- if (options.capabilities?.canopy === false) delete layers.canopy;
199
- if (options.capabilities?.globalLandcover === false) delete layers.globalLandcover;
200
- if (options.capabilities?.tree === false) delete layers.tree;
305
+ if (options.capabilities?.canopy === false) delete layers2.canopy;
306
+ if (options.capabilities?.globalLandcover === false) delete layers2.globalLandcover;
307
+ if (options.capabilities?.tree === false) delete layers2.tree;
201
308
  return {
202
309
  type: "openmaptiles",
203
310
  contractVersion: openMapTilesContractVersion,
204
- fields,
205
- layers,
311
+ fields: fields2,
312
+ layers: layers2,
206
313
  semantics: {
207
314
  parkLayer: options.semantics?.parkLayer ?? "mixed"
208
315
  }
@@ -496,25 +603,25 @@ function inferTileflowDataRequirements(style, options = {}) {
496
603
  for (const [index, layer] of (style.layers ?? []).entries()) {
497
604
  if (layer.source !== sourceId || typeof layer["source-layer"] !== "string") continue;
498
605
  const sourceLayer = layer["source-layer"];
499
- const fields = getOrCreate(fieldsByLayer, sourceLayer);
606
+ const fields2 = getOrCreate(fieldsByLayer, sourceLayer);
500
607
  const filter = layer.filter === void 0 ? void 0 : convertFilter(layer.filter);
501
- collectFieldAccesses(filter, fields, dynamicAccesses, `layers[${index}].filter`);
608
+ collectFieldAccesses(filter, fields2, dynamicAccesses, `layers[${index}].filter`);
502
609
  for (const key of ["layout", "paint"]) {
503
- collectFieldAccesses(layer[key], fields, dynamicAccesses, `layers[${index}].${key}`);
610
+ collectFieldAccesses(layer[key], fields2, dynamicAccesses, `layers[${index}].${key}`);
504
611
  }
505
612
  }
506
613
  for (const requirement of options.additional ?? []) {
507
614
  requirePortableName(requirement.id, "additional source layer");
508
- const fields = getOrCreate(fieldsByLayer, requirement.id);
615
+ const fields2 = getOrCreate(fieldsByLayer, requirement.id);
509
616
  for (const field2 of requirement.fields) {
510
617
  requirePortableName(field2.name, `additional field on ${requirement.id}`);
511
- const existing = fields.get(field2.name);
618
+ const existing = fields2.get(field2.name);
512
619
  if (existing !== void 0 && field2.type !== void 0 && existing !== field2.type) {
513
620
  throw new TypeError(
514
621
  `Conflicting manual data types for ${requirement.id}.${field2.name}: ${existing} and ${field2.type}.`
515
622
  );
516
623
  }
517
- fields.set(field2.name, field2.type ?? existing);
624
+ fields2.set(field2.name, field2.type ?? existing);
518
625
  }
519
626
  }
520
627
  return {
@@ -522,8 +629,8 @@ function inferTileflowDataRequirements(style, options = {}) {
522
629
  dynamicAccesses: [...dynamicAccesses].sort(compareCodeUnits),
523
630
  schemaVersion: 1,
524
631
  sourceId,
525
- sourceLayers: [...fieldsByLayer].sort(([left], [right]) => compareCodeUnits(left, right)).map(([id2, fields]) => ({
526
- fields: [...fields].sort(([left], [right]) => compareCodeUnits(left, right)).map(([name, type]) => ({ name, ...type === void 0 ? {} : { type } })),
632
+ sourceLayers: [...fieldsByLayer].sort(([left], [right]) => compareCodeUnits(left, right)).map(([id2, fields2]) => ({
633
+ fields: [...fields2].sort(([left], [right]) => compareCodeUnits(left, right)).map(([name, type]) => ({ name, ...type === void 0 ? {} : { type } })),
527
634
  id: id2
528
635
  }))
529
636
  };
@@ -598,40 +705,40 @@ function validateTileflowDataCompatibility(requirements, contract) {
598
705
  }
599
706
  return issues;
600
707
  }
601
- function collectFieldAccesses(value, fields, dynamicAccesses, path) {
708
+ function collectFieldAccesses(value, fields2, dynamicAccesses, path) {
602
709
  if (Array.isArray(value)) {
603
710
  const operator = value[0];
604
711
  if (operator === "literal") return;
605
712
  if (operator === "get" || operator === "has") {
606
713
  const featureProperties = value.length === 2 || isPropertiesExpression(value[2]);
607
714
  if (featureProperties) {
608
- if (typeof value[1] === "string") fields.set(value[1], fields.get(value[1]));
715
+ if (typeof value[1] === "string") fields2.set(value[1], fields2.get(value[1]));
609
716
  else dynamicAccesses.add(`${path}[1]`);
610
717
  }
611
718
  if (typeof value[1] !== "string") {
612
- collectFieldAccesses(value[1], fields, dynamicAccesses, `${path}[1]`);
719
+ collectFieldAccesses(value[1], fields2, dynamicAccesses, `${path}[1]`);
613
720
  }
614
721
  if (!featureProperties) {
615
- collectFieldAccesses(value[2], fields, dynamicAccesses, `${path}[2]`);
722
+ collectFieldAccesses(value[2], fields2, dynamicAccesses, `${path}[2]`);
616
723
  }
617
724
  for (let index = 3; index < value.length; index += 1) {
618
- collectFieldAccesses(value[index], fields, dynamicAccesses, `${path}[${index}]`);
725
+ collectFieldAccesses(value[index], fields2, dynamicAccesses, `${path}[${index}]`);
619
726
  }
620
727
  return;
621
728
  }
622
729
  if (operator === "properties") dynamicAccesses.add(path);
623
730
  for (let index = 1; index < value.length; index += 1) {
624
- collectFieldAccesses(value[index], fields, dynamicAccesses, `${path}[${index}]`);
731
+ collectFieldAccesses(value[index], fields2, dynamicAccesses, `${path}[${index}]`);
625
732
  }
626
733
  return;
627
734
  }
628
735
  if (!value || typeof value !== "object") return;
629
- const record3 = value;
630
- if (typeof record3.property === "string" && Array.isArray(record3.stops)) {
631
- fields.set(record3.property, fields.get(record3.property));
736
+ const record4 = value;
737
+ if (typeof record4.property === "string" && Array.isArray(record4.stops)) {
738
+ fields2.set(record4.property, fields2.get(record4.property));
632
739
  }
633
- for (const [key, child] of Object.entries(record3)) {
634
- collectFieldAccesses(child, fields, dynamicAccesses, `${path}.${key}`);
740
+ for (const [key, child] of Object.entries(record4)) {
741
+ collectFieldAccesses(child, fields2, dynamicAccesses, `${path}.${key}`);
635
742
  }
636
743
  }
637
744
  function isPropertiesExpression(value) {
@@ -1237,20 +1344,20 @@ function applySymbolStyle(layer, style) {
1237
1344
  return applyLayerRange(result, range2);
1238
1345
  }
1239
1346
  function createAreaLayers(base, style) {
1240
- const layers = [];
1347
+ const layers2 = [];
1241
1348
  if (style.fill && style.fill.visible !== false) {
1242
- layers.push({
1349
+ layers2.push({
1243
1350
  layer: applyFillStyle({ ...base, type: "fill" }, style.fill),
1244
1351
  phase: "fill"
1245
1352
  });
1246
1353
  }
1247
1354
  if (style.outline && style.outline.visible !== false) {
1248
- layers.push({
1355
+ layers2.push({
1249
1356
  layer: applyLineStyle({ ...base, id: `${base.id}-outline`, type: "line" }, style.outline),
1250
1357
  phase: "outline"
1251
1358
  });
1252
1359
  }
1253
- return layers;
1360
+ return layers2;
1254
1361
  }
1255
1362
  function applyCircleStyle(layer, style) {
1256
1363
  const paint = { ...asRecord(layer.paint) };
@@ -1861,21 +1968,21 @@ function compileBuildings(request, context) {
1861
1968
  return contributions;
1862
1969
  }
1863
1970
  function buildingColorExpression(context) {
1864
- const fields = context.data.schema.fields;
1971
+ const fields2 = context.data.schema.fields;
1865
1972
  const colors = context.colors.buildings;
1866
1973
  return [
1867
1974
  "case",
1868
- ["==", ["coalesce", ["get", fields.buildingTone], ""], "active"],
1975
+ ["==", ["coalesce", ["get", fields2.buildingTone], ""], "active"],
1869
1976
  colors.active,
1870
- ["==", ["coalesce", ["get", fields.buildingTone], ""], "destination"],
1977
+ ["==", ["coalesce", ["get", fields2.buildingTone], ""], "destination"],
1871
1978
  colors.destination,
1872
- ["==", ["coalesce", ["get", fields.buildingTone], ""], "commercial"],
1979
+ ["==", ["coalesce", ["get", fields2.buildingTone], ""], "commercial"],
1873
1980
  colors.commercial,
1874
1981
  // Without a tone, World's use class: housing, shops and offices, public buildings and works
1875
1982
  // each take their theme colour; a shed, a garage or an unknown use the generic one.
1876
1983
  [
1877
1984
  "match",
1878
- ["coalesce", ["get", fields.class], ""],
1985
+ ["coalesce", ["get", fields2.class], ""],
1879
1986
  "residential",
1880
1987
  colors.residential,
1881
1988
  "commercial",
@@ -1899,7 +2006,7 @@ function businessCorridorVisibilityFilter(context) {
1899
2006
  ];
1900
2007
  }
1901
2008
  function buildingHeightExpression(context) {
1902
- const fields = context.data.schema.fields;
2009
+ const fields2 = context.data.schema.fields;
1903
2010
  return [
1904
2011
  "max",
1905
2012
  0,
@@ -1907,7 +2014,7 @@ function buildingHeightExpression(context) {
1907
2014
  "to-number",
1908
2015
  [
1909
2016
  "coalesce",
1910
- ["get", fields.renderHeight],
2017
+ ["get", fields2.renderHeight],
1911
2018
  // V8.14 materializes this fallback in the tile. Keep the defensive
1912
2019
  // value only for malformed or legacy third-party sources.
1913
2020
  5
@@ -1917,11 +2024,11 @@ function buildingHeightExpression(context) {
1917
2024
  ];
1918
2025
  }
1919
2026
  function buildingBaseExpression(context, height) {
1920
- const fields = context.data.schema.fields;
2027
+ const fields2 = context.data.schema.fields;
1921
2028
  return [
1922
2029
  "max",
1923
2030
  0,
1924
- ["min", ["to-number", ["coalesce", ["get", fields.renderMinHeight], 0], 0], height]
2031
+ ["min", ["to-number", ["coalesce", ["get", fields2.renderMinHeight], 0], 0], height]
1925
2032
  ];
1926
2033
  }
1927
2034
 
@@ -1976,12 +2083,12 @@ var tileflowRoadConstructionClasses = [
1976
2083
  function isTileflowPathRoadClass(roadClass) {
1977
2084
  return tileflowPathRoadClasses.includes(roadClass);
1978
2085
  }
1979
- function tileflowRoadClassFilter(fields, roadClass) {
2086
+ function tileflowRoadClassFilter(fields2, roadClass) {
1980
2087
  if (isTileflowPathRoadClass(roadClass)) {
1981
2088
  return [
1982
2089
  "all",
1983
- ["match", ["get", fields.class], ["path", ...constructionClasses[roadClass]], true, false],
1984
- ["match", ["get", fields.subclass], pathSubclasses[roadClass], true, false]
2090
+ ["match", ["get", fields2.class], ["path", ...constructionClasses[roadClass]], true, false],
2091
+ ["match", ["get", fields2.subclass], pathSubclasses[roadClass], true, false]
1985
2092
  ];
1986
2093
  }
1987
2094
  const classes = roadClass === "minor" ? [
@@ -1999,7 +2106,7 @@ function tileflowRoadClassFilter(fields, roadClass) {
1999
2106
  ...compatibleRoadClasses[roadClass] ?? [],
2000
2107
  ...constructionClasses[roadClass]
2001
2108
  ];
2002
- return ["match", ["get", fields.class], classes, true, false];
2109
+ return ["match", ["get", fields2.class], classes, true, false];
2003
2110
  }
2004
2111
 
2005
2112
  // src/modules/roads/index.ts
@@ -2157,25 +2264,25 @@ function labelNameFields(language, context) {
2157
2264
  return labelFieldExpression(language, context).slice(1).map((entry) => entry[1]);
2158
2265
  }
2159
2266
  function labelFieldExpression(language, context) {
2160
- const fields = context.data.schema.fields;
2267
+ const fields2 = context.data.schema.fields;
2161
2268
  if (language === "local") {
2162
2269
  return [
2163
2270
  "coalesce",
2164
- ["get", fields.name],
2165
- ["get", fields.nameLatin],
2166
- ["get", fields.nameEnglish]
2271
+ ["get", fields2.name],
2272
+ ["get", fields2.nameLatin],
2273
+ ["get", fields2.nameEnglish]
2167
2274
  ];
2168
2275
  }
2169
2276
  if (language === "auto") {
2170
2277
  return [
2171
2278
  "coalesce",
2172
- ["get", fields.nameLatin],
2173
- ["get", fields.name],
2174
- ["get", fields.nameEnglish]
2279
+ ["get", fields2.nameLatin],
2280
+ ["get", fields2.name],
2281
+ ["get", fields2.nameEnglish]
2175
2282
  ];
2176
2283
  }
2177
- const requestedField = language === "en" ? fields.nameEnglish : `name:${language}`;
2178
- return ["coalesce", ["get", requestedField], ["get", fields.nameLatin], ["get", fields.name]];
2284
+ const requestedField = language === "en" ? fields2.nameEnglish : `name:${language}`;
2285
+ return ["coalesce", ["get", requestedField], ["get", fields2.nameLatin], ["get", fields2.name]];
2179
2286
  }
2180
2287
 
2181
2288
  // src/modules/labels/compiler.ts
@@ -2712,8 +2819,8 @@ function classFilter(field2, classes) {
2712
2819
  function aerodromeLabelExpression(detail, language, context) {
2713
2820
  const name = labelFieldExpression(language, context);
2714
2821
  if (detail === "none") return name;
2715
- const fields = context.data.schema.fields;
2716
- const code = detail === "all" ? ["coalesce", ["get", fields.iata], ["get", fields.icao], ""] : ["coalesce", ["get", fields.iata], ""];
2822
+ const fields2 = context.data.schema.fields;
2823
+ const code = detail === "all" ? ["coalesce", ["get", fields2.iata], ["get", fields2.icao], ""] : ["coalesce", ["get", fields2.iata], ""];
2717
2824
  return [
2718
2825
  "case",
2719
2826
  ["!=", ["to-string", code], ""],
@@ -2801,8 +2908,8 @@ function placePriority(rankField, base, capitals = false, capitalField = "capita
2801
2908
  function capitalFilter(capitalField) {
2802
2909
  return [">", ["to-number", ["get", capitalField], 0], 0];
2803
2910
  }
2804
- function roadClassesFilter(fields, roadClasses) {
2805
- return roadClasses.length === 1 ? tileflowRoadClassFilter(fields, roadClasses[0]) : ["any", ...roadClasses.map((roadClass) => tileflowRoadClassFilter(fields, roadClass))];
2911
+ function roadClassesFilter(fields2, roadClasses) {
2912
+ return roadClasses.length === 1 ? tileflowRoadClassFilter(fields2, roadClasses[0]) : ["any", ...roadClasses.map((roadClass) => tileflowRoadClassFilter(fields2, roadClass))];
2806
2913
  }
2807
2914
  function symbolContribution(target, localOrder, layer, slot = "symbols", family) {
2808
2915
  return {
@@ -3251,11 +3358,11 @@ function compileLandforms(request, language, context) {
3251
3358
  ];
3252
3359
  });
3253
3360
  }
3254
- function landformFilter(fields, classes) {
3255
- const classFilter4 = classes.length === 1 ? ["==", ["get", fields.class], classes[0]] : ["match", ["get", fields.class], classes, true, false];
3361
+ function landformFilter(fields2, classes) {
3362
+ const classFilter4 = classes.length === 1 ? ["==", ["get", fields2.class], classes[0]] : ["match", ["get", fields2.class], classes, true, false];
3256
3363
  const classZoom = [
3257
3364
  "match",
3258
- ["get", fields.class],
3365
+ ["get", fields2.class],
3259
3366
  "volcano",
3260
3367
  [">=", ["zoom"], 9],
3261
3368
  "peak",
@@ -3269,10 +3376,10 @@ function landformFilter(fields, classes) {
3269
3376
  return [
3270
3377
  "all",
3271
3378
  ["==", ["geometry-type"], "Point"],
3272
- ["has", fields.name],
3379
+ ["has", fields2.name],
3273
3380
  classFilter4,
3274
3381
  classZoom,
3275
- ["<=", ["to-number", ["get", fields.rank], 99], ["step", ["zoom"], 3, 12, 10, 14, 99]]
3382
+ ["<=", ["to-number", ["get", fields2.rank], 99], ["step", ["zoom"], 3, 12, 10, 14, 99]]
3276
3383
  ];
3277
3384
  }
3278
3385
  function landformContribution(target, localOrder, layer) {
@@ -3287,6 +3394,25 @@ function landformContribution(target, localOrder, layer) {
3287
3394
  }
3288
3395
 
3289
3396
  // src/modules/nautical/index.ts
3397
+ var tileflowNauticalImageRoles = Object.freeze({
3398
+ aids: Object.freeze({ default: "nautical.aid" }),
3399
+ beacons: Object.freeze({ default: "nautical.beacon" }),
3400
+ buoys: Object.freeze({
3401
+ cardinal: "nautical.buoy.cardinal",
3402
+ default: "nautical.buoy",
3403
+ port: "nautical.buoy.port",
3404
+ starboard: "nautical.buoy.starboard"
3405
+ }),
3406
+ harbours: Object.freeze({ default: "nautical.harbour" }),
3407
+ lighthouses: Object.freeze({ default: "nautical.lighthouse" }),
3408
+ lights: Object.freeze({ default: "nautical.light" }),
3409
+ ports: Object.freeze({ default: "nautical.port" }),
3410
+ wrecks: Object.freeze({ default: "nautical.wreck" })
3411
+ });
3412
+ var tileflowNauticalNotice = Object.freeze({
3413
+ id: "nautical-not-for-navigation",
3414
+ text: "Not for navigation"
3415
+ });
3290
3416
  function nautical(options = {}) {
3291
3417
  return { type: "nautical", ...cloneJson11(options) };
3292
3418
  }
@@ -3332,30 +3458,51 @@ var tileflowBathymetryV1Schema = Object.freeze({
3332
3458
  });
3333
3459
  var tileflowNauticalV1Schema = Object.freeze({
3334
3460
  fields: Object.freeze({
3461
+ category: "category",
3335
3462
  cell: "cell",
3336
3463
  character: "character",
3337
3464
  class: "class",
3338
3465
  color: "color",
3466
+ colorPattern: "color_pattern",
3467
+ country: "country",
3339
3468
  coverage: "coverage",
3340
3469
  depth: "depth",
3341
- direction: "direction",
3342
3470
  edition: "edition",
3471
+ families: "families",
3472
+ group: "group",
3473
+ heightM: "height_m",
3474
+ label: "label",
3343
3475
  licence: "licence",
3476
+ lit: "lit",
3477
+ minZoom: "min_zoom",
3344
3478
  name: "name",
3345
- provider: "provider",
3479
+ orientation: "orientation",
3480
+ periodS: "period_s",
3481
+ position: "position",
3346
3482
  provenance: "provenance",
3347
- quality: "quality",
3483
+ provider: "provider",
3348
3484
  rangeNm: "range_nm",
3485
+ rank: "rank",
3486
+ reference: "reference",
3487
+ restriction: "restriction",
3349
3488
  scale: "scale",
3489
+ sectorEnd: "sector_end",
3490
+ sectorStart: "sector_start",
3491
+ shape: "shape",
3492
+ size: "size",
3350
3493
  subclass: "subclass",
3351
- update: "update"
3494
+ system: "system",
3495
+ topmark: "topmark",
3496
+ unlocode: "unlocode",
3497
+ update: "update",
3498
+ waterLevel: "water_level"
3352
3499
  }),
3353
3500
  geometryTypes: Object.freeze({
3354
3501
  aids: Object.freeze(["Point"]),
3355
3502
  coverage: Object.freeze(["Polygon"]),
3356
- hazards: Object.freeze(["Point", "Polygon"]),
3503
+ hazards: Object.freeze(["Point", "LineString", "Polygon"]),
3357
3504
  lights: Object.freeze(["Point"]),
3358
- navigationAreas: Object.freeze(["Polygon"]),
3505
+ navigationAreas: Object.freeze(["Point", "LineString", "Polygon"]),
3359
3506
  reefs: Object.freeze(["Polygon"]),
3360
3507
  soundings: Object.freeze(["Point"]),
3361
3508
  wrecks: Object.freeze(["Point", "Polygon"])
@@ -3526,490 +3673,832 @@ function cloneJson12(value) {
3526
3673
  }
3527
3674
 
3528
3675
  // src/modules/nautical/compiler.ts
3676
+ var { fields, layers } = tileflowNauticalV1Schema;
3677
+ var markColours = Object.freeze({
3678
+ amber: "#F2A10A",
3679
+ black: "#1F2328",
3680
+ blue: "#2D6CDF",
3681
+ brown: "#8A5A2E",
3682
+ green: "#1E9E57",
3683
+ grey: "#8C939A",
3684
+ magenta: "#C2398F",
3685
+ orange: "#EF7D1A",
3686
+ pink: "#EE8AB8",
3687
+ red: "#D3313A",
3688
+ violet: "#8456C9",
3689
+ white: "#FFFFFF",
3690
+ yellow: "#F5C518"
3691
+ });
3692
+ var lightColours = Object.freeze({
3693
+ ...markColours,
3694
+ white: "#F7D046"
3695
+ });
3696
+ var floatingAidClasses = ["buoy", "light-float", "light-vessel"];
3697
+ var fixedAidClasses = ["beacon", "daymark"];
3698
+ var portLateralCategories = ["port", "preferred-channel-port", "waterway-left"];
3699
+ var starboardLateralCategories = [
3700
+ "preferred-channel-starboard",
3701
+ "starboard",
3702
+ "waterway-right"
3703
+ ];
3704
+ var exposedWaterLevels = ["above-mean-water", "awash", "covers", "dry"];
3705
+ var dangerousWreckClasses = ["dangerous", "hull-showing", "mast-showing"];
3706
+ var operationalAreaClasses = [
3707
+ "anchor-berth",
3708
+ "anchorage",
3709
+ "dumping-ground",
3710
+ "military",
3711
+ "restricted",
3712
+ "traffic-separation"
3713
+ ];
3714
+ var routeClasses = ["route", "traffic-separation"];
3715
+ var cableClasses = ["cable", "cable-area", "pipeline", "pipeline-area"];
3716
+ var portSizes = ["large", "medium", "small", "very-small"];
3529
3717
  function compileNautical(request, context) {
3530
3718
  const nauticalSource = context.marine?.nautical;
3531
3719
  if (!nauticalSource || request?.enabled === false) return [];
3532
3720
  const colors = context.colors;
3533
- const { fields, layers } = tileflowNauticalV1Schema;
3721
+ const ink = colors.hydro.label;
3722
+ const halo = colors.hydro.water;
3723
+ const accent = colors.poi.transport;
3534
3724
  const chartText = {
3535
3725
  ...typographyTextStyle(context.typography.water),
3536
- color: colors.hydro.label,
3537
- haloColor: colors.hydro.water,
3726
+ color: ink,
3727
+ haloColor: halo,
3538
3728
  haloWidth: 1.2
3539
3729
  };
3540
- const config = mergeTileflowDesign(
3541
- {
3542
- type: "nautical",
3543
- enabled: true,
3544
- soundings: {
3545
- minZoom: 12,
3546
- placement: "point",
3547
- priority: 92,
3730
+ const markText = {
3731
+ ...typographyTextStyle(context.typography.poi),
3732
+ color: ink,
3733
+ haloColor: halo,
3734
+ haloWidth: 1.2,
3735
+ transform: "none"
3736
+ };
3737
+ const images = themedImages(context);
3738
+ const rankPriority = {
3739
+ priority: expression(["coalesce", ["get", fields.rank], 9]),
3740
+ priorityOrder: "lower-first"
3741
+ };
3742
+ const nameFrom = (minZoom) => expression(["step", ["zoom"], "", minZoom, ["coalesce", ["get", fields.name], ""]]);
3743
+ const sideLabel = { anchor: "left", offset: [0.85, 0], optional: true };
3744
+ const belowLabel = { anchor: "top", offset: [0, 0.75], optional: true };
3745
+ const markColour = expression(colourMatch(firstColour(fields.color), markColours, ink));
3746
+ const markStroke = expression(colourMatch(secondColour(fields.color), markColours, ink));
3747
+ const flareColour = expression(
3748
+ colourMatch(firstColour(fields.color), lightColours, lightColours.white)
3749
+ );
3750
+ const iconPaint = { color: markColour, haloColor: ink, haloWidth: 1 };
3751
+ const defaults4 = {
3752
+ type: "nautical",
3753
+ enabled: true,
3754
+ // Coverage cells are square tiles; a faint seamless tint before marks appear avoids a grid.
3755
+ coverage: {
3756
+ fill: {
3757
+ antialias: false,
3758
+ color: ink,
3759
+ maxZoom: 8,
3760
+ opacity: zoom.linear([
3761
+ [0, 0.06],
3762
+ [5, 0.045],
3763
+ [8, 0]
3764
+ ])
3765
+ }
3766
+ },
3767
+ navigationAreas: {
3768
+ fill: {
3769
+ color: accent,
3770
+ minZoom: 7,
3771
+ opacity: expression([
3772
+ "match",
3773
+ ["get", fields.class],
3774
+ "traffic-separation",
3775
+ 0.08,
3776
+ ["military", "restricted", "dumping-ground"],
3777
+ 0.05,
3778
+ 0
3779
+ ])
3780
+ },
3781
+ outline: {
3782
+ color: expression([
3783
+ "match",
3784
+ ["get", fields.class],
3785
+ [...operationalAreaClasses],
3786
+ accent,
3787
+ ink
3788
+ ]),
3789
+ dash: [4, 2],
3790
+ minZoom: 7,
3791
+ opacity: expression([
3792
+ "interpolate",
3793
+ ["linear"],
3794
+ ["zoom"],
3795
+ 7,
3796
+ ["match", ["get", fields.class], [...operationalAreaClasses], 0.55, 0],
3797
+ 10,
3798
+ ["match", ["get", fields.class], [...operationalAreaClasses], 0.75, 0],
3799
+ 12,
3800
+ ["match", ["get", fields.class], [...operationalAreaClasses], 0.85, 0.4]
3801
+ ]),
3802
+ width: zoom.linear([
3803
+ [7, 0.6],
3804
+ [14, 1.2]
3805
+ ])
3806
+ }
3807
+ },
3808
+ reefs: {
3809
+ fill: { color: colors.landcover.sand, minZoom: 6, opacity: 0.32 },
3810
+ outline: { color: ink, dash: [1.5, 1.5], minZoom: 6, opacity: 0.6, width: 0.8 }
3811
+ },
3812
+ cables: {
3813
+ color: accent,
3814
+ dash: [2, 2],
3815
+ minZoom: 8,
3816
+ opacity: zoom.linear([
3817
+ [8, 0.3],
3818
+ [12, 0.6]
3819
+ ]),
3820
+ width: zoom.linear([
3821
+ [8, 0.6],
3822
+ [14, 1]
3823
+ ])
3824
+ },
3825
+ routes: {
3826
+ color: expression([
3827
+ "match",
3828
+ ["get", fields.class],
3829
+ "traffic-separation",
3830
+ accent,
3831
+ ink
3832
+ ]),
3833
+ dash: [5, 3],
3834
+ minZoom: 8,
3835
+ opacity: 0.72,
3836
+ width: zoom.linear([
3837
+ [8, 0.6],
3838
+ [14, 1.3]
3839
+ ])
3840
+ },
3841
+ hazardAreas: {
3842
+ fill: { color: accent, minZoom: 10, opacity: 0.08 },
3843
+ outline: { color: accent, dash: [1, 1], minZoom: 10, opacity: 0.7, width: 0.8 }
3844
+ },
3845
+ wreckAreas: {
3846
+ fill: { color: ink, minZoom: 11, opacity: 0.08 },
3847
+ outline: { color: ink, dash: [2, 1], minZoom: 11, opacity: 0.6, width: 0.75 }
3848
+ },
3849
+ soundings: {
3850
+ minZoom: 12,
3851
+ placement: "point",
3852
+ text: {
3853
+ ...chartText,
3854
+ allowOverlap: false,
3855
+ field: expression(["to-string", ["get", fields.depth]]),
3856
+ optional: false,
3857
+ padding: 5,
3858
+ size: zoom.linear([
3859
+ [12, 9],
3860
+ [16, 11]
3861
+ ]),
3862
+ transform: "none"
3863
+ }
3864
+ },
3865
+ hazards: {
3866
+ minZoom: 8,
3867
+ placement: "point",
3868
+ marker: {
3869
+ color: expression([
3870
+ "match",
3871
+ ["get", fields.class],
3872
+ "offshore-platform",
3873
+ ink,
3874
+ "rgba(0, 0, 0, 0)"
3875
+ ]),
3876
+ radius: zoom.linear([
3877
+ [8, 2.2],
3878
+ [16, 3.6]
3879
+ ]),
3880
+ strokeColor: ink,
3881
+ strokeWidth: 1.1
3882
+ },
3883
+ text: {
3884
+ ...markText,
3885
+ field: expression([
3886
+ "match",
3887
+ ["get", fields.waterLevel],
3888
+ [...exposedWaterLevels],
3889
+ "*",
3890
+ "+"
3891
+ ]),
3892
+ haloWidth: 1,
3893
+ offset: expression([
3894
+ "match",
3895
+ ["get", fields.waterLevel],
3896
+ [...exposedWaterLevels],
3897
+ ["literal", [0, 0.25]],
3898
+ ["literal", [0, 0]]
3899
+ ]),
3900
+ optional: false,
3901
+ padding: 1,
3902
+ size: zoom.linear([
3903
+ [12, 11],
3904
+ [16, 14]
3905
+ ])
3906
+ }
3907
+ },
3908
+ wrecks: {
3909
+ minZoom: 11,
3910
+ placement: "point",
3911
+ ...images.wrecks ? {
3912
+ icon: {
3913
+ color: ink,
3914
+ haloColor: halo,
3915
+ haloWidth: 1,
3916
+ image: images.wrecks,
3917
+ opacity: expression([
3918
+ "match",
3919
+ ["get", fields.class],
3920
+ [...dangerousWreckClasses],
3921
+ 1,
3922
+ 0.65
3923
+ ]),
3924
+ size: zoom.linear([
3925
+ [11, 1],
3926
+ [16, 1.4]
3927
+ ])
3928
+ },
3929
+ text: { ...markText, ...sideLabel, field: nameFrom(14), padding: 4, size: 9 }
3930
+ } : {
3548
3931
  text: {
3549
- ...chartText,
3550
- allowOverlap: false,
3551
- field: expression(["to-string", ["get", fields.depth]]),
3932
+ ...markText,
3933
+ color: expression([
3934
+ "match",
3935
+ ["get", fields.class],
3936
+ [...dangerousWreckClasses],
3937
+ accent,
3938
+ ink
3939
+ ]),
3940
+ field: "Wk",
3552
3941
  optional: false,
3553
- padding: 5,
3942
+ padding: 3,
3943
+ size: 10
3944
+ }
3945
+ }
3946
+ },
3947
+ harbours: {
3948
+ minZoom: 11,
3949
+ placement: "point",
3950
+ ...images.harbours ? {
3951
+ icon: {
3952
+ color: ink,
3953
+ haloColor: halo,
3954
+ haloWidth: 1,
3955
+ image: images.harbours,
3554
3956
  size: zoom.linear([
3555
- [12, 9],
3556
- [16, 11]
3957
+ [11, 0.9],
3958
+ [16, 1.3]
3557
3959
  ])
3558
3960
  }
3961
+ } : {
3962
+ marker: {
3963
+ color: ink,
3964
+ radius: zoom.linear([
3965
+ [11, 2.2],
3966
+ [16, 3.6]
3967
+ ]),
3968
+ strokeColor: halo,
3969
+ strokeWidth: 1
3970
+ }
3559
3971
  },
3560
- aids: {
3561
- minZoom: 10,
3562
- placement: "point",
3563
- priority: 98,
3972
+ text: { ...markText, ...belowLabel, field: nameFrom(12), padding: 4, size: 10 }
3973
+ },
3974
+ aids: {
3975
+ minZoom: 11,
3976
+ placement: "point",
3977
+ ...rankPriority,
3978
+ ...images.aids ? {
3979
+ icon: {
3980
+ ...iconPaint,
3981
+ image: images.aids,
3982
+ size: zoom.linear([
3983
+ [11, 0.8],
3984
+ [16, 1.2]
3985
+ ])
3986
+ }
3987
+ } : {
3564
3988
  marker: {
3565
- color: colors.hydro.water,
3989
+ color: halo,
3566
3990
  radius: zoom.linear([
3567
- [10, 2.6],
3568
- [16, 4.2]
3991
+ [11, 1.8],
3992
+ [16, 3]
3569
3993
  ]),
3570
- strokeColor: colors.hydro.label,
3571
- strokeWidth: 1.2
3572
- },
3573
- text: {
3574
- ...chartText,
3575
- field: expression([
3576
- "coalesce",
3577
- ["get", fields.name],
3578
- ["get", fields.subclass],
3579
- ["get", fields.class]
3994
+ strokeColor: ink,
3995
+ strokeWidth: 1
3996
+ }
3997
+ },
3998
+ text: { ...markText, ...sideLabel, field: nameFrom(15), padding: 3, size: 9 }
3999
+ },
4000
+ beacons: {
4001
+ minZoom: 11,
4002
+ placement: "point",
4003
+ ...rankPriority,
4004
+ ...images.beacons ? {
4005
+ icon: {
4006
+ ...iconPaint,
4007
+ image: images.beacons,
4008
+ size: zoom.linear([
4009
+ [11, 0.8],
4010
+ [16, 1.2]
4011
+ ])
4012
+ }
4013
+ } : {
4014
+ marker: {
4015
+ color: markColour,
4016
+ radius: zoom.linear([
4017
+ [11, 1.8],
4018
+ [16, 3.4]
3580
4019
  ]),
3581
- offset: [0, 1.1],
3582
- optional: true,
3583
- padding: 4,
3584
- size: 10
4020
+ strokeColor: markStroke,
4021
+ strokeWidth: 1
3585
4022
  }
3586
4023
  },
3587
- lighthouses: {
3588
- minZoom: 10,
3589
- placement: "point",
3590
- priority: 99,
4024
+ text: { ...markText, ...sideLabel, field: nameFrom(14), padding: 3, size: 9 }
4025
+ },
4026
+ lights: {
4027
+ minZoom: 6,
4028
+ placement: "point",
4029
+ ...rankPriority,
4030
+ ...images.lights ? {
4031
+ icon: {
4032
+ allowOverlap: true,
4033
+ color: flareColour,
4034
+ haloColor: halo,
4035
+ haloWidth: 0.5,
4036
+ ignorePlacement: true,
4037
+ image: images.lights,
4038
+ opacity: 0.9,
4039
+ size: byClassAndZoom([
4040
+ [6, 0.9, 0.65],
4041
+ [14, 1.6, 1.15]
4042
+ ])
4043
+ }
4044
+ } : {
3591
4045
  marker: {
3592
- color: colors.hydro.water,
4046
+ color: flareColour,
4047
+ opacity: 0.55,
4048
+ radius: byClassAndZoom([
4049
+ [6, 3.2, 1.8],
4050
+ [14, 7, 4.5]
4051
+ ])
4052
+ }
4053
+ },
4054
+ text: {
4055
+ ...markText,
4056
+ ...sideLabel,
4057
+ field: expression([
4058
+ "step",
4059
+ ["zoom"],
4060
+ "",
4061
+ 10,
4062
+ [
4063
+ "case",
4064
+ ["==", ["get", fields.class], "major"],
4065
+ ["coalesce", ["get", fields.label], ""],
4066
+ ""
4067
+ ],
4068
+ 13,
4069
+ ["coalesce", ["get", fields.label], ""]
4070
+ ]),
4071
+ padding: 3,
4072
+ size: zoom.linear([
4073
+ [10, 9],
4074
+ [16, 10.5]
4075
+ ])
4076
+ }
4077
+ },
4078
+ buoys: {
4079
+ minZoom: 8,
4080
+ placement: "point",
4081
+ ...rankPriority,
4082
+ ...images.buoys ? {
4083
+ icon: {
4084
+ ...iconPaint,
4085
+ // Dense harbours thin out by rank at low zooms instead of piling up.
4086
+ image: images.buoys,
4087
+ padding: 1,
4088
+ size: zoom.linear([
4089
+ [11, 1],
4090
+ [16, 1.5]
4091
+ ])
4092
+ }
4093
+ } : {
4094
+ marker: {
4095
+ color: markColour,
3593
4096
  radius: zoom.linear([
3594
- [10, 3],
4097
+ [8, 2.4],
3595
4098
  [16, 4.6]
3596
4099
  ]),
3597
- strokeColor: colors.hydro.label,
4100
+ strokeColor: markStroke,
3598
4101
  strokeWidth: 1.4
3599
- },
3600
- text: {
3601
- ...chartText,
3602
- field: expression([
3603
- "case",
3604
- ["has", fields.name],
3605
- ["to-string", ["get", fields.name]],
3606
- "Lighthouse"
3607
- ]),
3608
- offset: [0, 1.2],
3609
- optional: true,
3610
- padding: 4,
3611
- size: 10
3612
4102
  }
3613
4103
  },
3614
- lights: {
3615
- minZoom: 11,
3616
- placement: "point",
3617
- priority: 96,
4104
+ text: { ...markText, ...sideLabel, field: nameFrom(14), padding: 3, size: 9 }
4105
+ },
4106
+ lighthouses: {
4107
+ minZoom: 8,
4108
+ placement: "point",
4109
+ ...rankPriority,
4110
+ ...images.lighthouses ? {
4111
+ icon: {
4112
+ allowOverlap: true,
4113
+ color: ink,
4114
+ haloColor: halo,
4115
+ haloWidth: 1,
4116
+ image: images.lighthouses,
4117
+ size: zoom.linear([
4118
+ [8, 1],
4119
+ [16, 1.6]
4120
+ ])
4121
+ }
4122
+ } : {
3618
4123
  marker: {
3619
- color: colors.poi.transport,
3620
- opacity: 0.24,
4124
+ color: ink,
3621
4125
  radius: zoom.linear([
3622
- [11, 4],
3623
- [16, 7]
4126
+ [8, 2.6],
4127
+ [16, 4.8]
3624
4128
  ]),
3625
- strokeColor: colors.poi.transport,
3626
- strokeWidth: 1
3627
- },
3628
- text: {
3629
- ...chartText,
3630
- color: colors.poi.transport,
3631
- field: lightLabel(fields),
3632
- offset: [0, 1.25],
3633
- optional: true,
3634
- padding: 5,
3635
- size: 9
4129
+ strokeColor: halo,
4130
+ strokeWidth: 1.2
4131
+ }
4132
+ },
4133
+ text: {
4134
+ ...markText,
4135
+ ...belowLabel,
4136
+ field: nameFrom(10),
4137
+ padding: 4,
4138
+ size: zoom.linear([
4139
+ [10, 9.5],
4140
+ [16, 11.5]
4141
+ ])
4142
+ }
4143
+ },
4144
+ ports: {
4145
+ minZoom: 3,
4146
+ placement: "point",
4147
+ ...rankPriority,
4148
+ ...images.ports ? {
4149
+ icon: {
4150
+ color: ink,
4151
+ haloColor: halo,
4152
+ haloWidth: 1,
4153
+ image: images.ports,
4154
+ size: byPortSizeAndZoom([
4155
+ [3, [1.05, 0.95, 0.85, 0.75]],
4156
+ [12, [1.45, 1.35, 1.25, 1.15]]
4157
+ ])
4158
+ }
4159
+ } : {
4160
+ marker: {
4161
+ color: ink,
4162
+ radius: byPortSizeAndZoom([
4163
+ [3, [3.2, 2.8, 2.4, 2]],
4164
+ [12, [5, 4.5, 4, 3.5]]
4165
+ ]),
4166
+ strokeColor: halo,
4167
+ strokeWidth: 1.2
3636
4168
  }
3637
4169
  },
4170
+ text: {
4171
+ ...markText,
4172
+ ...belowLabel,
4173
+ field: expression(["coalesce", ["get", fields.name], ""]),
4174
+ padding: 6,
4175
+ size: byPortSizeAndZoom([
4176
+ [3, [11, 10, 9.5, 9]],
4177
+ [12, [12.5, 11.5, 11, 10.5]]
4178
+ ])
4179
+ }
4180
+ },
4181
+ labels: {
4182
+ coverage: {
4183
+ maxZoom: 9,
4184
+ minZoom: 4,
4185
+ placement: "point",
4186
+ visible: false,
4187
+ text: { ...chartText, field: expression(["get", fields.provider]), size: 8 }
4188
+ },
3638
4189
  hazards: {
3639
4190
  minZoom: 11,
3640
4191
  placement: "point",
3641
- priority: 95,
3642
- text: {
3643
- ...chartText,
3644
- color: colors.poi.transport,
3645
- field: nameAndDepthWithPrefix(fields.name, fields.depth, "X"),
3646
- optional: false,
3647
- padding: 5,
3648
- size: 12
3649
- }
4192
+ text: { ...markText, color: accent, field: expression(["get", fields.name]) }
3650
4193
  },
3651
- wrecks: {
4194
+ navigationAreas: {
3652
4195
  minZoom: 11,
3653
4196
  placement: "point",
3654
- priority: 94,
3655
4197
  text: {
3656
- ...chartText,
3657
- field: nameAndDepthWithPrefix(fields.name, fields.depth, "Wrk"),
3658
- optional: false,
3659
- padding: 5,
3660
- size: 9
4198
+ ...markText,
4199
+ color: expression([
4200
+ "match",
4201
+ ["get", fields.class],
4202
+ [...operationalAreaClasses],
4203
+ accent,
4204
+ ink
4205
+ ]),
4206
+ field: expression(["get", fields.name]),
4207
+ optional: true,
4208
+ padding: 8,
4209
+ size: 9.5
3661
4210
  }
3662
4211
  },
3663
4212
  reefs: {
3664
- fill: { color: colors.landcover.sand, minZoom: 7, opacity: 0.34 },
3665
- outline: {
3666
- color: colors.hydro.label,
3667
- dash: [1.5, 1.5],
3668
- minZoom: 7,
3669
- opacity: 0.62,
3670
- width: 0.8
3671
- }
3672
- },
3673
- hazardAreas: {
3674
- fill: { color: colors.poi.transport, minZoom: 11, opacity: 0.1 },
3675
- outline: {
3676
- color: colors.poi.transport,
3677
- dash: [1, 1],
3678
- minZoom: 11,
3679
- opacity: 0.72,
3680
- width: 0.8
3681
- }
3682
- },
3683
- wreckAreas: {
3684
- fill: { color: colors.hydro.label, minZoom: 11, opacity: 0.08 },
3685
- outline: {
3686
- color: colors.hydro.label,
3687
- dash: [2, 1],
3688
- minZoom: 11,
3689
- opacity: 0.62,
3690
- width: 0.75
3691
- }
3692
- },
3693
- navigationAreas: {
3694
- fill: { color: colors.poi.transport, minZoom: 8, opacity: 0.06 },
3695
- outline: {
3696
- color: colors.poi.transport,
3697
- dash: [4, 2],
3698
- minZoom: 8,
3699
- opacity: 0.62,
3700
- width: 0.8
3701
- }
4213
+ minZoom: 11,
4214
+ placement: "point",
4215
+ text: { ...chartText, field: expression(["get", fields.name]), size: 9 }
3702
4216
  },
3703
- coverage: {
3704
- outline: {
3705
- color: colors.poi.transport,
3706
- dash: [2, 3],
3707
- maxZoom: 9,
3708
- minZoom: 4,
3709
- opacity: 0.34,
3710
- width: 0.6
3711
- }
3712
- },
3713
- labels: {
3714
- coverage: {
3715
- maxZoom: 9,
3716
- minZoom: 4,
3717
- placement: "point",
3718
- priority: 70,
3719
- text: {
3720
- ...chartText,
3721
- color: colors.poi.transport,
3722
- field: expression(["coalesce", ["get", fields.name], ["get", fields.provider]]),
3723
- optional: true,
3724
- padding: 12,
3725
- size: 8
3726
- }
3727
- },
3728
- hazards: {
3729
- minZoom: 11,
3730
- placement: "point",
3731
- priority: 93,
3732
- text: {
3733
- ...chartText,
3734
- color: colors.poi.transport,
3735
- field: nameAndDepthWithPrefix(fields.name, fields.depth, "X"),
3736
- optional: true,
3737
- padding: 6,
3738
- size: 9
3739
- }
3740
- },
3741
- navigationAreas: {
3742
- minZoom: 10,
3743
- placement: "point",
3744
- priority: 78,
3745
- text: {
3746
- ...chartText,
3747
- color: colors.poi.transport,
3748
- field: expression(["coalesce", ["get", fields.name], ["get", fields.class]]),
3749
- optional: true,
3750
- padding: 8,
3751
- size: 9
3752
- }
3753
- },
3754
- reefs: {
3755
- minZoom: 12,
3756
- placement: "point",
3757
- priority: 89,
3758
- text: {
3759
- ...chartText,
3760
- field: nameAndDepthWithPrefix(fields.name, fields.depth, "Reef"),
3761
- optional: true,
3762
- padding: 7,
3763
- size: 9
3764
- }
3765
- },
3766
- wrecks: {
3767
- minZoom: 11,
3768
- placement: "point",
3769
- priority: 92,
3770
- text: {
3771
- ...chartText,
3772
- field: nameAndDepthWithPrefix(fields.name, fields.depth, "Wrk"),
3773
- optional: true,
3774
- padding: 6,
3775
- size: 9
3776
- }
3777
- }
4217
+ wrecks: {
4218
+ minZoom: 12,
4219
+ placement: "point",
4220
+ text: { ...markText, field: expression(["get", fields.name]), size: 9 }
3778
4221
  }
3779
- },
4222
+ }
4223
+ };
4224
+ const config = mergeTileflowDesign(
4225
+ defaults4,
3780
4226
  request
3781
4227
  );
3782
4228
  const source = nauticalSource.sourceId;
3783
4229
  const contributions = [];
3784
- appendAreaFeature(contributions, {
4230
+ const add2 = (options) => appendNauticalLayer(contributions, { ...options, source });
4231
+ add2({
4232
+ // Only coverage that speaks for every family; lists of lights alone would double the tint.
4233
+ filter: ["all", polygons, ["in", layers.aids, ["coalesce", ["get", fields.families], ""]]],
3785
4234
  id: "tileflow-nautical-coverage",
3786
4235
  localOrder: 380,
3787
- source,
3788
4236
  sourceLayer: layers.coverage,
3789
4237
  style: config.coverage,
3790
4238
  target: "nautical.coverage"
3791
4239
  });
3792
- appendAreaFeature(contributions, {
4240
+ add2({
4241
+ filter: polygons,
3793
4242
  id: "tileflow-nautical-navigation-areas",
3794
4243
  localOrder: 390,
3795
- source,
3796
4244
  sourceLayer: layers.navigationAreas,
3797
4245
  style: config.navigationAreas,
3798
4246
  target: "nautical.navigationAreas"
3799
4247
  });
3800
- appendAreaFeature(contributions, {
4248
+ add2({
4249
+ filter: polygons,
3801
4250
  id: "tileflow-nautical-reefs",
3802
4251
  localOrder: 400,
3803
- source,
3804
4252
  sourceLayer: layers.reefs,
3805
4253
  style: config.reefs,
3806
4254
  target: "nautical.reefs"
3807
4255
  });
3808
- appendAreaFeature(contributions, {
4256
+ add2({
4257
+ filter: linesOf(cableClasses),
4258
+ id: "tileflow-nautical-cables",
4259
+ line: true,
4260
+ localOrder: 404,
4261
+ sourceLayer: layers.navigationAreas,
4262
+ style: config.cables,
4263
+ target: "nautical.cables"
4264
+ });
4265
+ add2({
4266
+ filter: linesOf(routeClasses),
4267
+ id: "tileflow-nautical-routes",
4268
+ line: true,
4269
+ localOrder: 406,
4270
+ sourceLayer: layers.navigationAreas,
4271
+ style: config.routes,
4272
+ target: "nautical.routes"
4273
+ });
4274
+ add2({
4275
+ filter: polygons,
3809
4276
  id: "tileflow-nautical-hazard-areas",
3810
4277
  localOrder: 410,
3811
- source,
4278
+ outlineFilter: ["match", ["geometry-type"], ["LineString", "Polygon"], true, false],
3812
4279
  sourceLayer: layers.hazards,
3813
4280
  style: config.hazardAreas,
3814
4281
  target: "nautical.hazardAreas"
3815
4282
  });
3816
- appendAreaFeature(contributions, {
4283
+ add2({
4284
+ filter: polygons,
3817
4285
  id: "tileflow-nautical-wreck-areas",
3818
4286
  localOrder: 420,
3819
- source,
3820
4287
  sourceLayer: layers.wrecks,
3821
4288
  style: config.wreckAreas,
3822
4289
  target: "nautical.wreckAreas"
3823
4290
  });
3824
- appendPolygonLabel(contributions, {
3825
- featureFilter: ["any", ["has", fields.name], ["has", fields.provider]],
3826
- id: "tileflow-nautical-coverage-labels",
3827
- localOrder: 1060,
3828
- source,
3829
- sourceLayer: layers.coverage,
3830
- style: config.labels?.coverage,
3831
- target: "nautical.labels.coverage"
3832
- });
3833
- appendPolygonLabel(contributions, {
3834
- featureFilter: ["any", ["has", fields.name], ["has", fields.class]],
3835
- id: "tileflow-nautical-navigation-area-labels",
3836
- localOrder: 1070,
3837
- source,
3838
- sourceLayer: layers.navigationAreas,
3839
- style: config.labels?.navigationAreas,
3840
- target: "nautical.labels.navigationAreas"
3841
- });
3842
- appendPolygonLabel(contributions, {
3843
- id: "tileflow-nautical-reef-labels",
3844
- localOrder: 1080,
3845
- source,
3846
- sourceLayer: layers.reefs,
3847
- style: config.labels?.reefs,
3848
- target: "nautical.labels.reefs"
4291
+ for (const [key, id2, sourceLayer, localOrder] of [
4292
+ ["coverage", "tileflow-nautical-coverage-labels", layers.coverage, 560],
4293
+ ["navigationAreas", "tileflow-nautical-navigation-area-labels", layers.navigationAreas, 562],
4294
+ ["reefs", "tileflow-nautical-reef-labels", layers.reefs, 564],
4295
+ ["hazards", "tileflow-nautical-hazard-area-labels", layers.hazards, 566],
4296
+ ["wrecks", "tileflow-nautical-wreck-area-labels", layers.wrecks, 568]
4297
+ ]) {
4298
+ add2({
4299
+ filter: ["all", polygons, ["has", key === "coverage" ? fields.provider : fields.name]],
4300
+ id: id2,
4301
+ localOrder,
4302
+ sourceLayer,
4303
+ style: config.labels?.[key],
4304
+ target: `nautical.labels.${key}`
4305
+ });
4306
+ }
4307
+ add2({
4308
+ filter: ["all", points, ["has", fields.depth]],
4309
+ id: "tileflow-nautical-soundings",
4310
+ localOrder: 570,
4311
+ sourceLayer: layers.soundings,
4312
+ style: config.soundings,
4313
+ target: "nautical.soundings"
3849
4314
  });
3850
- appendPolygonLabel(contributions, {
3851
- id: "tileflow-nautical-hazard-area-labels",
3852
- localOrder: 1090,
3853
- source,
4315
+ add2({
4316
+ filter: points,
4317
+ id: "tileflow-nautical-hazards",
4318
+ localOrder: 574,
4319
+ markerFilter: ["!=", ["get", fields.class], "rock"],
3854
4320
  sourceLayer: layers.hazards,
3855
- style: config.labels?.hazards,
3856
- target: "nautical.labels.hazards"
4321
+ style: config.hazards,
4322
+ symbolFilter: ["==", ["get", fields.class], "rock"],
4323
+ target: "nautical.hazards"
3857
4324
  });
3858
- appendPolygonLabel(contributions, {
3859
- id: "tileflow-nautical-wreck-area-labels",
3860
- localOrder: 1095,
3861
- source,
4325
+ add2({
4326
+ filter: points,
4327
+ id: "tileflow-nautical-wrecks",
4328
+ localOrder: 578,
3862
4329
  sourceLayer: layers.wrecks,
3863
- style: config.labels?.wrecks,
3864
- target: "nautical.labels.wrecks"
4330
+ style: config.wrecks,
4331
+ target: "nautical.wrecks"
3865
4332
  });
3866
- appendPointFeature(contributions, {
3867
- id: "tileflow-nautical-soundings",
3868
- localOrder: 1100,
3869
- source,
3870
- sourceLayer: layers.soundings,
3871
- style: config.soundings,
3872
- target: "nautical.soundings",
3873
- filter: ["all", ["==", ["geometry-type"], "Point"], ["has", fields.depth]]
4333
+ add2({
4334
+ filter: ["all", points, ["==", ["get", fields.class], "harbour"]],
4335
+ id: "tileflow-nautical-harbours",
4336
+ localOrder: 582,
4337
+ sourceLayer: layers.navigationAreas,
4338
+ style: config.harbours,
4339
+ target: "nautical.harbours"
3874
4340
  });
3875
- appendPointFeature(contributions, {
4341
+ add2({
4342
+ filter: [
4343
+ "all",
4344
+ points,
4345
+ [
4346
+ "match",
4347
+ ["get", fields.class],
4348
+ [...floatingAidClasses, ...fixedAidClasses, "lighthouse"],
4349
+ false,
4350
+ true
4351
+ ]
4352
+ ],
3876
4353
  id: "tileflow-nautical-aids",
3877
- localOrder: 1110,
3878
- source,
4354
+ localOrder: 586,
3879
4355
  sourceLayer: layers.aids,
3880
4356
  style: config.aids,
3881
- target: "nautical.aids",
3882
- filter: [
3883
- "all",
3884
- ["==", ["geometry-type"], "Point"],
3885
- ["!=", ["get", fields.class], "lighthouse"]
3886
- ]
4357
+ target: "nautical.aids"
3887
4358
  });
3888
- appendPointFeature(contributions, {
3889
- id: "tileflow-nautical-lighthouses",
3890
- localOrder: 1115,
3891
- source,
4359
+ add2({
4360
+ filter: ["all", points, ["match", ["get", fields.class], [...fixedAidClasses], true, false]],
4361
+ id: "tileflow-nautical-beacons",
4362
+ localOrder: 590,
3892
4363
  sourceLayer: layers.aids,
3893
- style: config.lighthouses,
3894
- target: "nautical.lighthouses",
3895
- filter: [
3896
- "all",
3897
- ["==", ["geometry-type"], "Point"],
3898
- ["==", ["get", fields.class], "lighthouse"]
3899
- ]
4364
+ style: config.beacons,
4365
+ target: "nautical.beacons"
3900
4366
  });
3901
- appendPointFeature(contributions, {
4367
+ add2({
4368
+ filter: points,
3902
4369
  id: "tileflow-nautical-lights",
3903
- localOrder: 1120,
3904
- source,
4370
+ localOrder: 594,
3905
4371
  sourceLayer: layers.lights,
3906
4372
  style: config.lights,
3907
- target: "nautical.lights",
3908
- filter: ["==", ["geometry-type"], "Point"]
4373
+ target: "nautical.lights"
3909
4374
  });
3910
- appendPointFeature(contributions, {
3911
- id: "tileflow-nautical-hazards",
3912
- localOrder: 1130,
3913
- source,
3914
- sourceLayer: layers.hazards,
3915
- style: config.hazards,
3916
- target: "nautical.hazards",
3917
- filter: ["==", ["geometry-type"], "Point"]
4375
+ add2({
4376
+ filter: ["all", points, ["match", ["get", fields.class], [...floatingAidClasses], true, false]],
4377
+ id: "tileflow-nautical-buoys",
4378
+ localOrder: 598,
4379
+ sourceLayer: layers.aids,
4380
+ style: config.buoys,
4381
+ target: "nautical.buoys"
3918
4382
  });
3919
- appendPointFeature(contributions, {
3920
- id: "tileflow-nautical-wrecks",
3921
- localOrder: 1140,
3922
- source,
3923
- sourceLayer: layers.wrecks,
3924
- style: config.wrecks,
3925
- target: "nautical.wrecks",
3926
- filter: ["==", ["geometry-type"], "Point"]
4383
+ add2({
4384
+ filter: ["all", points, ["==", ["get", fields.class], "lighthouse"]],
4385
+ id: "tileflow-nautical-lighthouses",
4386
+ localOrder: 602,
4387
+ sourceLayer: layers.aids,
4388
+ style: config.lighthouses,
4389
+ target: "nautical.lighthouses"
4390
+ });
4391
+ add2({
4392
+ filter: ["all", points, ["==", ["get", fields.class], "port"]],
4393
+ id: "tileflow-nautical-ports",
4394
+ localOrder: 606,
4395
+ sourceLayer: layers.navigationAreas,
4396
+ style: config.ports,
4397
+ target: "nautical.ports"
3927
4398
  });
3928
4399
  return contributions;
3929
4400
  }
3930
- function appendPolygonLabel(contributions, options) {
3931
- const style = options.style;
3932
- if (!style || style.visible === false || (!style.text || style.text.visible === false) && (!style.icon || style.icon.visible === false)) {
3933
- return;
3934
- }
3935
- contributions.push(
3936
- nauticalContribution(
3937
- options.target,
3938
- options.localOrder,
3939
- applySymbolStyle(
3940
- {
3941
- id: options.id,
3942
- type: "symbol",
3943
- source: options.source,
3944
- "source-layer": options.sourceLayer,
3945
- filter: options.featureFilter ? ["all", ["==", ["geometry-type"], "Polygon"], options.featureFilter] : ["==", ["geometry-type"], "Polygon"]
3946
- },
3947
- style
3948
- ),
3949
- "symbols"
3950
- )
3951
- );
4401
+ var points = ["==", ["geometry-type"], "Point"];
4402
+ var polygons = ["==", ["geometry-type"], "Polygon"];
4403
+ function linesOf(classes) {
4404
+ return [
4405
+ "all",
4406
+ ["==", ["geometry-type"], "LineString"],
4407
+ ["match", ["get", fields.class], [...classes], true, false]
4408
+ ];
3952
4409
  }
3953
- function appendAreaFeature(contributions, options) {
3954
- if (!options.style) return;
3955
- for (const area of createAreaLayers(
3956
- {
3957
- id: options.id,
3958
- type: "fill",
3959
- source: options.source,
3960
- "source-layer": options.sourceLayer,
3961
- filter: ["==", ["geometry-type"], "Polygon"]
3962
- },
3963
- options.style
3964
- )) {
4410
+ var fromFeatureMinZoom = [">=", ["zoom"], ["to-number", ["get", fields.minZoom], 0]];
4411
+ function appendNauticalLayer(contributions, options) {
4412
+ const style = options.style;
4413
+ if (!style) return;
4414
+ const base = (id2, type, filter) => ({
4415
+ id: id2,
4416
+ type,
4417
+ source: options.source,
4418
+ "source-layer": options.sourceLayer,
4419
+ filter: ["all", filter, fromFeatureMinZoom]
4420
+ });
4421
+ if (options.line) {
4422
+ const line = style;
4423
+ if (line.visible === false) return;
3965
4424
  contributions.push(
3966
4425
  nauticalContribution(
3967
- `${options.target}.${area.phase}`,
3968
- options.localOrder + (area.phase === "fill" ? 0 : 1),
3969
- area.layer,
4426
+ options.target,
4427
+ options.localOrder,
4428
+ applyLineStyle(base(options.id, "line", options.filter), line),
3970
4429
  "hydro"
3971
4430
  )
3972
4431
  );
4432
+ return;
3973
4433
  }
3974
- }
3975
- function appendPointFeature(contributions, options) {
3976
- const style = options.style;
3977
- if (!style || style.visible === false) return;
3978
- const symbolStyle2 = withoutMarker(style);
3979
- const base = {
3980
- id: options.id,
3981
- type: "symbol",
3982
- source: options.source,
3983
- "source-layer": options.sourceLayer,
3984
- filter: options.filter
3985
- };
3986
- if (style.marker && style.marker.visible !== false) {
4434
+ if ("fill" in style || "outline" in style) {
4435
+ const area = style;
4436
+ if (area.fill && area.fill.visible !== false) {
4437
+ contributions.push(
4438
+ nauticalContribution(
4439
+ `${options.target}.fill`,
4440
+ options.localOrder,
4441
+ applyFillStyle(base(options.id, "fill", options.filter), area.fill),
4442
+ "hydro"
4443
+ )
4444
+ );
4445
+ }
4446
+ if (area.outline && area.outline.visible !== false) {
4447
+ contributions.push(
4448
+ nauticalContribution(
4449
+ `${options.target}.outline`,
4450
+ options.localOrder + 1,
4451
+ applyLineStyle(
4452
+ base(`${options.id}-outline`, "line", options.outlineFilter ?? options.filter),
4453
+ area.outline
4454
+ ),
4455
+ "hydro"
4456
+ )
4457
+ );
4458
+ }
4459
+ return;
4460
+ }
4461
+ const point = style;
4462
+ if (point.visible === false) return;
4463
+ const isLabel = options.target.startsWith("nautical.labels.");
4464
+ if (!isLabel && point.marker && point.marker.visible !== false) {
3987
4465
  contributions.push(
3988
4466
  nauticalContribution(
3989
4467
  `${options.target}.marker`,
3990
4468
  options.localOrder,
3991
4469
  applyCircleStyle(
3992
- { ...base, id: `${options.id}-marker`, type: "circle" },
4470
+ base(
4471
+ `${options.id}-marker`,
4472
+ "circle",
4473
+ options.markerFilter ? ["all", options.filter, options.markerFilter] : options.filter
4474
+ ),
3993
4475
  mergeTileflowDesign(
3994
4476
  {
3995
- ...style.maxZoom === void 0 ? {} : { maxZoom: style.maxZoom },
3996
- ...style.minZoom === void 0 ? {} : { minZoom: style.minZoom }
4477
+ ...point.maxZoom === void 0 ? {} : { maxZoom: point.maxZoom },
4478
+ ...point.minZoom === void 0 ? {} : { minZoom: point.minZoom }
3997
4479
  },
3998
- style.marker
4480
+ point.marker
3999
4481
  )
4000
4482
  ),
4001
4483
  "symbols"
4002
4484
  )
4003
4485
  );
4004
4486
  }
4005
- const hasText = Boolean(style.text && style.text.visible !== false);
4006
- const hasIcon = Boolean(style.icon && style.icon.visible !== false);
4487
+ const hasText = Boolean(point.text && point.text.visible !== false);
4488
+ const hasIcon = Boolean(point.icon && point.icon.visible !== false);
4007
4489
  if (!hasText && !hasIcon) return;
4008
4490
  contributions.push(
4009
4491
  nauticalContribution(
4010
- `${options.target}.symbol`,
4011
- options.localOrder + 1,
4012
- applySymbolStyle(base, symbolStyle2),
4492
+ isLabel ? options.target : `${options.target}.symbol`,
4493
+ options.localOrder + (isLabel ? 0 : 1),
4494
+ applySymbolStyle(
4495
+ base(
4496
+ options.id,
4497
+ "symbol",
4498
+ options.symbolFilter ? ["all", options.filter, options.symbolFilter] : options.filter
4499
+ ),
4500
+ withoutMarker(point)
4501
+ ),
4013
4502
  "symbols"
4014
4503
  )
4015
4504
  );
@@ -4022,31 +4511,107 @@ function withoutMarker(style) {
4022
4511
  function nauticalContribution(target, localOrder, layer, slot) {
4023
4512
  return { kind: "layer", layer, localOrder, owner: "nautical", slot, target };
4024
4513
  }
4025
- function nameAndDepthWithPrefix(nameField, depthField, prefix) {
4514
+ function themedImages(context) {
4515
+ const roles = tileflowNauticalImageRoles;
4516
+ const images = {};
4517
+ for (const group of Object.keys(roles)) {
4518
+ const image = context.images[roles[group].default];
4519
+ if (image) images[group] = image;
4520
+ }
4521
+ const buoy = images.buoys;
4522
+ if (typeof buoy === "string") {
4523
+ const port = context.images[roles.buoys.port] ?? buoy;
4524
+ const starboard = context.images[roles.buoys.starboard] ?? buoy;
4525
+ const cardinal = context.images[roles.buoys.cardinal] ?? buoy;
4526
+ images.buoys = expression([
4527
+ "case",
4528
+ ["==", ["get", fields.subclass], "cardinal"],
4529
+ cardinal,
4530
+ [
4531
+ "match",
4532
+ ["get", fields.category],
4533
+ [...portLateralCategories],
4534
+ port,
4535
+ [...starboardLateralCategories],
4536
+ starboard,
4537
+ buoy
4538
+ ]
4539
+ ]);
4540
+ }
4541
+ return images;
4542
+ }
4543
+ function firstColour(field2) {
4544
+ return [
4545
+ "let",
4546
+ "nauticalColours",
4547
+ ["to-string", ["coalesce", ["get", field2], ""]],
4548
+ leadingName(["var", "nauticalColours"])
4549
+ ];
4550
+ }
4551
+ function secondColour(field2) {
4552
+ return [
4553
+ "let",
4554
+ "nauticalColours",
4555
+ ["to-string", ["coalesce", ["get", field2], ""]],
4556
+ [
4557
+ "let",
4558
+ "nauticalComma",
4559
+ ["index-of", ",", ["var", "nauticalColours"]],
4560
+ [
4561
+ "case",
4562
+ ["<", ["var", "nauticalComma"], 0],
4563
+ "",
4564
+ [
4565
+ "let",
4566
+ "nauticalRest",
4567
+ ["slice", ["var", "nauticalColours"], ["+", ["var", "nauticalComma"], 1]],
4568
+ leadingName(["var", "nauticalRest"])
4569
+ ]
4570
+ ]
4571
+ ]
4572
+ ];
4573
+ }
4574
+ function leadingName(list) {
4575
+ return [
4576
+ "let",
4577
+ "nauticalEnd",
4578
+ ["index-of", ",", list],
4579
+ ["case", ["<", ["var", "nauticalEnd"], 0], list, ["slice", list, 0, ["var", "nauticalEnd"]]]
4580
+ ];
4581
+ }
4582
+ function colourMatch(name, palette, fallback) {
4583
+ return [
4584
+ "match",
4585
+ name,
4586
+ ...Object.entries(palette).flatMap(([colourName, value]) => [colourName, value]),
4587
+ fallback
4588
+ ];
4589
+ }
4590
+ function byClassAndZoom(stops) {
4026
4591
  return expression([
4027
- "concat",
4028
- prefix,
4029
- ["case", ["has", nameField], ["concat", " ", ["to-string", ["get", nameField]]], ""],
4030
- ["case", ["has", depthField], ["concat", " ", ["to-string", ["get", depthField]], "m"], ""]
4592
+ "interpolate",
4593
+ ["linear"],
4594
+ ["zoom"],
4595
+ ...stops.flatMap(([stop, major, minor]) => [
4596
+ stop,
4597
+ ["match", ["get", fields.class], "major", major, minor]
4598
+ ])
4031
4599
  ]);
4032
4600
  }
4033
- function lightLabel(fields) {
4601
+ function byPortSizeAndZoom(stops) {
4034
4602
  return expression([
4035
- "concat",
4036
- ["case", ["has", fields.character], ["to-string", ["get", fields.character]], "Lt"],
4037
- [
4038
- "case",
4039
- ["has", fields.rangeNm],
4040
- ["concat", " ", ["to-string", ["get", fields.rangeNm]], "M"],
4041
- ""
4042
- ],
4043
- [
4044
- "case",
4045
- ["has", fields.direction],
4046
- ["concat", " ", ["to-string", ["get", fields.direction]], "\xB0"],
4047
- ""
4048
- ],
4049
- ["case", ["has", fields.name], ["concat", " ", ["to-string", ["get", fields.name]]], ""]
4603
+ "interpolate",
4604
+ ["linear"],
4605
+ ["zoom"],
4606
+ ...stops.flatMap(([stop, values]) => [
4607
+ stop,
4608
+ [
4609
+ "match",
4610
+ ["get", fields.size],
4611
+ ...portSizes.flatMap((size, index) => [size, values[index]]),
4612
+ values[3]
4613
+ ]
4614
+ ])
4050
4615
  ]);
4051
4616
  }
4052
4617
 
@@ -4211,12 +4776,12 @@ function mergePoiCategoryLayers(entries, options) {
4211
4776
  };
4212
4777
  for (const part of ["layout", "paint"]) {
4213
4778
  const records = entries.map(({ layer }) => asRecord2(layer[part]));
4214
- const properties2 = [...new Set(records.flatMap((record3) => Object.keys(record3)))].sort();
4779
+ const properties2 = [...new Set(records.flatMap((record4) => Object.keys(record4)))].sort();
4215
4780
  const merged = {};
4216
4781
  for (const property of properties2) {
4217
4782
  const fallback = Object.hasOwn(varying, property) ? varying[property] : tileflowPoiLayerPropertyDefaults[property];
4218
4783
  const values = records.map(
4219
- (record3) => Object.hasOwn(record3, property) ? record3[property] : fallback
4784
+ (record4) => Object.hasOwn(record4, property) ? record4[property] : fallback
4220
4785
  );
4221
4786
  if (values.every((value) => sameJson(value, values[0]))) {
4222
4787
  if (values[0] !== void 0) merged[property] = values[0];
@@ -4575,11 +5140,11 @@ function compileCategory(category, request, semantics, context, language, select
4575
5140
  return parts;
4576
5141
  }
4577
5142
  function createPoiSelection(semantics, context, language) {
4578
- const { fields } = context.data.schema;
5143
+ const { fields: fields2 } = context.data.schema;
4579
5144
  const shown = /* @__PURE__ */ new Map();
4580
5145
  const iconOnlyTypes = [...new Set(semantics.placement.iconOnlyTypes)];
4581
- const iconOnly = () => iconOnlyTypes.length ? ["match", ["get", fields.poiType], iconOnlyTypes, true, false] : ["literal", false];
4582
- const inCategories = (categories) => categories.length === 1 ? ["==", ["get", fields.poiCategory], categories[0]] : ["match", ["get", fields.poiCategory], [...categories], true, false];
5146
+ const iconOnly = () => iconOnlyTypes.length ? ["match", ["get", fields2.poiType], iconOnlyTypes, true, false] : ["literal", false];
5147
+ const inCategories = (categories) => categories.length === 1 ? ["==", ["get", fields2.poiCategory], categories[0]] : ["match", ["get", fields2.poiCategory], [...categories], true, false];
4583
5148
  const named = () => [
4584
5149
  "any",
4585
5150
  ...labelNameFields(language, context).map((field2) => ["has", field2])
@@ -4592,22 +5157,22 @@ function createPoiSelection(semantics, context, language) {
4592
5157
  if (!iconOnlyTypes.length || field2 === void 0) return field2;
4593
5158
  return expression([
4594
5159
  "match",
4595
- ["get", fields.poiType],
5160
+ ["get", fields2.poiType],
4596
5161
  iconOnlyTypes,
4597
5162
  "",
4598
5163
  fieldValue(field2)
4599
5164
  ]);
4600
5165
  },
4601
5166
  filter(categories, representation) {
4602
- const filterRank = numericPoiField(fields.poiFilterRank, 6);
4603
- const sizeRank = numericPoiField(fields.poiSizeRank, 17);
5167
+ const filterRank = numericPoiField(fields2.poiFilterRank, 6);
5168
+ const sizeRank = numericPoiField(fields2.poiSizeRank, 17);
4604
5169
  const result = [
4605
5170
  "all",
4606
5171
  inCategories(categories),
4607
- ["has", fields.poiFilterRank],
5172
+ ["has", fields2.poiFilterRank],
4608
5173
  [">=", filterRank, 0],
4609
5174
  ["<=", filterRank, poiRankThreshold(semantics.density)],
4610
- ["has", fields.poiSizeRank],
5175
+ ["has", fields2.poiSizeRank],
4611
5176
  [">=", sizeRank, 0],
4612
5177
  ["<=", sizeRank, 16]
4613
5178
  ];
@@ -4830,9 +5395,19 @@ var visualNumberProperties = /* @__PURE__ */ new Set([
4830
5395
  "angle",
4831
5396
  "base",
4832
5397
  "blur",
5398
+ "brightnessScale",
4833
5399
  "crownScale",
4834
5400
  "dash",
4835
5401
  "exaggeration",
5402
+ "emissiveStrength",
5403
+ "emissiveVariation",
5404
+ "emissiveHeight",
5405
+ "colorMix",
5406
+ "metallic",
5407
+ "roughness",
5408
+ "hue",
5409
+ "saturation",
5410
+ "lightness",
4836
5411
  "fadeDuration",
4837
5412
  "gapWidth",
4838
5413
  "haloBlur",
@@ -4846,6 +5421,7 @@ var visualNumberProperties = /* @__PURE__ */ new Set([
4846
5421
  "maxAngle",
4847
5422
  "maxWidth",
4848
5423
  "miterLimit",
5424
+ "modelOcclusion",
4849
5425
  "offset",
4850
5426
  "opacity",
4851
5427
  "padding",
@@ -5694,13 +6270,13 @@ function assertThemeIdentity(theme) {
5694
6270
  }
5695
6271
  }
5696
6272
  function assertThemeDocument(theme) {
5697
- const record3 = assertPlainThemeRecord(theme, "theme");
5698
- assertExactThemeKeys(record3, "theme", themeDocumentKeys);
5699
- assertRequiredThemeKeys(record3, "theme", themeDocumentKeys);
6273
+ const record4 = assertPlainThemeRecord(theme, "theme");
6274
+ assertExactThemeKeys(record4, "theme", themeDocumentKeys);
6275
+ assertRequiredThemeKeys(record4, "theme", themeDocumentKeys);
5700
6276
  assertThemeIdentity(theme);
5701
- assertThemeTokens(record3.tokens, "theme.tokens", true);
5702
- assertThemeTypography(record3.typography, "theme.typography");
5703
- assertThemeLighting(record3.lighting, "theme.lighting");
6277
+ assertThemeTokens(record4.tokens, "theme.tokens", true);
6278
+ assertThemeTypography(record4.typography, "theme.typography");
6279
+ assertThemeLighting(record4.lighting, "theme.lighting");
5704
6280
  cloneJson14(theme);
5705
6281
  }
5706
6282
  function assertThemeTokens(value, path, complete) {
@@ -6656,12 +7232,12 @@ function rgbToHex(r, g, b) {
6656
7232
 
6657
7233
  // src/modules/roads/roundabouts.ts
6658
7234
  function compileRoundabouts(request, surfaces, context, contributions) {
6659
- const { fields, layers } = context.data.schema;
6660
- if (!layers.circularFeature) return;
7235
+ const { fields: fields2, layers: layers2 } = context.data.schema;
7236
+ if (!layers2.circularFeature) return;
6661
7237
  const drawn = surfaces.filter(({ fill }) => fill && fill.visible !== false);
6662
7238
  if (!drawn.length) return;
6663
7239
  const values = (resolve) => drawn.map((surface) => ({
6664
- condition: tileflowRoadClassFilter(fields, surface.roadClass),
7240
+ condition: tileflowRoadClassFilter(fields2, surface.roadClass),
6665
7241
  value: toMapLibreStyleValue(resolve(surface))
6666
7242
  }));
6667
7243
  const widths = values(({ fill }) => fill?.width ?? 1);
@@ -6669,10 +7245,10 @@ function compileRoundabouts(request, surfaces, context, contributions) {
6669
7245
  const gaps = values(({ casing }) => casing?.gapWidth ?? 0);
6670
7246
  const fallbackWidth = request?.fallbackWidth === void 0 ? void 0 : toMapLibreStyleValue(request.fallbackWidth);
6671
7247
  const borderWidth = request?.borderWidth === void 0 ? void 0 : toMapLibreStyleValue(request.borderWidth);
6672
- const radiusAt15 = ["to-number", ["get", fields.circularRadiusAtZoom15], 0];
6673
- const radiusMeters = ["to-number", ["get", fields.circularRadiusMeters], 0];
6674
- const innerMeters = ["to-number", ["get", fields.circularInnerRadiusMeters], 0];
6675
- const outerMeters = ["to-number", ["get", fields.circularOuterRadiusMeters], 0];
7248
+ const radiusAt15 = ["to-number", ["get", fields2.circularRadiusAtZoom15], 0];
7249
+ const radiusMeters = ["to-number", ["get", fields2.circularRadiusMeters], 0];
7250
+ const innerMeters = ["to-number", ["get", fields2.circularInnerRadiusMeters], 0];
7251
+ const outerMeters = ["to-number", ["get", fields2.circularOuterRadiusMeters], 0];
6676
7252
  const physical = [
6677
7253
  "all",
6678
7254
  [">", radiusMeters, 0],
@@ -6740,7 +7316,7 @@ function compileRoundabouts(request, surfaces, context, contributions) {
6740
7316
  strokeWidth: geometry(phase === "casing", true),
6741
7317
  strokeColor: phase === "casing" ? context.colors.roads.casing : expression([
6742
7318
  "match",
6743
- ["coalesce", ["get", fields.class], "minor"],
7319
+ ["coalesce", ["get", fields2.class], "minor"],
6744
7320
  "motorway",
6745
7321
  context.colors.roads.motorway,
6746
7322
  "trunk",
@@ -6751,7 +7327,7 @@ function compileRoundabouts(request, surfaces, context, contributions) {
6751
7327
  context.colors.roads.secondary,
6752
7328
  context.colors.roads.minor
6753
7329
  ]),
6754
- strokeOpacity: phaseVisibility(drawn, phase, fields)
7330
+ strokeOpacity: phaseVisibility(drawn, phase, fields2)
6755
7331
  });
6756
7332
  for (const phase of ["casing", "fill"]) {
6757
7333
  const style = mergeTileflowDesign(phaseStyle(phase), request?.[phase]);
@@ -6767,13 +7343,13 @@ function compileRoundabouts(request, surfaces, context, contributions) {
6767
7343
  id: `tileflow-road-circular-${phase}`,
6768
7344
  type: "circle",
6769
7345
  source: context.data.sourceId,
6770
- "source-layer": layers.circularFeature,
7346
+ "source-layer": layers2.circularFeature,
6771
7347
  filter: [
6772
7348
  "all",
6773
- ["==", ["get", fields.circularKind], "road_ring"],
7349
+ ["==", ["get", fields2.circularKind], "road_ring"],
6774
7350
  [
6775
7351
  "any",
6776
- ...eligible.map((surface) => tileflowRoadClassFilter(fields, surface.roadClass))
7352
+ ...eligible.map((surface) => tileflowRoadClassFilter(fields2, surface.roadClass))
6777
7353
  ]
6778
7354
  ]
6779
7355
  },
@@ -6793,7 +7369,7 @@ function select(values, fallback) {
6793
7369
  if (values.every(({ value }) => JSON.stringify(value) === serialized)) return values[0].value;
6794
7370
  return ["case", ...values.flatMap(({ condition, value }) => [condition, value]), fallback];
6795
7371
  }
6796
- function phaseVisibility(surfaces, phase, fields) {
7372
+ function phaseVisibility(surfaces, phase, fields2) {
6797
7373
  const levels = [
6798
7374
  ...new Set(
6799
7375
  surfaces.flatMap((surface) => {
@@ -6809,7 +7385,7 @@ function phaseVisibility(surfaces, phase, fields) {
6809
7385
  surfaces.map((surface) => {
6810
7386
  const style = surface[phase];
6811
7387
  return {
6812
- condition: tileflowRoadClassFilter(fields, surface.roadClass),
7388
+ condition: tileflowRoadClassFilter(fields2, surface.roadClass),
6813
7389
  value: (style?.minZoom === void 0 || level >= style.minZoom) && (style?.maxZoom === void 0 || level < style.maxZoom) ? 1 : 0
6814
7390
  };
6815
7391
  }),
@@ -7299,8 +7875,8 @@ function roadPhysicalCohort(roadClass) {
7299
7875
  return "path";
7300
7876
  }
7301
7877
  function compileSidewalks(request, pedestrianAreaColor, context, contributions) {
7302
- const { fields, layers } = context.data.schema;
7303
- if (!layers.sidewalk) return;
7878
+ const { fields: fields2, layers: layers2 } = context.data.schema;
7879
+ if (!layers2.sidewalk) return;
7304
7880
  const config = mergeTileflowDesign(
7305
7881
  {
7306
7882
  surface: {
@@ -7314,11 +7890,11 @@ function compileSidewalks(request, pedestrianAreaColor, context, contributions)
7314
7890
  const base = {
7315
7891
  type: "fill",
7316
7892
  source: context.data.sourceId,
7317
- "source-layer": layers.sidewalk,
7893
+ "source-layer": layers2.sidewalk,
7318
7894
  filter: [
7319
7895
  "all",
7320
7896
  ["==", ["geometry-type"], "Polygon"],
7321
- ["match", ["get", fields.class], ["sidewalk", "pedestrian"], true, false]
7897
+ ["match", ["get", fields2.class], ["sidewalk", "pedestrian"], true, false]
7322
7898
  ]
7323
7899
  };
7324
7900
  if (config.surface?.visible !== false) {
@@ -7356,8 +7932,8 @@ function compileSidewalks(request, pedestrianAreaColor, context, contributions)
7356
7932
  }
7357
7933
  }
7358
7934
  function compileCrossings(request, context, contributions) {
7359
- const { fields, layers } = context.data.schema;
7360
- if (!request || !layers.streetFurniture) return;
7935
+ const { fields: fields2, layers: layers2 } = context.data.schema;
7936
+ if (!request || !layers2.streetFurniture) return;
7361
7937
  const config = mergeTileflowDesign(
7362
7938
  {
7363
7939
  allowOverlap: true,
@@ -7370,7 +7946,7 @@ function compileCrossings(request, context, contributions) {
7370
7946
  ]),
7371
7947
  padding: 0,
7372
7948
  pitchAlignment: "map",
7373
- rotate: expression(["+", ["to-number", ["get", fields.direction], 0], 90]),
7949
+ rotate: expression(["+", ["to-number", ["get", fields2.direction], 0], 90]),
7374
7950
  rotationAlignment: "map",
7375
7951
  size: zoom.linear([
7376
7952
  [15, 0.22],
@@ -7393,14 +7969,14 @@ function compileCrossings(request, context, contributions) {
7393
7969
  id: "tileflow-road-crossing",
7394
7970
  type: "symbol",
7395
7971
  source: context.data.sourceId,
7396
- "source-layer": layers.streetFurniture,
7972
+ "source-layer": layers2.streetFurniture,
7397
7973
  filter: [
7398
7974
  "all",
7399
7975
  ["==", ["geometry-type"], "Point"],
7400
- ["==", ["get", fields.subclass], "crossing"],
7401
- ["!=", ["get", fields.crossing], "no"],
7402
- ["has", fields.markings],
7403
- ["match", ["get", fields.markings], ["no", "none", "unmarked"], false, true]
7976
+ ["==", ["get", fields2.subclass], "crossing"],
7977
+ ["!=", ["get", fields2.crossing], "no"],
7978
+ ["has", fields2.markings],
7979
+ ["match", ["get", fields2.markings], ["no", "none", "unmarked"], false, true]
7404
7980
  ]
7405
7981
  },
7406
7982
  config
@@ -7476,36 +8052,36 @@ function substituteZoom(value, level) {
7476
8052
  if (value.length === 1 && value[0] === "zoom") return level;
7477
8053
  return value.map((entry) => substituteZoom(entry, level));
7478
8054
  }
7479
- function resolveRoadTreatments(request, fields, roadClass) {
8055
+ function resolveRoadTreatments(request, fields2, roadClass) {
7480
8056
  const entries = [];
7481
8057
  const add2 = (style, condition) => {
7482
8058
  if (style && style.enabled !== false) entries.push({ condition, style });
7483
8059
  };
7484
8060
  add2(request?.modifiers?.construction, [
7485
8061
  "match",
7486
- ["get", fields.class],
8062
+ ["get", fields2.class],
7487
8063
  tileflowRoadConstructionClasses,
7488
8064
  true,
7489
8065
  false
7490
8066
  ]);
7491
- add2(request?.restrictions?.bicycle, restrictedAccessFilter(fields.bicycle));
7492
- add2(request?.restrictions?.foot, restrictedAccessFilter(fields.foot));
7493
- add2(request?.restrictions?.horse, restrictedAccessFilter(fields.horse));
7494
- add2(request?.restrictions?.access, restrictedAccessFilter(fields.access));
7495
- add2(request?.restrictions?.toll, flagFilter(fields.toll));
7496
- add2(request?.modifiers?.expressway, flagFilter(fields.expressway));
7497
- add2(request?.modifiers?.ramp, flagFilter(fields.ramp));
7498
- add2(request?.modifiers?.unpaved, ["==", ["get", fields.surface], "unpaved"]);
7499
- add2(request?.modifiers?.indoor, flagFilter(fields.indoor));
7500
- add2(request?.modifiers?.official, flagFilter(fields.official));
8067
+ add2(request?.restrictions?.bicycle, restrictedAccessFilter(fields2.bicycle));
8068
+ add2(request?.restrictions?.foot, restrictedAccessFilter(fields2.foot));
8069
+ add2(request?.restrictions?.horse, restrictedAccessFilter(fields2.horse));
8070
+ add2(request?.restrictions?.access, restrictedAccessFilter(fields2.access));
8071
+ add2(request?.restrictions?.toll, flagFilter(fields2.toll));
8072
+ add2(request?.modifiers?.expressway, flagFilter(fields2.expressway));
8073
+ add2(request?.modifiers?.ramp, flagFilter(fields2.ramp));
8074
+ add2(request?.modifiers?.unpaved, ["==", ["get", fields2.surface], "unpaved"]);
8075
+ add2(request?.modifiers?.indoor, flagFilter(fields2.indoor));
8076
+ add2(request?.modifiers?.official, flagFilter(fields2.official));
7501
8077
  for (const [scale, style] of Object.entries(request?.mountainBike ?? {})) {
7502
- add2(style, ["==", ["to-string", ["get", fields.mtbScale]], scale]);
8078
+ add2(style, ["==", ["to-string", ["get", fields2.mtbScale]], scale]);
7503
8079
  }
7504
8080
  if (roadClass === "service") {
7505
8081
  for (const [serviceType, value] of Object.entries(serviceTypeValues)) {
7506
8082
  add2(request?.serviceTypes?.[serviceType], [
7507
8083
  "==",
7508
- ["get", fields.service],
8084
+ ["get", fields2.service],
7509
8085
  value
7510
8086
  ]);
7511
8087
  }
@@ -8308,7 +8884,7 @@ function compileWater(request, context, language = "auto") {
8308
8884
  );
8309
8885
  if (config.enabled === false) return [];
8310
8886
  const source = context.data.sourceId;
8311
- const { fields, layers } = context.data.schema;
8887
+ const { fields: fields2, layers: layers2 } = context.data.schema;
8312
8888
  const contributions = [];
8313
8889
  if (config.bodies) {
8314
8890
  for (const area of createAreaLayers(
@@ -8316,8 +8892,8 @@ function compileWater(request, context, language = "auto") {
8316
8892
  id: "tileflow-water",
8317
8893
  type: "fill",
8318
8894
  source,
8319
- "source-layer": layers.water,
8320
- filter: ["!=", ["get", fields.intermittent], 1]
8895
+ "source-layer": layers2.water,
8896
+ filter: ["!=", ["get", fields2.intermittent], 1]
8321
8897
  },
8322
8898
  config.bodies
8323
8899
  )) {
@@ -8337,8 +8913,8 @@ function compileWater(request, context, language = "auto") {
8337
8913
  id: "tileflow-water-intermittent",
8338
8914
  type: "fill",
8339
8915
  source,
8340
- "source-layer": layers.water,
8341
- filter: ["==", ["get", fields.intermittent], 1]
8916
+ "source-layer": layers2.water,
8917
+ filter: ["==", ["get", fields2.intermittent], 1]
8342
8918
  },
8343
8919
  config.intermittent.bodies
8344
8920
  )) {
@@ -8356,9 +8932,9 @@ function compileWater(request, context, language = "auto") {
8356
8932
  const sidecarBathymetry = bathymetryProduct?.vector;
8357
8933
  const usePrimaryBathymetryFallback = context.marine === void 0;
8358
8934
  const bathymetrySource = sidecarBathymetry?.sourceId ?? source;
8359
- const bathymetryLayer = sidecarBathymetry ? "bathymetry" : usePrimaryBathymetryFallback ? layers.bathymetry : void 0;
8360
- const bathymetryDepthField = sidecarBathymetry ? "min_depth" : usePrimaryBathymetryFallback ? fields.bathymetryMinDepth : void 0;
8361
- const bathymetrySortField = sidecarBathymetry ? "sort_key" : usePrimaryBathymetryFallback ? fields.bathymetrySortKey : void 0;
8935
+ const bathymetryLayer = sidecarBathymetry ? "bathymetry" : usePrimaryBathymetryFallback ? layers2.bathymetry : void 0;
8936
+ const bathymetryDepthField = sidecarBathymetry ? "min_depth" : usePrimaryBathymetryFallback ? fields2.bathymetryMinDepth : void 0;
8937
+ const bathymetrySortField = sidecarBathymetry ? "sort_key" : usePrimaryBathymetryFallback ? fields2.bathymetrySortKey : void 0;
8362
8938
  if (bathymetryLayer && bathymetryDepthField && bathymetrySortField) {
8363
8939
  const depth = context.colors.hydro.depth;
8364
8940
  const depthStops = bathymetryDepthStops(depth);
@@ -8558,11 +9134,11 @@ function compileWater(request, context, language = "auto") {
8558
9134
  id: `tileflow-waterway-${name}`,
8559
9135
  type: "line",
8560
9136
  source,
8561
- "source-layer": layers.waterway,
9137
+ "source-layer": layers2.waterway,
8562
9138
  filter: [
8563
9139
  "all",
8564
- classFilter3(fields.class, classes),
8565
- ["!=", ["get", fields.intermittent], 1]
9140
+ classFilter3(fields2.class, classes),
9141
+ ["!=", ["get", fields2.intermittent], 1]
8566
9142
  ]
8567
9143
  },
8568
9144
  style
@@ -8587,11 +9163,11 @@ function compileWater(request, context, language = "auto") {
8587
9163
  id: `tileflow-waterway-${name}-intermittent`,
8588
9164
  type: "line",
8589
9165
  source,
8590
- "source-layer": layers.waterway,
9166
+ "source-layer": layers2.waterway,
8591
9167
  filter: [
8592
9168
  "all",
8593
- classFilter3(fields.class, classes),
8594
- ["==", ["get", fields.intermittent], 1]
9169
+ classFilter3(fields2.class, classes),
9170
+ ["==", ["get", fields2.intermittent], 1]
8595
9171
  ]
8596
9172
  },
8597
9173
  mergeTileflowDesign(style, intermittent)
@@ -8606,8 +9182,8 @@ function compileWater(request, context, language = "auto") {
8606
9182
  }
8607
9183
  function appendBathymetryNames(contributions, options) {
8608
9184
  const { context, language } = options;
8609
- const { fields } = tileflowBathymetryV1Schema;
8610
- const localName = ["to-string", ["coalesce", ["get", fields.name], ""]];
9185
+ const { fields: fields2 } = tileflowBathymetryV1Schema;
9186
+ const localName = ["to-string", ["coalesce", ["get", fields2.name], ""]];
8611
9187
  const name = language === "auto" || language === "local" ? localName : [
8612
9188
  "case",
8613
9189
  ["!=", ["to-string", ["coalesce", ["get", `name:${language}`], ""]], ""],
@@ -8618,7 +9194,7 @@ function appendBathymetryNames(contributions, options) {
8618
9194
  {
8619
9195
  minZoom: 0,
8620
9196
  placement: "point",
8621
- priority: expression(["to-number", ["get", fields.sortKey], 0]),
9197
+ priority: expression(["to-number", ["get", fields2.sortKey], 0]),
8622
9198
  priorityOrder: "lower-first",
8623
9199
  text: {
8624
9200
  ...typographyTextStyle(context.typography.water),
@@ -8636,8 +9212,8 @@ function appendBathymetryNames(contributions, options) {
8636
9212
  options.style
8637
9213
  );
8638
9214
  if (style.visible === false || style.text?.visible === false) return;
8639
- const sourceMinimum = ["to-number", ["coalesce", ["get", fields.minZoom], 0], 0];
8640
- const sourceMaximum = ["to-number", ["coalesce", ["get", fields.maxZoom], 24], 24];
9215
+ const sourceMinimum = ["to-number", ["coalesce", ["get", fields2.minZoom], 0], 0];
9216
+ const sourceMaximum = ["to-number", ["coalesce", ["get", fields2.maxZoom], 24], 24];
8641
9217
  const ranges = options.availability === true ? void 0 : [...options.availability.zoomRanges].sort(
8642
9218
  (left, right) => left.minZoom - right.minZoom || left.maxZoom - right.maxZoom
8643
9219
  );
@@ -9078,8 +9654,8 @@ function assertProvidedServices(domain, services) {
9078
9654
  }
9079
9655
  }
9080
9656
  function checkedModuleRecord(entries) {
9081
- const record3 = Object.fromEntries(entries);
9082
- const actual = Object.keys(record3).sort(compareCodeUnits3);
9657
+ const record4 = Object.fromEntries(entries);
9658
+ const actual = Object.keys(record4).sort(compareCodeUnits3);
9083
9659
  if (actual.length !== tileflowSemanticDomainRegistry.length || actual.some(
9084
9660
  (name, index) => name !== [...tileflowSemanticDomainRegistry.map(({ name: name2 }) => name2)].sort(compareCodeUnits3)[index]
9085
9661
  )) {
@@ -9087,7 +9663,7 @@ function checkedModuleRecord(entries) {
9087
9663
  "Tileflow semantic domain registry did not produce one value for every module."
9088
9664
  );
9089
9665
  }
9090
- return record3;
9666
+ return record4;
9091
9667
  }
9092
9668
  function assertRegistryIsValid() {
9093
9669
  const names = /* @__PURE__ */ new Set();
@@ -9146,12 +9722,12 @@ function readTileflowCompilerProvenance(layer) {
9146
9722
  const target = metadata[tileflowCompilerMetadataKeys.target];
9147
9723
  return owner && slot && typeof target === "string" && tileflowSemanticTargetPattern.test(target) ? [{ operations: [], owner, slot, target }] : [];
9148
9724
  }
9149
- function createTileflowStyleInspection(map, theme, layers) {
9725
+ function createTileflowStyleInspection(map, theme, layers2) {
9150
9726
  return {
9151
9727
  schemaVersion: tileflowStyleInspectionSchemaVersion,
9152
9728
  map,
9153
9729
  theme,
9154
- layers: layers.map((layer, index) => ({
9730
+ layers: layers2.map((layer, index) => ({
9155
9731
  id: typeof layer.id === "string" ? layer.id : "",
9156
9732
  index,
9157
9733
  type: typeof layer.type === "string" ? layer.type : "",
@@ -9251,12 +9827,12 @@ var classicManifestSchemaOperations = {
9251
9827
 
9252
9828
  // src/portable-identity-schema.ts
9253
9829
  function createPortableIdentitySchemas(operations) {
9254
- const bounded = operations.maxLength(
9830
+ const bounded2 = operations.maxLength(
9255
9831
  operations.minLength(operations.string(), 1),
9256
9832
  tileflowPortableIdMaximumLength
9257
9833
  );
9258
9834
  const pattern = operations.regex(
9259
- bounded,
9835
+ bounded2,
9260
9836
  tileflowPortableIdPattern,
9261
9837
  "Expected lowercase kebab-case beginning with a letter"
9262
9838
  );
@@ -9370,7 +9946,7 @@ function insertTileflowOverlays(input) {
9370
9946
  available.length > 0 ? `Use one of: ${available.join(", ")}.` : "Declare the source first."
9371
9947
  );
9372
9948
  }
9373
- const layers2 = overlay.layers.map((layer, index) => {
9949
+ const layers3 = overlay.layers.map((layer, index) => {
9374
9950
  if (layerIds.has(layer.id)) {
9375
9951
  throw new TileflowOverlayCompilationError(
9376
9952
  "TF_OVERLAY_LAYER_ID_DUPLICATE",
@@ -9388,21 +9964,21 @@ function insertTileflowOverlays(input) {
9388
9964
  }
9389
9965
  };
9390
9966
  });
9391
- groups.set(overlay.placement, [...groups.get(overlay.placement) ?? [], ...layers2]);
9967
+ groups.set(overlay.placement, [...groups.get(overlay.placement) ?? [], ...layers3]);
9392
9968
  identities[overlayId] = Object.freeze({
9393
9969
  layers: Object.freeze(overlay.layers.map(({ id: id2 }) => id2)),
9394
9970
  placement: overlay.placement,
9395
9971
  source: overlay.source
9396
9972
  });
9397
9973
  }
9398
- let layers = input.basemapLayers.map(cloneJson18);
9974
+ let layers2 = input.basemapLayers.map(cloneJson18);
9399
9975
  for (const placement of tileflowOverlayPlacements) {
9400
9976
  const overlayLayers = groups.get(placement);
9401
9977
  if (!overlayLayers?.length) continue;
9402
- const index = tileflowOverlayInsertionIndex(layers, placement);
9403
- layers = [...layers.slice(0, index), ...overlayLayers, ...layers.slice(index)];
9978
+ const index = tileflowOverlayInsertionIndex(layers2, placement);
9979
+ layers2 = [...layers2.slice(0, index), ...overlayLayers, ...layers2.slice(index)];
9404
9980
  }
9405
- return { identities, layers };
9981
+ return { identities, layers: layers2 };
9406
9982
  }
9407
9983
  function isSafeLocalPmtilesPath(value) {
9408
9984
  if (typeof value !== "string" || value.length > 512 || !value.endsWith(".pmtiles") || value.includes("\\") || /[\p{Cc}?#]/u.test(value)) {
@@ -9426,8 +10002,8 @@ function cloneJson18(value) {
9426
10002
  Object.entries(value).map(([key, child]) => [key, cloneJson18(child)])
9427
10003
  );
9428
10004
  }
9429
- function tileflowOverlayInsertionIndex(layers, placement) {
9430
- const ranks = layers.map((layer) => {
10005
+ function tileflowOverlayInsertionIndex(layers2, placement) {
10006
+ const ranks = layers2.map((layer) => {
9431
10007
  const slots = readTileflowCompilerProvenance(layer).map(
9432
10008
  ({ slot }) => tileflowLayerSlots.indexOf(slot)
9433
10009
  );
@@ -9634,6 +10210,14 @@ function validateBoundaryChoroplethOverlays(mapId, overlays, boundaryAreas) {
9634
10210
  return overlays;
9635
10211
  }
9636
10212
 
10213
+ // src/notices.ts
10214
+ var tileflowNoticesMetadataKey = "tileflow:notices";
10215
+ var tileflowNoticeLimits = Object.freeze({
10216
+ maxNotices: 8,
10217
+ maxSources: 16,
10218
+ maxTextLength: 120
10219
+ });
10220
+
9637
10221
  // src/resolved-map-schema.ts
9638
10222
  import { Color as Color3 } from "@maplibre/maplibre-gl-style-spec";
9639
10223
  import { z as z5 } from "zod";
@@ -10271,12 +10855,12 @@ function dataSource() {
10271
10855
  return Object.freeze({ kind: "tileflow-data-source", name: "primary" });
10272
10856
  }
10273
10857
  function createSemanticDataView(data) {
10274
- const fields = Object.fromEntries(
10858
+ const fields2 = Object.fromEntries(
10275
10859
  Object.entries(data.schema.fields).flatMap(
10276
10860
  ([name, value]) => value === void 0 ? [] : [[name, field(name)]]
10277
10861
  )
10278
10862
  );
10279
- const layers = Object.fromEntries(
10863
+ const layers2 = Object.fromEntries(
10280
10864
  Object.entries(data.schema.layers).flatMap(
10281
10865
  ([name, value]) => value === void 0 ? [] : [[name, dataLayer(name)]]
10282
10866
  )
@@ -10284,7 +10868,7 @@ function createSemanticDataView(data) {
10284
10868
  return {
10285
10869
  ...data,
10286
10870
  sourceId: dataSource(),
10287
- schema: { ...data.schema, fields, layers }
10871
+ schema: { ...data.schema, fields: fields2, layers: layers2 }
10288
10872
  };
10289
10873
  }
10290
10874
  function bindSemanticReferences(value, data) {
@@ -10448,12 +11032,12 @@ function materializeTileflowLayerFamilyIR(template, semantics) {
10448
11032
  });
10449
11033
  }
10450
11034
  function lowerTileflowDomainIR(families, data, resolvePhysicalId = physicalLayerIdForSemanticKey) {
10451
- const layers = families.map(
11035
+ const layers2 = families.map(
10452
11036
  (family) => bindSemanticReferences(emitLayer(family, resolvePhysicalId), data)
10453
11037
  );
10454
- assertNoSemanticReferences(layers);
11038
+ assertNoSemanticReferences(layers2);
10455
11039
  const ids = /* @__PURE__ */ new Set();
10456
- for (const layer of layers) {
11040
+ for (const layer of layers2) {
10457
11041
  if (ids.has(layer.id)) {
10458
11042
  throw new TileflowDomainIRError(
10459
11043
  "TILEFLOW_DOMAIN_IR_DUPLICATE_PHYSICAL_ID",
@@ -10462,7 +11046,7 @@ function lowerTileflowDomainIR(families, data, resolvePhysicalId = physicalLayer
10462
11046
  }
10463
11047
  ids.add(layer.id);
10464
11048
  }
10465
- return Object.freeze({ layers: Object.freeze(layers) });
11049
+ return Object.freeze({ layers: Object.freeze(layers2) });
10466
11050
  }
10467
11051
  var TileflowDomainIRError = class extends Error {
10468
11052
  code;
@@ -10616,7 +11200,11 @@ var exactPhysicalLayerIds = Object.freeze({
10616
11200
  });
10617
11201
  var nauticalPhysicalBases = Object.freeze({
10618
11202
  "nautical.aids": "tileflow-nautical-aids",
11203
+ "nautical.beacons": "tileflow-nautical-beacons",
11204
+ "nautical.buoys": "tileflow-nautical-buoys",
11205
+ "nautical.cables": "tileflow-nautical-cables",
10619
11206
  "nautical.coverage": "tileflow-nautical-coverage",
11207
+ "nautical.harbours": "tileflow-nautical-harbours",
10620
11208
  "nautical.hazardAreas": "tileflow-nautical-hazard-areas",
10621
11209
  "nautical.hazards": "tileflow-nautical-hazards",
10622
11210
  "nautical.labels.coverage": "tileflow-nautical-coverage-labels",
@@ -10627,7 +11215,9 @@ var nauticalPhysicalBases = Object.freeze({
10627
11215
  "nautical.lighthouses": "tileflow-nautical-lighthouses",
10628
11216
  "nautical.lights": "tileflow-nautical-lights",
10629
11217
  "nautical.navigationAreas": "tileflow-nautical-navigation-areas",
11218
+ "nautical.ports": "tileflow-nautical-ports",
10630
11219
  "nautical.reefs": "tileflow-nautical-reefs",
11220
+ "nautical.routes": "tileflow-nautical-routes",
10631
11221
  "nautical.soundings": "tileflow-nautical-soundings",
10632
11222
  "nautical.wreckAreas": "tileflow-nautical-wreck-areas",
10633
11223
  "nautical.wrecks": "tileflow-nautical-wrecks"
@@ -10909,17 +11499,17 @@ function compileRenderSelector(selector, data) {
10909
11499
  return lowerSelector(selector, data);
10910
11500
  }
10911
11501
  function applyCompiledRenderStacks(input, operations) {
10912
- let layers = input.map(cloneJson21);
11502
+ let layers2 = input.map(cloneJson21);
10913
11503
  const passes = operations.filter(
10914
11504
  (operation) => operation.kind === "layer"
10915
11505
  );
10916
11506
  const refinements = operations.filter(
10917
11507
  (operation) => operation.kind === "refinement"
10918
11508
  );
10919
- requireUniqueCompiledLayers(layers, passes);
11509
+ requireUniqueCompiledLayers(layers2, passes);
10920
11510
  const passTargets = new Set(passes.map(({ target }) => target));
10921
- const knownTargets = /* @__PURE__ */ new Set([...layers.map(({ target }) => target), ...passTargets]);
10922
- const activeOwners = new Set(layers.map(({ owner }) => owner));
11511
+ const knownTargets = /* @__PURE__ */ new Set([...layers2.map(({ target }) => target), ...passTargets]);
11512
+ const activeOwners = new Set(layers2.map(({ owner }) => owner));
10923
11513
  const drawn = /* @__PURE__ */ new Set();
10924
11514
  for (let changed = true; changed; ) {
10925
11515
  changed = false;
@@ -10937,7 +11527,7 @@ function applyCompiledRenderStacks(input, operations) {
10937
11527
  (refinement) => refinement.requirements.every((requirement) => activeOwners.has(requirement))
10938
11528
  ).sort(compareCompiledOperations);
10939
11529
  for (const refinement of activeRefinements) {
10940
- const index = findTargetIndex(layers, refinement.target);
11530
+ const index = findTargetIndex(layers2, refinement.target);
10941
11531
  if (index < 0 && !passTargets.has(refinement.target)) {
10942
11532
  throw renderStackError(
10943
11533
  "unknown-refinement-target",
@@ -10972,11 +11562,11 @@ function applyCompiledRenderStacks(input, operations) {
10972
11562
  const lastPlaced = /* @__PURE__ */ new Map();
10973
11563
  const isMovePending = (target) => pending.some((operation) => operation.kind === "refinement" && operation.target === target);
10974
11564
  const isReady = (operation) => {
10975
- if (operation.kind === "refinement" && findTargetIndex(layers, operation.target) < 0) {
11565
+ if (operation.kind === "refinement" && findTargetIndex(layers2, operation.target) < 0) {
10976
11566
  return false;
10977
11567
  }
10978
11568
  const anchor = placementAnchor(operation.placement);
10979
- return anchor === void 0 || findTargetIndex(layers, anchor) >= 0 && !isMovePending(anchor);
11569
+ return anchor === void 0 || findTargetIndex(layers2, anchor) >= 0 && !isMovePending(anchor);
10980
11570
  };
10981
11571
  while (pending.length > 0) {
10982
11572
  const first = pending.find(isReady);
@@ -10994,34 +11584,34 @@ function applyCompiledRenderStacks(input, operations) {
10994
11584
  const moved = /* @__PURE__ */ new Map();
10995
11585
  for (const operation of group) {
10996
11586
  if (operation.kind !== "refinement") continue;
10997
- const index2 = findTargetIndex(layers, operation.target);
10998
- moved.set(operation.target, requireRefinementOwner(layers[index2], operation));
10999
- layers = [...layers.slice(0, index2), ...layers.slice(index2 + 1)];
11587
+ const index2 = findTargetIndex(layers2, operation.target);
11588
+ moved.set(operation.target, requireRefinementOwner(layers2[index2], operation));
11589
+ layers2 = [...layers2.slice(0, index2), ...layers2.slice(index2 + 1)];
11000
11590
  for (const [placed, target] of lastPlaced) {
11001
11591
  if (target === operation.target) lastPlaced.delete(placed);
11002
11592
  }
11003
11593
  }
11004
11594
  const placement = first.placement;
11005
11595
  const anchor = placementAnchor(placement);
11006
- const anchorLayer = anchor === void 0 ? void 0 : layers[findTargetIndex(layers, anchor)];
11596
+ const anchorLayer = anchor === void 0 ? void 0 : layers2[findTargetIndex(layers2, anchor)];
11007
11597
  const slot = anchorLayer === void 0 ? tileflowBandPlacementSlot(placement) : requireSemanticSlot(anchorLayer, anchor);
11008
11598
  const block = group.map(
11009
11599
  (operation) => operation.kind === "layer" ? materializeRenderLayer(operation, anchorLayer, slot) : moveLayer(moved.get(operation.target), operation, slot, anchorLayer)
11010
11600
  );
11011
11601
  const previous = lastPlaced.get(key);
11012
- const previousIndex = previous === void 0 ? -1 : findTargetIndex(layers, previous);
11013
- const index = anchorLayer !== void 0 ? findTargetIndex(layers, anchor) + (key.startsWith("above:") ? 1 : 0) : previousIndex >= 0 ? previousIndex + 1 : tileflowBandPlacementIndex(
11014
- layers.map((candidate) => tileflowLayerSlots.indexOf(candidate.slot)),
11602
+ const previousIndex = previous === void 0 ? -1 : findTargetIndex(layers2, previous);
11603
+ const index = anchorLayer !== void 0 ? findTargetIndex(layers2, anchor) + (key.startsWith("above:") ? 1 : 0) : previousIndex >= 0 ? previousIndex + 1 : tileflowBandPlacementIndex(
11604
+ layers2.map((candidate) => tileflowLayerSlots.indexOf(candidate.slot)),
11015
11605
  placement
11016
11606
  );
11017
- layers = [...layers.slice(0, index), ...block, ...layers.slice(index)];
11607
+ layers2 = [...layers2.slice(0, index), ...block, ...layers2.slice(index)];
11018
11608
  lastPlaced.set(key, block.at(-1).target);
11019
11609
  }
11020
11610
  for (const refinement of activeRefinements) {
11021
11611
  if (refinement.patch === void 0) continue;
11022
- const index = findTargetIndex(layers, refinement.target);
11612
+ const index = findTargetIndex(layers2, refinement.target);
11023
11613
  if (index < 0) continue;
11024
- const previous = requireRefinementOwner(layers[index], refinement);
11614
+ const previous = requireRefinementOwner(layers2[index], refinement);
11025
11615
  const expectedType = rendererLayerType(refinement.renderer);
11026
11616
  if (previous.renderer !== expectedType) {
11027
11617
  throw renderStackError(
@@ -11029,9 +11619,9 @@ function applyCompiledRenderStacks(input, operations) {
11029
11619
  `Render refinement ${refinement.target} expects ${expectedType}, found ${String(previous.renderer)}.`
11030
11620
  );
11031
11621
  }
11032
- layers[index] = applyRefinement(previous, { ...refinement, patch: refinement.patch });
11622
+ layers2[index] = applyRefinement(previous, { ...refinement, patch: refinement.patch });
11033
11623
  }
11034
- return layers;
11624
+ return layers2;
11035
11625
  }
11036
11626
  function requireRefinementOwner(layer, refinement) {
11037
11627
  if (layer.owner !== refinement.owner) {
@@ -11550,9 +12140,9 @@ function requireOperationName(name) {
11550
12140
  );
11551
12141
  }
11552
12142
  }
11553
- function requireUniqueCompiledLayers(layers, operations) {
11554
- const keys = new Set(layers.map(({ key }) => key));
11555
- const targets = new Set(layers.map(({ target }) => target));
12143
+ function requireUniqueCompiledLayers(layers2, operations) {
12144
+ const keys = new Set(layers2.map(({ key }) => key));
12145
+ const targets = new Set(layers2.map(({ target }) => target));
11556
12146
  for (const operation of operations) {
11557
12147
  if (keys.has(operation.template.key)) {
11558
12148
  throw renderStackError(
@@ -11612,8 +12202,8 @@ function requireSemanticSlot(layer, target) {
11612
12202
  }
11613
12203
  return layer.slot;
11614
12204
  }
11615
- function findTargetIndex(layers, target) {
11616
- return layers.findIndex((layer) => layer.target === target);
12205
+ function findTargetIndex(layers2, target) {
12206
+ return layers2.findIndex((layer) => layer.target === target);
11617
12207
  }
11618
12208
  function requireScalar(value, description) {
11619
12209
  if (typeof value !== "boolean" && typeof value !== "number" && typeof value !== "string" || typeof value === "number" && !Number.isFinite(value)) {
@@ -12721,6 +13311,28 @@ function boundedThemeNumberSchema(min, max) {
12721
13311
  }).strict()
12722
13312
  ]);
12723
13313
  }
13314
+ var modelRoleLightingSchema = z5.object({
13315
+ emissiveStrength: boundedThemeNumberSchema(0, 5).optional(),
13316
+ emissiveVariation: boundedThemeNumberSchema(0, 1).optional(),
13317
+ emissiveColor: themeColorValueSchema.optional(),
13318
+ color: themeColorValueSchema.optional(),
13319
+ colorMix: boundedThemeNumberSchema(0, 1).optional(),
13320
+ metallic: boundedThemeNumberSchema(0, 1).optional(),
13321
+ roughness: boundedThemeNumberSchema(0, 1).optional(),
13322
+ colorVariation: z5.object({
13323
+ hue: z5.tuple([boundedThemeNumberSchema(0, 360), boundedThemeNumberSchema(0, 360)]),
13324
+ saturation: z5.tuple([boundedThemeNumberSchema(0, 100), boundedThemeNumberSchema(0, 100)]),
13325
+ lightness: z5.tuple([boundedThemeNumberSchema(0, 100), boundedThemeNumberSchema(0, 100)]),
13326
+ space: z5.enum(["srgb", "linear"]).optional()
13327
+ }).strict().optional(),
13328
+ emissiveHeight: z5.tuple([
13329
+ boundedThemeNumberSchema(0, 1),
13330
+ boundedThemeNumberSchema(0, 1),
13331
+ boundedThemeNumberSchema(0, 1),
13332
+ boundedThemeNumberSchema(0, 1),
13333
+ boundedThemeNumberSchema(-1, 1)
13334
+ ]).optional()
13335
+ }).strict();
12724
13336
  var buildingsModuleSchema = z5.object({
12725
13337
  type: z5.literal("buildings"),
12726
13338
  businessCorridor: areaStyleSchema.optional(),
@@ -12736,7 +13348,26 @@ var buildingsModuleSchema = z5.object({
12736
13348
  edgeRadius: z5.number().min(0).max(1).optional(),
12737
13349
  edgeColor: themeColorValueSchema.optional(),
12738
13350
  nightLight: boundedThemeNumberSchema(0, 2).optional(),
13351
+ floodLight: z5.object({
13352
+ intensity: boundedThemeNumberSchema(0, 1).optional(),
13353
+ brightnessScale: boundedThemeNumberSchema(0, 16).optional(),
13354
+ color: themeColorValueSchema.optional(),
13355
+ groundRadius: z5.tuple([z5.number().finite().min(0).max(2048), z5.number().finite().min(0).max(2048)]).refine(([min, max]) => min <= max, "The minimum radius must not exceed the maximum.").optional(),
13356
+ minGroundHeight: z5.number().finite().min(0).max(6e3).optional(),
13357
+ minWallHeight: z5.number().finite().min(0).max(6e3).optional(),
13358
+ wallHeightRatio: z5.number().finite().min(0).max(1).optional()
13359
+ }).strict().optional(),
13360
+ modelLighting: z5.object({
13361
+ unclassified: modelRoleLightingSchema.optional(),
13362
+ wall: modelRoleLightingSchema.optional(),
13363
+ door: modelRoleLightingSchema.optional(),
13364
+ roof: modelRoleLightingSchema.optional(),
13365
+ window: modelRoleLightingSchema.optional(),
13366
+ lamp: modelRoleLightingSchema.optional(),
13367
+ logo: modelRoleLightingSchema.optional()
13368
+ }).strict().optional(),
12739
13369
  occlusion: z5.boolean().optional(),
13370
+ modelOcclusion: boundedThemeNumberSchema(0, 1).optional(),
12740
13371
  shadows: z5.boolean().optional(),
12741
13372
  windows: z5.boolean().optional(),
12742
13373
  models: z5.array(
@@ -12973,8 +13604,12 @@ var poiModuleSchema = z5.object({
12973
13604
  var nauticalModuleSchema = z5.object({
12974
13605
  type: z5.literal("nautical"),
12975
13606
  aids: markerSymbolStyleSchema.optional(),
13607
+ beacons: markerSymbolStyleSchema.optional(),
13608
+ buoys: markerSymbolStyleSchema.optional(),
13609
+ cables: lineStyleSchema.optional(),
12976
13610
  coverage: areaStyleSchema.optional(),
12977
13611
  enabled: z5.boolean().optional(),
13612
+ harbours: markerSymbolStyleSchema.optional(),
12978
13613
  hazardAreas: areaStyleSchema.optional(),
12979
13614
  hazards: markerSymbolStyleSchema.optional(),
12980
13615
  labels: z5.object({
@@ -12987,8 +13622,10 @@ var nauticalModuleSchema = z5.object({
12987
13622
  lighthouses: markerSymbolStyleSchema.optional(),
12988
13623
  lights: markerSymbolStyleSchema.optional(),
12989
13624
  navigationAreas: areaStyleSchema.optional(),
13625
+ ports: markerSymbolStyleSchema.optional(),
12990
13626
  reefs: areaStyleSchema.optional(),
12991
13627
  renderStack: renderStackSchema.optional(),
13628
+ routes: lineStyleSchema.optional(),
12992
13629
  soundings: markerSymbolStyleSchema.optional(),
12993
13630
  wreckAreas: areaStyleSchema.optional(),
12994
13631
  wrecks: markerSymbolStyleSchema.optional()
@@ -13847,8 +14484,8 @@ function isSafeGlyphUrl(value) {
13847
14484
  function validateZoomRanges(value, context, path = []) {
13848
14485
  if (!value || typeof value !== "object") return;
13849
14486
  if (!Array.isArray(value)) {
13850
- const record3 = value;
13851
- if (typeof record3.minZoom === "number" && typeof record3.maxZoom === "number" && record3.minZoom > record3.maxZoom) {
14487
+ const record4 = value;
14488
+ if (typeof record4.minZoom === "number" && typeof record4.maxZoom === "number" && record4.minZoom > record4.maxZoom) {
13852
14489
  context.addIssue({
13853
14490
  code: "custom",
13854
14491
  path: [...path, "maxZoom"],
@@ -14470,7 +15107,7 @@ function applyTileflowIconCapabilities(style, icons) {
14470
15107
  "line-pattern",
14471
15108
  "background-pattern"
14472
15109
  ]) {
14473
- const pattern = record(layer.paint)[property];
15110
+ const pattern = record2(layer.paint)[property];
14474
15111
  if (pattern !== void 0 && [...outputs(pattern, ids)].some((id2) => appearances[id2]?.representation === "sdf")) {
14475
15112
  throw Object.assign(new Error(`Layer "${layer.id}" cannot use an SDF icon as a pattern.`), {
14476
15113
  code: "TF_ICON_PATTERN_SDF",
@@ -14479,7 +15116,7 @@ function applyTileflowIconCapabilities(style, icons) {
14479
15116
  });
14480
15117
  }
14481
15118
  }
14482
- const image = record(layer.layout)["icon-image"];
15119
+ const image = record2(layer.layout)["icon-image"];
14483
15120
  if (image === void 0) continue;
14484
15121
  if (typeof image === "string" && /\{[^{}]+\}/u.test(image) || typeof image !== "string" && !Array.isArray(image)) {
14485
15122
  throw Object.assign(new Error(`Layer "${layer.id}" has an unproven legacy icon selection.`), {
@@ -14501,7 +15138,7 @@ function applyTileflowIconCapabilities(style, icons) {
14501
15138
  }
14502
15139
  );
14503
15140
  }
14504
- const paint = { ...record(layer.paint) };
15141
+ const paint = { ...record2(layer.paint) };
14505
15142
  for (const [property, limit] of [
14506
15143
  ["icon-halo-width", 2],
14507
15144
  ["icon-halo-blur", 1]
@@ -14531,7 +15168,7 @@ function applyTileflowIconCapabilities(style, icons) {
14531
15168
  layer.paint = paint;
14532
15169
  }
14533
15170
  }
14534
- function record(value) {
15171
+ function record2(value) {
14535
15172
  return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
14536
15173
  }
14537
15174
  function outputs(value, ids) {
@@ -14620,8 +15257,8 @@ function defaultPaint(image, key, names, appearances, ids) {
14620
15257
  // src/cartography/interaction-manifest.ts
14621
15258
  var tileflowInteractionManifestMetadataKey = "tileflow:interaction-manifest";
14622
15259
  var tileflowInteractionManifestVersion = 3;
14623
- function createTileflowInteractionManifest(layers, fields) {
14624
- const poiLayers = layers.flatMap((layer, priority) => {
15260
+ function createTileflowInteractionManifest(layers2, fields2) {
15261
+ const poiLayers = layers2.flatMap((layer, priority) => {
14625
15262
  const id2 = typeof layer.id === "string" ? layer.id : void 0;
14626
15263
  const source = typeof layer.source === "string" ? layer.source : void 0;
14627
15264
  const sourceLayer = typeof layer["source-layer"] === "string" ? layer["source-layer"] : void 0;
@@ -14650,7 +15287,7 @@ function createTileflowInteractionManifest(layers, fields) {
14650
15287
  identity: ["source", "source-layer", "feature-id"],
14651
15288
  representationPriority: ["marker", "icon", "combined", "label"]
14652
15289
  },
14653
- fields: { ...fields },
15290
+ fields: { ...fields2 },
14654
15291
  hitTesting: { frequency: "animation-frame", order: "rendered-topmost" },
14655
15292
  identity: "maplibre-feature-id-if-present",
14656
15293
  layers: poiLayers
@@ -14659,13 +15296,13 @@ function createTileflowInteractionManifest(layers, fields) {
14659
15296
  version: tileflowInteractionManifestVersion
14660
15297
  };
14661
15298
  }
14662
- function assertTileflowInteractionManifestLayers(manifest, layers) {
15299
+ function assertTileflowInteractionManifestLayers(manifest, layers2) {
14663
15300
  const poiLayers = manifest?.domains.poi?.layers ?? [];
14664
15301
  if (poiLayers.length > 256) {
14665
15302
  throw new Error("Tileflow interaction manifest exceeds the 256-layer POI lookup limit.");
14666
15303
  }
14667
15304
  const layersById = new Map(
14668
- layers.flatMap((layer) => typeof layer.id === "string" ? [[layer.id, layer]] : [])
15305
+ layers2.flatMap((layer) => typeof layer.id === "string" ? [[layer.id, layer]] : [])
14669
15306
  );
14670
15307
  const poiNamespaces = new Set(
14671
15308
  poiLayers.map((layer) => `${layer.source}\0${layer.sourceLayer}`)
@@ -14729,9 +15366,9 @@ function isSafeArtifactName(value) {
14729
15366
  }
14730
15367
 
14731
15368
  // src/cartography/layout-zoom-diagnostics.ts
14732
- function diagnoseFractionalLayoutZoomSteps(layers) {
15369
+ function diagnoseFractionalLayoutZoomSteps(layers2) {
14733
15370
  const diagnostics = [];
14734
- for (const layer of layers) {
15371
+ for (const layer of layers2) {
14735
15372
  const layout = layer.layout;
14736
15373
  if (layout === null || typeof layout !== "object") continue;
14737
15374
  for (const [property, value] of Object.entries(layout)) {
@@ -14772,11 +15409,11 @@ function isZoom2(value) {
14772
15409
  // src/cartography/overlay-placement-manifest.ts
14773
15410
  var tileflowOverlayPlacementManifestMetadataKey = "tileflow:overlay-placement-manifest";
14774
15411
  var tileflowOverlayPlacementManifestSchemaVersion = 1;
14775
- function createTileflowOverlayPlacementManifest(layers) {
15412
+ function createTileflowOverlayPlacementManifest(layers2) {
14776
15413
  const anchors = Object.fromEntries(
14777
15414
  tileflowOverlayPlacements.map((placement) => {
14778
- const index = tileflowOverlayInsertionIndex(layers, placement);
14779
- const id2 = index < layers.length ? layers[index]?.id : void 0;
15415
+ const index = tileflowOverlayInsertionIndex(layers2, placement);
15416
+ const id2 = index < layers2.length ? layers2[index]?.id : void 0;
14780
15417
  if (id2 !== void 0 && typeof id2 !== "string") {
14781
15418
  throw new Error(`Tileflow overlay placement ${placement} resolved an invalid layer ID.`);
14782
15419
  }
@@ -14788,7 +15425,7 @@ function createTileflowOverlayPlacementManifest(layers) {
14788
15425
  schemaVersion: tileflowOverlayPlacementManifestSchemaVersion
14789
15426
  };
14790
15427
  }
14791
- function assertTileflowOverlayPlacementManifestLayers(manifest, layers) {
15428
+ function assertTileflowOverlayPlacementManifestLayers(manifest, layers2) {
14792
15429
  if (manifest.schemaVersion !== tileflowOverlayPlacementManifestSchemaVersion) {
14793
15430
  throw new Error("Tileflow overlay placement manifest schema version is unsupported.");
14794
15431
  }
@@ -14797,14 +15434,14 @@ function assertTileflowOverlayPlacementManifestLayers(manifest, layers) {
14797
15434
  throw new Error("Tileflow overlay placement manifest keys are invalid.");
14798
15435
  }
14799
15436
  const layerIndexes = new Map(
14800
- layers.flatMap(
15437
+ layers2.flatMap(
14801
15438
  (layer, index) => typeof layer.id === "string" ? [[layer.id, index]] : []
14802
15439
  )
14803
15440
  );
14804
15441
  let previous = -1;
14805
15442
  for (const placement of tileflowOverlayPlacements) {
14806
15443
  const anchor = manifest.anchors[placement];
14807
- const index = anchor === null ? layers.length : layerIndexes.get(anchor);
15444
+ const index = anchor === null ? layers2.length : layerIndexes.get(anchor);
14808
15445
  if (index === void 0) {
14809
15446
  throw new Error(`Tileflow overlay placement manifest references missing layer: ${anchor}`);
14810
15447
  }
@@ -14836,18 +15473,18 @@ var lineLayoutDefaults = {
14836
15473
  "line-round-limit": 1.05
14837
15474
  };
14838
15475
  function planTileflowLayerFamilies(input) {
14839
- let layers = input.map(cloneJson23);
14840
- layers = consolidateRoadLines(layers);
14841
- layers = consolidateRoadHatches(layers);
14842
- layers = consolidateRoadLabels(layers);
14843
- layers = consolidateFillFamily(layers, "land.landcover", "land.cohorts.landcover");
14844
- layers = consolidateFillFamily(layers, "land.landuse", "land.cohorts.landuse");
14845
- layers = consolidateWaterways(layers);
14846
- return layers;
14847
- }
14848
- function consolidateRoadLines(layers) {
15476
+ let layers2 = input.map(cloneJson23);
15477
+ layers2 = consolidateRoadLines(layers2);
15478
+ layers2 = consolidateRoadHatches(layers2);
15479
+ layers2 = consolidateRoadLabels(layers2);
15480
+ layers2 = consolidateFillFamily(layers2, "land.landcover", "land.cohorts.landcover");
15481
+ layers2 = consolidateFillFamily(layers2, "land.landuse", "land.cohorts.landuse");
15482
+ layers2 = consolidateWaterways(layers2);
15483
+ return layers2;
15484
+ }
15485
+ function consolidateRoadLines(layers2) {
14849
15486
  const groups = /* @__PURE__ */ new Map();
14850
- for (const [index, layer] of layers.entries()) {
15487
+ for (const [index, layer] of layers2.entries()) {
14851
15488
  if (layer.renderer !== "line" || layer.family?.kind !== "road-line") continue;
14852
15489
  const key = layer.family.group;
14853
15490
  const group = groups.get(key) ?? [];
@@ -14862,7 +15499,7 @@ function consolidateRoadLines(layers) {
14862
15499
  continue;
14863
15500
  }
14864
15501
  const mergedId = eligible[0].layer.family.outputKey;
14865
- if (hasGeneratedKeyCollision(layers, mergedId, eligible)) continue;
15502
+ if (hasGeneratedKeyCollision(layers2, mergedId, eligible)) continue;
14866
15503
  const merged = mergeRoadLineGroup(
14867
15504
  mergedId,
14868
15505
  eligible.map(({ layer }) => layer)
@@ -14876,10 +15513,10 @@ function consolidateRoadLines(layers) {
14876
15513
  }
14877
15514
  replacements.set(insertAt, [...replacements.get(insertAt) ?? [], merged]);
14878
15515
  }
14879
- return applyReplacements(layers, replacements);
15516
+ return applyReplacements(layers2, replacements);
14880
15517
  }
14881
- function canMergeRoadLines(layers) {
14882
- const common = layers[0];
15518
+ function canMergeRoadLines(layers2) {
15519
+ const common = layers2[0];
14883
15520
  if (!common) return false;
14884
15521
  const supportedPaint = /* @__PURE__ */ new Set([...Object.keys(linePaintDefaults), "line-pattern"]);
14885
15522
  const supportedLayout = /* @__PURE__ */ new Set([
@@ -14887,18 +15524,18 @@ function canMergeRoadLines(layers) {
14887
15524
  "line-sort-key",
14888
15525
  "visibility"
14889
15526
  ]);
14890
- return layers.every(
15527
+ return layers2.every(
14891
15528
  (layer) => sameLayerSource(layer, common) && Object.keys(layer.style.appearance ?? {}).every((key) => supportedPaint.has(key)) && Object.keys(layer.style.placement ?? {}).every((key) => supportedLayout.has(key)) && layer.style.appearance?.["line-pattern"] === void 0 && layer.style.placement?.visibility !== "none" && !isOrderedRenderPass(layer) && sameTopLevelProperties(layer, common, ["minZoom"])
14892
15529
  );
14893
15530
  }
14894
- function mergeRoadLineGroup(key, layers) {
14895
- const first = layers[0];
14896
- const conditions = layers.map((layer) => asFilter(layer.selector));
15531
+ function mergeRoadLineGroup(key, layers2) {
15532
+ const first = layers2[0];
15533
+ const conditions = layers2.map((layer) => asFilter(layer.selector));
14897
15534
  if (conditions.some(containsZoom)) return void 0;
14898
15535
  const paint = {};
14899
- const paintKeys = new Set(layers.flatMap((layer) => Object.keys(layer.style.appearance ?? {})));
15536
+ const paintKeys = new Set(layers2.flatMap((layer) => Object.keys(layer.style.appearance ?? {})));
14900
15537
  for (const key2 of paintKeys) {
14901
- const values = layers.map((layer) => layer.style.appearance?.[key2]);
15538
+ const values = layers2.map((layer) => layer.style.appearance?.[key2]);
14902
15539
  const combined = combineConditionalValues(
14903
15540
  values.map((value, index) => ({
14904
15541
  condition: conditions[index],
@@ -14912,7 +15549,7 @@ function mergeRoadLineGroup(key, layers) {
14912
15549
  }
14913
15550
  const layout = {};
14914
15551
  for (const key2 of Object.keys(lineLayoutDefaults)) {
14915
- const values = layers.map((layer, index) => ({
15552
+ const values = layers2.map((layer, index) => ({
14916
15553
  condition: conditions[index],
14917
15554
  value: layer.style.placement?.[key2] ?? lineLayoutDefaults[key2]
14918
15555
  }));
@@ -14925,7 +15562,7 @@ function mergeRoadLineGroup(key, layers) {
14925
15562
  }
14926
15563
  }
14927
15564
  const sortKey = combineConditionalValues(
14928
- layers.map((layer, index) => ({
15565
+ layers2.map((layer, index) => ({
14929
15566
  condition: conditions[index],
14930
15567
  value: rankedSortKey(layer.style.placement?.["line-sort-key"] ?? 0, index)
14931
15568
  })),
@@ -14942,16 +15579,16 @@ function mergeRoadLineGroup(key, layers) {
14942
15579
  selector: unionFilters(conditions),
14943
15580
  range: {
14944
15581
  minZoom: roadHighZoom,
14945
- ...finiteMaximumZoom(layers) === void 0 ? {} : { maxZoom: finiteMaximumZoom(layers) }
15582
+ ...finiteMaximumZoom(layers2) === void 0 ? {} : { maxZoom: finiteMaximumZoom(layers2) }
14946
15583
  },
14947
15584
  style: { appearance: paint, placement: layout }
14948
15585
  },
14949
- layers
15586
+ layers2
14950
15587
  );
14951
15588
  }
14952
- function consolidateRoadHatches(layers) {
15589
+ function consolidateRoadHatches(layers2) {
14953
15590
  const groups = /* @__PURE__ */ new Map();
14954
- for (const [index, layer] of layers.entries()) {
15591
+ for (const [index, layer] of layers2.entries()) {
14955
15592
  if (layer.renderer !== "symbol" && layer.renderer !== "line" || layer.family?.kind !== "road-hatch") {
14956
15593
  continue;
14957
15594
  }
@@ -14971,7 +15608,7 @@ function consolidateRoadHatches(layers) {
14971
15608
  continue;
14972
15609
  }
14973
15610
  const mergedId = first.family.outputKey;
14974
- if (hasGeneratedKeyCollision(layers, mergedId, entries)) continue;
15611
+ if (hasGeneratedKeyCollision(layers2, mergedId, entries)) continue;
14975
15612
  const conditions = entries.map(({ layer }) => asFilter(layer.selector));
14976
15613
  const sortKeyProperty = first.renderer === "line" ? "line-sort-key" : "symbol-sort-key";
14977
15614
  const layoutKeys = new Set(
@@ -15076,17 +15713,17 @@ function consolidateRoadHatches(layers) {
15076
15713
  for (const { index } of entries) replacements.set(index, []);
15077
15714
  replacements.set(entries.at(-1).index, [merged]);
15078
15715
  }
15079
- return applyReplacements(layers, replacements);
15716
+ return applyReplacements(layers2, replacements);
15080
15717
  }
15081
- function consolidateRoadLabels(layers) {
15082
- const candidates = layers.map((layer, index) => ({
15718
+ function consolidateRoadLabels(layers2) {
15719
+ const candidates = layers2.map((layer, index) => ({
15083
15720
  index,
15084
15721
  layer,
15085
15722
  roadClass: layer.family?.kind === "road-label" ? layer.family.member : void 0
15086
15723
  })).filter(
15087
15724
  ({ layer, roadClass }) => layer.renderer === "symbol" && roadClass !== void 0 && layer.feature?.dataLayer !== void 0
15088
15725
  );
15089
- if (candidates.some(({ layer }) => isOrderedRenderPass(layer))) return layers;
15726
+ if (candidates.some(({ layer }) => isOrderedRenderPass(layer))) return layers2;
15090
15727
  const groups = /* @__PURE__ */ new Map();
15091
15728
  for (const candidate of candidates) {
15092
15729
  const { layer } = candidate;
@@ -15108,7 +15745,7 @@ function consolidateRoadLabels(layers) {
15108
15745
  if (!group.every(({ layer }) => sameTopLevelProperties(layer, first))) continue;
15109
15746
  const conditions = group.map(({ layer }) => asFilter(layer.selector));
15110
15747
  const key = group.some(({ roadClass }) => roadClass === "motorway") ? "labels.cohorts.roads.major" : group.some(({ roadClass }) => roadClass === "service") ? "labels.cohorts.roads.local" : `labels.cohorts.roads.cohort${groupNumber++}`;
15111
- if (hasGeneratedKeyCollision(layers, key, group)) continue;
15748
+ if (hasGeneratedKeyCollision(layers2, key, group)) continue;
15112
15749
  const layout = { ...first.style.placement ?? {} };
15113
15750
  const sortKeyValues = group.map(({ layer }, index) => {
15114
15751
  const original = layer.style.placement?.["symbol-sort-key"] ?? 0;
@@ -15133,13 +15770,13 @@ function consolidateRoadLabels(layers) {
15133
15770
  for (const { index } of group) replacements.set(index, []);
15134
15771
  replacements.set(group.at(-1).index, [merged]);
15135
15772
  }
15136
- return applyReplacements(layers, replacements);
15773
+ return applyReplacements(layers2, replacements);
15137
15774
  }
15138
- function consolidateFillFamily(layers, group, mergedId) {
15139
- const candidates = layers.map((layer, index) => ({ index, layer })).filter(
15775
+ function consolidateFillFamily(layers2, group, mergedId) {
15776
+ const candidates = layers2.map((layer, index) => ({ index, layer })).filter(
15140
15777
  ({ layer }) => layer.renderer === "fill" && layer.family?.kind === "fill" && layer.family.group === group
15141
15778
  );
15142
- if (candidates.some(({ layer }) => isOrderedRenderPass(layer))) return layers;
15779
+ if (candidates.some(({ layer }) => isOrderedRenderPass(layer))) return layers2;
15143
15780
  const groups = /* @__PURE__ */ new Map();
15144
15781
  for (const candidate of candidates) {
15145
15782
  const { layer } = candidate;
@@ -15211,7 +15848,7 @@ function consolidateFillFamily(layers, group, mergedId) {
15211
15848
  if (!sortKey.ok) continue;
15212
15849
  layout["fill-sort-key"] = sortKey.value;
15213
15850
  const key = suffix === 0 ? mergedId : `${mergedId}.cohort${suffix}`;
15214
- if (hasGeneratedKeyCollision(layers, key, group2)) continue;
15851
+ if (hasGeneratedKeyCollision(layers2, key, group2)) continue;
15215
15852
  const merged = withMergedOrigins(
15216
15853
  {
15217
15854
  ...first,
@@ -15226,20 +15863,20 @@ function consolidateFillFamily(layers, group, mergedId) {
15226
15863
  replacements.set(group2.at(-1).index, [merged]);
15227
15864
  }
15228
15865
  }
15229
- return applyReplacements(layers, replacements);
15866
+ return applyReplacements(layers2, replacements);
15230
15867
  }
15231
- function consolidateWaterways(layers) {
15868
+ function consolidateWaterways(layers2) {
15232
15869
  const replacements = /* @__PURE__ */ new Map();
15233
15870
  for (const name of ["river", "canal", "stream", "other"]) {
15234
- const regularIndex = layers.findIndex(
15871
+ const regularIndex = layers2.findIndex(
15235
15872
  (layer) => layer.family?.kind === "waterway" && layer.family.group === name && layer.family.variant === "regular"
15236
15873
  );
15237
- const intermittentIndex = layers.findIndex(
15874
+ const intermittentIndex = layers2.findIndex(
15238
15875
  (layer) => layer.family?.kind === "waterway" && layer.family.group === name && layer.family.variant === "intermittent"
15239
15876
  );
15240
15877
  if (regularIndex < 0 || intermittentIndex < 0) continue;
15241
- const regular = layers[regularIndex];
15242
- const intermittent = layers[intermittentIndex];
15878
+ const regular = layers2[regularIndex];
15879
+ const intermittent = layers2[intermittentIndex];
15243
15880
  if (!sameLayerSource(regular, intermittent) || isOrderedRenderPass(regular) || isOrderedRenderPass(intermittent) || intermittentIndex !== regularIndex + 1 || minimumZoom(regular) !== minimumZoom(intermittent) || maximumZoom(regular) !== maximumZoom(intermittent) || !allEqual([regular.style.placement ?? {}, intermittent.style.placement ?? {}]) || !sameTopLevelProperties(regular, intermittent)) {
15244
15881
  continue;
15245
15882
  }
@@ -15298,7 +15935,7 @@ function consolidateWaterways(layers) {
15298
15935
  replacements.set(regularIndex, []);
15299
15936
  replacements.set(intermittentIndex, [merged]);
15300
15937
  }
15301
- return applyReplacements(layers, replacements);
15938
+ return applyReplacements(layers2, replacements);
15302
15939
  }
15303
15940
  function combineConditionalValues(entries, fallback, minimumRelevantZoom) {
15304
15941
  if (entries.length === 0) return { ok: true, value: fallback };
@@ -15533,8 +16170,8 @@ function unionFilters(filters) {
15533
16170
  function asFilter(value) {
15534
16171
  return Array.isArray(value) ? value : ["literal", true];
15535
16172
  }
15536
- function applyReplacements(layers, replacements) {
15537
- return layers.flatMap((layer, index) => replacements.get(index) ?? [layer]);
16173
+ function applyReplacements(layers2, replacements) {
16174
+ return layers2.flatMap((layer, index) => replacements.get(index) ?? [layer]);
15538
16175
  }
15539
16176
  function sameLayerSource(left, right) {
15540
16177
  return allEqual([left.feature, right.feature]);
@@ -15572,9 +16209,9 @@ function contiguousRuns(entries) {
15572
16209
  }
15573
16210
  return runs;
15574
16211
  }
15575
- function hasGeneratedKeyCollision(layers, key, entries) {
16212
+ function hasGeneratedKeyCollision(layers2, key, entries) {
15576
16213
  const members = new Set(entries.map(({ layer }) => layer));
15577
- return layers.some((layer) => layer.key === key && !members.has(layer));
16214
+ return layers2.some((layer) => layer.key === key && !members.has(layer));
15578
16215
  }
15579
16216
  function withMaximumZoom(layer, maxzoom) {
15580
16217
  return {
@@ -15588,8 +16225,8 @@ function minimumZoom(layer) {
15588
16225
  function maximumZoom(layer) {
15589
16226
  return typeof layer.range?.maxZoom === "number" ? layer.range.maxZoom : Infinity;
15590
16227
  }
15591
- function finiteMaximumZoom(layers) {
15592
- const maximum2 = Math.max(...layers.map(maximumZoom));
16228
+ function finiteMaximumZoom(layers2) {
16229
+ const maximum2 = Math.max(...layers2.map(maximumZoom));
15593
16230
  return Number.isFinite(maximum2) ? maximum2 : void 0;
15594
16231
  }
15595
16232
  function cloneJson23(value) {
@@ -15613,7 +16250,7 @@ var colourSources = [
15613
16250
  ["tileflow-buildings-3d", "fill-extrusion-color"],
15614
16251
  ["tileflow-buildings-fill", "fill-color"]
15615
16252
  ];
15616
- function tileflowBuildings3DDesignOf(module, context, layers, buildingModels, tileflowLandmarks) {
16253
+ function tileflowBuildings3DDesignOf(module, context, layers2, buildingModels, tileflowLandmarks) {
15617
16254
  const config = isRecord8(module) ? module : {};
15618
16255
  if (config.enabled === false) return void 0;
15619
16256
  const style = config.threeDimensional ?? {};
@@ -15621,10 +16258,10 @@ function tileflowBuildings3DDesignOf(module, context, layers, buildingModels, ti
15621
16258
  let color2;
15622
16259
  let verticalGradient = true;
15623
16260
  for (const [id2, property] of colourSources) {
15624
- const value = layers.find((layer) => layer.id === id2)?.paint?.[property];
16261
+ const value = layers2.find((layer) => layer.id === id2)?.paint?.[property];
15625
16262
  if (typeof value === "string" || Array.isArray(value)) {
15626
16263
  color2 = value;
15627
- verticalGradient = layers.find((layer) => layer.id === id2)?.paint?.["fill-extrusion-vertical-gradient"] !== false;
16264
+ verticalGradient = layers2.find((layer) => layer.id === id2)?.paint?.["fill-extrusion-vertical-gradient"] !== false;
15628
16265
  break;
15629
16266
  }
15630
16267
  }
@@ -15647,9 +16284,53 @@ function tileflowBuildings3DDesignOf(module, context, layers, buildingModels, ti
15647
16284
  edgeRadius: number(style.edgeRadius, defaults4.edgeRadius),
15648
16285
  ...typeof edgeColor === "string" ? { edgeColor } : {},
15649
16286
  nightLight: number(style.nightLight, 0),
16287
+ ...isRecord8(style.floodLight) ? {
16288
+ floodLight: readBuildingFloodLight({
16289
+ ...style.floodLight,
16290
+ intensity: number(style.floodLight.intensity, 0),
16291
+ brightnessScale: number(style.floodLight.brightnessScale, 1),
16292
+ color: style.floodLight.color === void 0 ? void 0 : toMapLibreStyleValue(style.floodLight.color)
16293
+ })
16294
+ } : {},
16295
+ ...isRecord8(style.modelLighting) ? {
16296
+ modelLighting: readModelRoleLighting(
16297
+ Object.fromEntries(
16298
+ Object.entries(style.modelLighting).filter(([, entry]) => isRecord8(entry)).map(([role, entry]) => {
16299
+ const own = entry;
16300
+ return [
16301
+ role,
16302
+ {
16303
+ ...own,
16304
+ emissiveStrength: number(own.emissiveStrength, 0),
16305
+ ...Object.fromEntries(
16306
+ ["emissiveVariation", "colorMix", "metallic", "roughness"].filter((key) => own[key] !== void 0).map((key) => [key, number(own[key], 0)])
16307
+ ),
16308
+ ...Array.isArray(own.emissiveHeight) ? { emissiveHeight: own.emissiveHeight.map((v) => number(v, 0)) } : {},
16309
+ ...isRecord8(own.colorVariation) ? {
16310
+ colorVariation: {
16311
+ ...own.colorVariation,
16312
+ ...Object.fromEntries(
16313
+ ["hue", "saturation", "lightness"].map((key) => [
16314
+ key,
16315
+ Array.isArray(
16316
+ own.colorVariation[key]
16317
+ ) ? own.colorVariation[key].map((v) => number(v, 0)) : []
16318
+ ])
16319
+ )
16320
+ }
16321
+ } : {},
16322
+ color: own.color === void 0 ? void 0 : toMapLibreStyleValue(own.color),
16323
+ emissiveColor: own.emissiveColor === void 0 ? void 0 : toMapLibreStyleValue(own.emissiveColor)
16324
+ }
16325
+ ];
16326
+ })
16327
+ )
16328
+ )
16329
+ } : {},
15650
16330
  windows: style.windows === true,
15651
16331
  shadows: typeof style.shadows === "boolean" ? style.shadows : defaults4.shadows,
15652
16332
  occlusion: typeof style.occlusion === "boolean" ? style.occlusion : defaults4.occlusion,
16333
+ modelOcclusion: number(style.modelOcclusion, defaults4.modelOcclusion),
15653
16334
  ...placedModels(style.models, buildingModels),
15654
16335
  ...modelColours(style.modelColors),
15655
16336
  ...landmarksOf(style.landmarks, tileflowLandmarks)
@@ -15694,9 +16375,9 @@ function modelColours(value) {
15694
16375
  }
15695
16376
  function tileflowStreetLightsDesignOf(module, context) {
15696
16377
  const config = isRecord8(module) ? module : {};
15697
- const layers = context.data.schema.layers;
16378
+ const layers2 = context.data.schema.layers;
15698
16379
  const style = config.streetLights ?? {};
15699
- if (config.enabled === false || style.enabled !== true || !layers.streetFurniture)
16380
+ if (config.enabled === false || style.enabled !== true || !layers2.streetFurniture)
15700
16381
  return void 0;
15701
16382
  const color2 = style.color === void 0 ? void 0 : toMapLibreStyleValue(style.color);
15702
16383
  const intensity = style.intensity === void 0 ? void 0 : toMapLibreStyleValue(style.intensity);
@@ -15704,9 +16385,9 @@ function tileflowStreetLightsDesignOf(module, context) {
15704
16385
  return {
15705
16386
  source: context.data.sourceId,
15706
16387
  layers: {
15707
- streetFurniture: layers.streetFurniture,
15708
- transportation: layers.road,
15709
- ...layers.sidewalk ? { sidewalk: layers.sidewalk } : {}
16388
+ streetFurniture: layers2.streetFurniture,
16389
+ transportation: layers2.road,
16390
+ ...layers2.sidewalk ? { sidewalk: layers2.sidewalk } : {}
15710
16391
  },
15711
16392
  estimate: estimate === "streets" || estimate === "none" || estimate === "lit" ? estimate : "lit",
15712
16393
  color: typeof color2 === "string" ? color2 : tileflowDefaultStreetLightsDesign.color,
@@ -16047,11 +16728,11 @@ function compileSemanticStyleInternal(input, options, inspect, onReport) {
16047
16728
  "finalization",
16048
16729
  () => createTileflowOverlayPlacementManifest(plannedLayers)
16049
16730
  );
16050
- const layers = runCompilationPhase("finalization", () => finalizeTileflowLayers(plannedLayers));
16731
+ const layers2 = runCompilationPhase("finalization", () => finalizeTileflowLayers(plannedLayers));
16051
16732
  const buildings3D = tileflowBuildings3DDesignOf(
16052
16733
  modules.buildings,
16053
16734
  context,
16054
- layers,
16735
+ layers2,
16055
16736
  options.preparedAssets?.buildingModels,
16056
16737
  data.kind === "tileflow-world" ? `${apiBaseUrl}/landmarks/tiles.json` : void 0
16057
16738
  );
@@ -16061,11 +16742,11 @@ function compileSemanticStyleInternal(input, options, inspect, onReport) {
16061
16742
  );
16062
16743
  runCompilationPhase(
16063
16744
  "finalization",
16064
- () => assertTileflowInteractionManifestLayers(interactionManifest, layers)
16745
+ () => assertTileflowInteractionManifestLayers(interactionManifest, layers2)
16065
16746
  );
16066
16747
  runCompilationPhase(
16067
16748
  "finalization",
16068
- () => assertTileflowOverlayPlacementManifestLayers(overlayPlacementManifest, layers)
16749
+ () => assertTileflowOverlayPlacementManifestLayers(overlayPlacementManifest, layers2)
16069
16750
  );
16070
16751
  const glyphs = runCompilationPhase("assets", () => resolveGlyphs(config));
16071
16752
  const sprite = options.preparedAssets?.icons?.sprite;
@@ -16105,10 +16786,10 @@ function compileSemanticStyleInternal(input, options, inspect, onReport) {
16105
16786
  version: 8,
16106
16787
  name: config.name ?? "Streets",
16107
16788
  sources,
16108
- layers
16789
+ layers: layers2
16109
16790
  })
16110
16791
  );
16111
- const flatVegetationLayers = layers.filter((layer) => {
16792
+ const flatVegetationLayers = layers2.filter((layer) => {
16112
16793
  const metadata = layer.metadata;
16113
16794
  return metadata?.["tileflow:vegetation-mode"] !== void 0 || metadata?.["tileflow:domain"] === "vegetation";
16114
16795
  });
@@ -16127,6 +16808,7 @@ function compileSemanticStyleInternal(input, options, inspect, onReport) {
16127
16808
  layer.layout = { ...layer.layout, visibility: "none" };
16128
16809
  }
16129
16810
  const atmosphere = resolveTileflowAtmosphere(config.atmosphere);
16811
+ const notices = compiledNotices(layers2, marine);
16130
16812
  const style = {
16131
16813
  ...atmosphere ? { sky: compileTileflowSky(atmosphere) } : {},
16132
16814
  version: 8,
@@ -16136,7 +16818,7 @@ function compileSemanticStyleInternal(input, options, inspect, onReport) {
16136
16818
  ...config.projection ? { projection: { type: config.projection } } : {},
16137
16819
  ...sprite ? { sprite } : {},
16138
16820
  sources,
16139
- layers,
16821
+ layers: layers2,
16140
16822
  ...terrain?.mode === "3d" && terrain.raster ? { terrain: { exaggeration: terrain.exaggeration, source: terrain.raster.sourceId } } : {},
16141
16823
  metadata: {
16142
16824
  ...mapMetadata ? {
@@ -16176,7 +16858,8 @@ function compileSemanticStyleInternal(input, options, inspect, onReport) {
16176
16858
  ...interactionManifest ? { [tileflowInteractionManifestMetadataKey]: interactionManifest } : {},
16177
16859
  [tileflowOverlayPlacementManifestMetadataKey]: overlayPlacementManifest,
16178
16860
  "tileflow:modules": Object.entries(modules).filter(([, module]) => !isRecord9(module) || module.enabled !== false).map(([name]) => name).sort(),
16179
- ...config.view ? { "tileflow:view": config.view } : {}
16861
+ ...config.view ? { "tileflow:view": config.view } : {},
16862
+ ...notices.length > 0 ? { [tileflowNoticesMetadataKey]: notices } : {}
16180
16863
  }
16181
16864
  };
16182
16865
  const report = {
@@ -16273,6 +16956,11 @@ function assertMapLibreStyle(style, mapId) {
16273
16956
  function isRecord9(value) {
16274
16957
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
16275
16958
  }
16959
+ function compiledNotices(layers2, marine) {
16960
+ const nautical2 = marine?.nautical?.sourceId;
16961
+ if (!nautical2 || !layers2.some((layer) => layer.source === nautical2)) return [];
16962
+ return [{ ...tileflowNauticalNotice, sources: [nautical2] }];
16963
+ }
16276
16964
  function resolveGlyphs(config) {
16277
16965
  if (config.fonts !== void 0) return void 0;
16278
16966
  return config.glyphs?.url;
@@ -16455,8 +17143,8 @@ function runCompilationPhase(phase, operation) {
16455
17143
  }
16456
17144
  }
16457
17145
  function withCompilationPhase(error, phase) {
16458
- const record3 = isRecord9(error) ? error : {};
16459
- if (typeof record3.phase === "string") return error;
17146
+ const record4 = isRecord9(error) ? error : {};
17147
+ if (typeof record4.phase === "string") return error;
16460
17148
  if (error instanceof Error && Object.isExtensible(error)) {
16461
17149
  Object.defineProperty(error, "phase", { configurable: true, enumerable: true, value: phase });
16462
17150
  return error;
@@ -16472,7 +17160,7 @@ function withCompilationPhase(error, phase) {
16472
17160
  "severity",
16473
17161
  "target"
16474
17162
  ]) {
16475
- if (record3[key] !== void 0) Object.assign(wrapped, { [key]: record3[key] });
17163
+ if (record4[key] !== void 0) Object.assign(wrapped, { [key]: record4[key] });
16476
17164
  }
16477
17165
  Object.assign(wrapped, { phase });
16478
17166
  return wrapped;
@@ -18251,9 +18939,9 @@ var tileflowNativeBuildRecordSchema = strictNativeObject({
18251
18939
  engines: strictNativeObject({ android: z13.literal("13.2.0"), ios: z13.literal("6.26.0") }),
18252
18940
  buildManifestSha256: hashSchema,
18253
18941
  transformations: z13.array(tileflowNativeStyleTransformationSchema).max(4096)
18254
- }).superRefine((record3, context) => {
18942
+ }).superRefine((record4, context) => {
18255
18943
  let previous = "";
18256
- for (const [index, item] of record3.transformations.entries()) {
18944
+ for (const [index, item] of record4.transformations.entries()) {
18257
18945
  const name = `${item.map}/${item.theme}`;
18258
18946
  if (name <= previous)
18259
18947
  context.addIssue({
@@ -26956,13 +27644,13 @@ function validateNativeStyle(input, options, stage) {
26956
27644
  issues.push(createTileflowNativeDiagnostic(code, path));
26957
27645
  }
26958
27646
  };
26959
- if (!record2(options) || !plainOptions(options)) {
27647
+ if (!record3(options) || !plainOptions(options)) {
26960
27648
  return [createTileflowNativeDiagnostic("NATIVE_RENDERER_UNSUPPORTED", "/profile")];
26961
27649
  }
26962
27650
  if (options.profile !== void 0 && options.profile !== "native-v1" || !expressionDefinitions) {
26963
27651
  return [createTileflowNativeDiagnostic("NATIVE_RENDERER_UNSUPPORTED", "/profile")];
26964
27652
  }
26965
- if (!isBoundedNativeJson(input, stage) || !record2(input)) {
27653
+ if (!isBoundedNativeJson(input, stage) || !record3(input)) {
26966
27654
  return [createTileflowNativeDiagnostic("NATIVE_UNSUPPORTED_STYLE")];
26967
27655
  }
26968
27656
  const style = input;
@@ -26976,11 +27664,11 @@ function validateNativeStyle(input, options, stage) {
26976
27664
  }
26977
27665
  if (style.projection !== void 0) {
26978
27666
  const projection = style.projection;
26979
- if (!record2(projection) || projection.type !== "mercator" || Object.keys(projection).length !== 1) {
27667
+ if (!record3(projection) || projection.type !== "mercator" || Object.keys(projection).length !== 1) {
26980
27668
  add2("NATIVE_UNSUPPORTED_STYLE", "/projection");
26981
27669
  }
26982
27670
  }
26983
- if (record2(style.metadata)) {
27671
+ if (record3(style.metadata)) {
26984
27672
  for (const key of Object.keys(style.metadata).sort()) {
26985
27673
  if (/^tileflow:(?:contour|pmtiles)/iu.test(key)) {
26986
27674
  add2("NATIVE_UNSUPPORTED_SOURCE", nativePointer("/metadata", key));
@@ -27023,14 +27711,14 @@ function validateNativeStyle(input, options, stage) {
27023
27711
  add2("NATIVE_FONT_UNAVAILABLE", "/glyphs");
27024
27712
  } else checkUrl(style.glyphs, "/glyphs", "glyphs");
27025
27713
  }
27026
- const sources = record2(style.sources) ? style.sources : {};
27714
+ const sources = record3(style.sources) ? style.sources : {};
27027
27715
  if (Object.keys(sources).length > tileflowNativeProfileLimits.maximumSources) {
27028
27716
  add2("NATIVE_UNSUPPORTED_SOURCE", "/sources");
27029
27717
  }
27030
27718
  for (const id2 of Object.keys(sources).sort().slice(0, tileflowNativeProfileLimits.maximumSources)) {
27031
27719
  const source = sources[id2];
27032
27720
  const path = nativePointer("/sources", id2);
27033
- if (!record2(source) || typeof source.type !== "string" || !sourceKinds.has(source.type)) {
27721
+ if (!record3(source) || typeof source.type !== "string" || !sourceKinds.has(source.type)) {
27034
27722
  add2("NATIVE_UNSUPPORTED_SOURCE", path);
27035
27723
  continue;
27036
27724
  }
@@ -27042,7 +27730,7 @@ function validateNativeStyle(input, options, stage) {
27042
27730
  "NATIVE_UNSUPPORTED_SOURCE"
27043
27731
  );
27044
27732
  if (source.clusterProperties !== void 0) {
27045
- if (record2(source.clusterProperties)) {
27733
+ if (record3(source.clusterProperties)) {
27046
27734
  for (const key of Object.keys(source.clusterProperties).sort()) {
27047
27735
  const values = source.clusterProperties[key];
27048
27736
  if (Array.isArray(values))
@@ -27068,7 +27756,7 @@ function validateNativeStyle(input, options, stage) {
27068
27756
  if (faces !== void 0) {
27069
27757
  const support = spec.$root?.["font-faces"]?.["sdk-support"]?.["basic functionality"];
27070
27758
  if (!support || !supportsBoth(support)) add2("NATIVE_FONT_UNAVAILABLE", "/font-faces");
27071
- if (!record2(faces) || Object.keys(faces).length > tileflowNativeProfileLimits.maximumFontFaces) {
27759
+ if (!record3(faces) || Object.keys(faces).length > tileflowNativeProfileLimits.maximumFontFaces) {
27072
27760
  add2("NATIVE_FONT_UNAVAILABLE", "/font-faces");
27073
27761
  } else {
27074
27762
  for (const name of Object.keys(faces).sort()) {
@@ -27080,19 +27768,19 @@ function validateNativeStyle(input, options, stage) {
27080
27768
  }
27081
27769
  }
27082
27770
  }
27083
- const layers = Array.isArray(style.layers) ? style.layers : [];
27084
- if (layers.length > tileflowNativeProfileLimits.maximumLayers)
27771
+ const layers2 = Array.isArray(style.layers) ? style.layers : [];
27772
+ if (layers2.length > tileflowNativeProfileLimits.maximumLayers)
27085
27773
  add2("NATIVE_UNSUPPORTED_STYLE", "/layers");
27086
- layers.slice(0, tileflowNativeProfileLimits.maximumLayers).forEach((layer, i) => {
27774
+ layers2.slice(0, tileflowNativeProfileLimits.maximumLayers).forEach((layer, i) => {
27087
27775
  const path = `/layers/${i}`;
27088
- if (!record2(layer) || typeof layer.type !== "string" || !layerKinds.has(layer.type) || layer.ref !== void 0) {
27776
+ if (!record3(layer) || typeof layer.type !== "string" || !layerKinds.has(layer.type) || layer.ref !== void 0) {
27089
27777
  add2("NATIVE_UNSUPPORTED_STYLE", path);
27090
27778
  return;
27091
27779
  }
27092
27780
  properties(layer, spec.layer, path, add2);
27093
27781
  for (const group of ["layout", "paint"]) {
27094
27782
  const values = layer[group];
27095
- if (!record2(values)) continue;
27783
+ if (!record3(values)) continue;
27096
27784
  properties(
27097
27785
  values,
27098
27786
  spec[`${group}_${layer.type}`],
@@ -27106,7 +27794,7 @@ function validateNativeStyle(input, options, stage) {
27106
27794
  }
27107
27795
  }
27108
27796
  expressions(layer.filter, `${path}/filter`, add2);
27109
- if (!options.deferFontClosure && record2(layer.layout) && layer.layout["text-field"] !== void 0) {
27797
+ if (!options.deferFontClosure && record3(layer.layout) && layer.layout["text-field"] !== void 0) {
27110
27798
  const fonts = layer.layout["text-font"];
27111
27799
  if (style.glyphs === void 0) {
27112
27800
  if (!fontStackAvailable(fonts, faces))
@@ -27116,7 +27804,7 @@ function validateNativeStyle(input, options, stage) {
27116
27804
  }
27117
27805
  });
27118
27806
  for (const key of ["light", "transition"]) {
27119
- if (record2(style[key])) {
27807
+ if (record3(style[key])) {
27120
27808
  properties(style[key], spec[key], `/${key}`, add2);
27121
27809
  for (const [property, value] of Object.entries(style[key]))
27122
27810
  expressions(value, nativePointer(`/${key}`, property), add2);
@@ -27149,7 +27837,7 @@ function properties(values, definitions, path, add2, code = "NATIVE_UNSUPPORTED_
27149
27837
  const basic = definition["sdk-support"]?.["basic functionality"];
27150
27838
  if (basic && !supportsBoth(basic)) add2(code, nativePointer(path, key));
27151
27839
  const value = values[key];
27152
- if (checkFeatureSupport && record2(value) && Object.hasOwn(value, "stops"))
27840
+ if (checkFeatureSupport && record3(value) && Object.hasOwn(value, "stops"))
27153
27841
  add2(code, nativePointer(path, key));
27154
27842
  if (typeof value === "string") {
27155
27843
  const enumSupport = definition.values?.[value]?.["sdk-support"]?.["basic functionality"];
@@ -27175,7 +27863,7 @@ function expressions(value, path, add2) {
27175
27863
  if (index === 0) return;
27176
27864
  if (operator === "match" && index >= 2 && index < value.length - 1 && index % 2 === 0) return;
27177
27865
  if (operator.startsWith("interpolate") && index === 1) return;
27178
- if (record2(child)) {
27866
+ if (record3(child)) {
27179
27867
  for (const key of Object.keys(child).sort())
27180
27868
  expressions(child[key], nativePointer(`${path}/${index}`, key), add2);
27181
27869
  } else expressions(child, `${path}/${index}`, add2);
@@ -27183,14 +27871,14 @@ function expressions(value, path, add2) {
27183
27871
  }
27184
27872
  function fontStackAvailable(value, faces) {
27185
27873
  const stack = Array.isArray(value) && value.length === 2 && value[0] === "literal" ? value[1] : value;
27186
- return Array.isArray(stack) && stack.length > 0 && record2(faces) && stack.every((name) => typeof name === "string" && Object.hasOwn(faces, name));
27874
+ return Array.isArray(stack) && stack.length > 0 && record3(faces) && stack.every((name) => typeof name === "string" && Object.hasOwn(faces, name));
27187
27875
  }
27188
27876
  function inlineFontStacks(value, path, faces, add2) {
27189
27877
  if (!Array.isArray(value) || !isExpression(value) || value[0] === "literal") return;
27190
27878
  value.forEach((child, index) => {
27191
27879
  if (index === 0 || value[0] === "match" && index >= 2 && index < value.length - 1 && index % 2 === 0)
27192
27880
  return;
27193
- if (value[0] === "format" && record2(child) && child["text-font"] !== void 0 && !fontStackAvailable(child["text-font"], faces)) {
27881
+ if (value[0] === "format" && record3(child) && child["text-font"] !== void 0 && !fontStackAvailable(child["text-font"], faces)) {
27194
27882
  add2("NATIVE_FONT_UNAVAILABLE", `${path}/${index}/text-font`);
27195
27883
  }
27196
27884
  inlineFontStacks(child, `${path}/${index}`, faces, add2);
@@ -27207,7 +27895,7 @@ function parserIssuePointer(key, style) {
27207
27895
  path = nativePointer(path, match3[1]);
27208
27896
  value = value[Number(match3[1])];
27209
27897
  rest = rest.slice(match3[0].length).replace(/^\./u, "");
27210
- } else if (record2(value)) {
27898
+ } else if (record3(value)) {
27211
27899
  const matches = Object.keys(value).filter(
27212
27900
  (name2) => rest === name2 || rest.startsWith(`${name2}.`) || rest.startsWith(`${name2}[`)
27213
27901
  );
@@ -27238,7 +27926,7 @@ function plainOptions(value) {
27238
27926
  return false;
27239
27927
  }
27240
27928
  }
27241
- function record2(value) {
27929
+ function record3(value) {
27242
27930
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
27243
27931
  }
27244
27932
  function normalizeNativeDiagnostics(input) {
@@ -27528,15 +28216,15 @@ function semanticIdentity(style) {
27528
28216
  const candidate = object(style.metadata)?.["tileflow:interaction-manifest"];
27529
28217
  if (candidate === void 0) return void 0;
27530
28218
  const manifest = semanticSchema.parse(candidate);
27531
- const layers = style.layers.map((value) => {
28219
+ const layers2 = style.layers.map((value) => {
27532
28220
  const layer = object(value);
27533
28221
  if (!layer) throw new Error();
27534
28222
  return layer;
27535
28223
  });
27536
- assertTileflowInteractionManifestLayers(manifest, layers);
28224
+ assertTileflowInteractionManifestLayers(manifest, layers2);
27537
28225
  const seen = /* @__PURE__ */ new Set();
27538
28226
  for (const layer of manifest.domains.poi?.layers ?? []) {
27539
- if (seen.has(layer.layerId) || layers[layer.priority]?.id !== layer.layerId) throw new Error();
28227
+ if (seen.has(layer.layerId) || layers2[layer.priority]?.id !== layer.layerId) throw new Error();
27540
28228
  seen.add(layer.layerId);
27541
28229
  }
27542
28230
  const poi2 = manifest.domains.poi;