@tileflow/core 0.1.0-alpha.34 → 0.1.0-alpha.35

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/index.js CHANGED
@@ -64,6 +64,7 @@ var init_manifest_schema_classic = __esm({
64
64
  return z2.enum(values);
65
65
  },
66
66
  literal: (value) => z2.literal(value),
67
+ union: (left, right) => z2.union([classic(left), classic(right)]),
67
68
  tuplePair(left, right) {
68
69
  return z2.tuple([classic(left), classic(right)]);
69
70
  },
@@ -296,26 +297,26 @@ function toMapLibreStyleValue(value) {
296
297
  return cloneJson2(value);
297
298
  }
298
299
  function isTileflowExpression(value) {
299
- return isRecord(value) && value.kind === "expression" && Array.isArray(value.value);
300
+ return isRecord2(value) && value.kind === "expression" && Array.isArray(value.value);
300
301
  }
301
302
  function isTileflowZoomValue(value) {
302
- return isRecord(value) && value.kind === "zoom" && Array.isArray(value.stops);
303
+ return isRecord2(value) && value.kind === "zoom" && Array.isArray(value.stops);
303
304
  }
304
305
  function isTileflowThemeTokenReference(value) {
305
- return isRecord(value) && hasExactOwnKeys(value, ["category", "kind", "token"]) && value.kind === "theme-token" && typeof value.token === "string" && /^[A-Za-z][A-Za-z0-9_-]*(?:\.[A-Za-z][A-Za-z0-9_-]*)*$/.test(value.token) && tileflowThemeTokenCategories.includes(value.category);
306
+ return isRecord2(value) && hasExactOwnKeys(value, ["category", "kind", "token"]) && value.kind === "theme-token" && typeof value.token === "string" && /^[A-Za-z][A-Za-z0-9_-]*(?:\.[A-Za-z][A-Za-z0-9_-]*)*$/.test(value.token) && tileflowThemeTokenCategories.includes(value.category);
306
307
  }
307
308
  function isTileflowFixedValue(value) {
308
- return isRecord(value) && hasExactOwnKeys(value, ["kind", "reason", "value"]) && value.kind === "theme-fixed" && typeof value.reason === "string" && Boolean(value.reason.trim()) && Object.hasOwn(value, "value");
309
+ return isRecord2(value) && hasExactOwnKeys(value, ["kind", "reason", "value"]) && value.kind === "theme-fixed" && typeof value.reason === "string" && Boolean(value.reason.trim()) && Object.hasOwn(value, "value");
309
310
  }
310
311
  function isTileflowThemeColorOperation(value) {
311
- if (!isRecord(value) || value.kind !== "theme-color") return false;
312
+ if (!isRecord2(value) || value.kind !== "theme-color") return false;
312
313
  if (value.operation === "alpha") {
313
314
  return hasExactOwnKeys(value, ["color", "kind", "opacity", "operation"]) && Object.hasOwn(value, "color") && Object.hasOwn(value, "opacity");
314
315
  }
315
316
  return value.operation === "mix" && hasExactOwnKeys(value, ["amount", "from", "kind", "operation", "space", "to"]) && value.space === "oklch" && Object.hasOwn(value, "amount") && Object.hasOwn(value, "from") && Object.hasOwn(value, "to");
316
317
  }
317
318
  function isTileflowThemeValueNode(value) {
318
- return isRecord(value) && (value.kind === "theme-token" || value.kind === "theme-fixed" || value.kind === "theme-color");
319
+ return isRecord2(value) && (value.kind === "theme-token" || value.kind === "theme-fixed" || value.kind === "theme-color");
319
320
  }
320
321
  function createZoomValue(interpolation, stops, base) {
321
322
  if (stops.length === 0) {
@@ -368,7 +369,7 @@ function cloneJson2(value) {
368
369
  }
369
370
  return JSON.parse(serialized);
370
371
  }
371
- function isRecord(value) {
372
+ function isRecord2(value) {
372
373
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
373
374
  }
374
375
  function hasExactOwnKeys(value, expectedKeys) {
@@ -440,6 +441,63 @@ var init_values = __esm({
440
441
  }
441
442
  });
442
443
 
444
+ // src/time-of-day.ts
445
+ function isTileflowTimeOfDay(value) {
446
+ return typeof value === "string" && tileflowTimesOfDay.includes(value);
447
+ }
448
+ function validateTileflowTimeOfDayVariants(variants, themes) {
449
+ const issues = [];
450
+ const owners = /* @__PURE__ */ new Map();
451
+ const families = Object.entries(variants);
452
+ for (const [family, moments] of families) {
453
+ if (!isTileflowThemeName(family) || !Object.hasOwn(themes, family)) {
454
+ issues.push({ path: [family], message: "Time-of-day family must name an existing theme" });
455
+ }
456
+ if (!Object.values(moments).includes(family)) {
457
+ issues.push({ path: [family], message: "A family must include its own theme in its presets" });
458
+ }
459
+ for (const [moment, name] of Object.entries(moments)) {
460
+ if (name === void 0) continue;
461
+ if (!isTileflowTimeOfDay(moment) || !isTileflowThemeName(name) || !Object.hasOwn(themes, name)) {
462
+ issues.push({
463
+ path: [family, moment],
464
+ message: "Expected a supported moment and an existing theme"
465
+ });
466
+ }
467
+ const owner = owners.get(name);
468
+ if (owner !== void 0 && owner !== family) {
469
+ issues.push({
470
+ path: [family, moment],
471
+ message: `Theme "${name}" already belongs to family "${owner}"`
472
+ });
473
+ }
474
+ owners.set(name, family);
475
+ }
476
+ }
477
+ return issues;
478
+ }
479
+ function resolveTileflowTimeOfDayTheme(variants, theme, timeOfDay) {
480
+ if (timeOfDay === void 0 || variants === void 0) return theme;
481
+ if (!isTileflowTimeOfDay(timeOfDay)) throw new TypeError("Expected day, dawn, dusk, or night");
482
+ const family = Object.hasOwn(variants, theme) ? variants[theme] : Object.values(variants).find((moments) => Object.values(moments).includes(theme));
483
+ if (!family) return theme;
484
+ const result = family[timeOfDay];
485
+ if (result === void 0) {
486
+ throw new Error(
487
+ `Theme "${theme}" does not offer timeOfDay="${timeOfDay}". Available: ${Object.keys(family).join(", ")}.`
488
+ );
489
+ }
490
+ return result;
491
+ }
492
+ var tileflowTimesOfDay;
493
+ var init_time_of_day = __esm({
494
+ "src/time-of-day.ts"() {
495
+ "use strict";
496
+ init_portable_identity_rules();
497
+ tileflowTimesOfDay = ["day", "dawn", "dusk", "night"];
498
+ }
499
+ });
500
+
443
501
  // src/theme-blend.ts
444
502
  function mixTileflowColours(from, to, t) {
445
503
  const a = oklab(from);
@@ -662,9 +720,9 @@ function tileflowSunMetadata(preset) {
662
720
  return Object.freeze({ version: 1, ...preset });
663
721
  }
664
722
  function readTileflowSunPreset(metadata) {
665
- if (!isRecord6(metadata)) return void 0;
723
+ if (!isRecord5(metadata)) return void 0;
666
724
  const value = metadata[tileflowSunMetadataKey];
667
- if (!isRecord6(value) || value.version !== 1 || !isRecord6(value.ambient)) return void 0;
725
+ if (!isRecord5(value) || value.version !== 1 || !isRecord5(value.ambient)) return void 0;
668
726
  const { azimuth, altitude, color: color3, intensity, shadowIntensity } = value;
669
727
  const ambient = value.ambient;
670
728
  if (!isFiniteNumber(azimuth) || !isFiniteNumber(altitude) || !isUnit(intensity) || !isUnit(shadowIntensity) || !isUnit(ambient.intensity) || !isColour(color3) || !isColour(ambient.color))
@@ -681,7 +739,7 @@ function readTileflowSunPreset(metadata) {
681
739
  function tileflowStyleSunPreset(style) {
682
740
  const published = readTileflowSunPreset(style?.metadata);
683
741
  if (published) return published;
684
- const light = isRecord6(style?.light) ? style.light : void 0;
742
+ const light = isRecord5(style?.light) ? style.light : void 0;
685
743
  const position = light?.position;
686
744
  if (!position) return tileflowDefaultSunPreset;
687
745
  return Object.freeze({
@@ -719,7 +777,7 @@ function smoothstep2(from, to, value) {
719
777
  function clamp01(value) {
720
778
  return Math.min(1, Math.max(0, Number.isFinite(value) ? value : 0));
721
779
  }
722
- function isRecord6(value) {
780
+ function isRecord5(value) {
723
781
  return typeof value === "object" && value !== null && !Array.isArray(value);
724
782
  }
725
783
  function isFiniteNumber(value) {
@@ -933,7 +991,7 @@ function resolveThemeValues(value, theme, path = "value") {
933
991
  if (errors.length > 0) throw new TileflowThemeAuditError(errors);
934
992
  return resolved;
935
993
  }
936
- function resolveThemeSelection(map, requested) {
994
+ function resolveThemeSelection(map, requested, timeOfDay) {
937
995
  const name = requested ?? map.defaultTheme;
938
996
  if (name === "system") {
939
997
  throw new Error(
@@ -950,7 +1008,8 @@ function resolveThemeSelection(map, requested) {
950
1008
  const available = Object.keys(map.themes).sort().join(", ") || "<none>";
951
1009
  throw new Error(`Unknown Tileflow theme "${name}"; available themes: ${available}.`);
952
1010
  }
953
- return { name, theme };
1011
+ const resolvedName = resolveTileflowTimeOfDayTheme(map.timeOfDay, name, timeOfDay);
1012
+ return { name: resolvedName, theme: map.themes[resolvedName] };
954
1013
  }
955
1014
  function auditTileflowThemeValues(value, path = "value", context = inferAuditContext(path)) {
956
1015
  const diagnostics = [];
@@ -963,7 +1022,7 @@ function auditTileflowThemeValues(value, path = "value", context = inferAuditCon
963
1022
  return diagnostics.sort(compareAuditDiagnostics);
964
1023
  }
965
1024
  function auditTileflowMapThemeValues(map) {
966
- const modules = isRecord7(map.modules) ? map.modules : void 0;
1025
+ const modules = isRecord6(map.modules) ? map.modules : void 0;
967
1026
  const moduleDiagnostics = modules ? Object.keys(modules).sort(compareCodeUnits2).flatMap(
968
1027
  (owner) => auditTileflowThemeValues(modules[owner], `modules.${owner}`, {
969
1028
  owner,
@@ -1070,7 +1129,7 @@ function isThemePrimitiveForCategory(value, category) {
1070
1129
  return category === "number" ? typeof value === "number" && Number.isFinite(value) || Array.isArray(value) && value.every((entry) => typeof entry === "number" && Number.isFinite(entry)) : typeof value === "string" && value.length > 0;
1071
1130
  }
1072
1131
  function isThemeValueCandidate(value) {
1073
- return isRecord7(value) && (value.kind === "theme-token" || value.kind === "theme-fixed" || value.kind === "theme-color");
1132
+ return isRecord6(value) && (value.kind === "theme-token" || value.kind === "theme-fixed" || value.kind === "theme-color");
1074
1133
  }
1075
1134
  function visitAuditableValue(value, path, category, state, intentRequired = false) {
1076
1135
  if (isThemeStructuralPath(path)) category = void 0;
@@ -1086,7 +1145,7 @@ function visitAuditableValue(value, path, category, state, intentRequired = fals
1086
1145
  visitAuditableArray(value, path, category, state, false, intentRequired);
1087
1146
  return;
1088
1147
  }
1089
- if (!isRecord7(value)) return;
1148
+ if (!isRecord6(value)) return;
1090
1149
  if (value.kind === "expression" && Array.isArray(value.value)) {
1091
1150
  visitAuditableArray(value.value, `${path}.value`, category, state, true, intentRequired);
1092
1151
  return;
@@ -1469,7 +1528,7 @@ function assertThemeLighting(value, path) {
1469
1528
  }
1470
1529
  }
1471
1530
  function assertThemeCategoryValue(value, expectedCategory, path) {
1472
- if (!isRecord7(value)) {
1531
+ if (!isRecord6(value)) {
1473
1532
  assertTokenPrimitive(expectedCategory, value, path);
1474
1533
  return;
1475
1534
  }
@@ -1830,11 +1889,11 @@ function cloneJson14(value) {
1830
1889
  if (serialized === void 0) throw new Error("Tileflow themes must be JSON-serializable.");
1831
1890
  return JSON.parse(serialized);
1832
1891
  }
1833
- function isRecord7(value) {
1892
+ function isRecord6(value) {
1834
1893
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
1835
1894
  }
1836
1895
  function isPlainRecord(value) {
1837
- if (!isRecord7(value)) return false;
1896
+ if (!isRecord6(value)) return false;
1838
1897
  const prototype = Object.getPrototypeOf(value);
1839
1898
  return prototype === Object.prototype || prototype === null;
1840
1899
  }
@@ -1845,6 +1904,7 @@ var tileflowThemeLimits, TileflowThemeAuditError, defaultTypography, themeDocume
1845
1904
  var init_model = __esm({
1846
1905
  "src/themes/model.ts"() {
1847
1906
  "use strict";
1907
+ init_time_of_day();
1848
1908
  init_expression_operators();
1849
1909
  init_values();
1850
1910
  init_portable_identity_rules();
@@ -1947,7 +2007,7 @@ var init_model = __esm({
1947
2007
  if (Array.isArray(value)) {
1948
2008
  return value.map((entry, index) => this.resolveTree(entry, `${path}[${index}]`, category));
1949
2009
  }
1950
- if (!isRecord7(value)) return value;
2010
+ if (!isRecord6(value)) return value;
1951
2011
  if (value.kind === "expression" && Array.isArray(value.value)) {
1952
2012
  return {
1953
2013
  ...value,
@@ -2170,12 +2230,31 @@ var init_model = __esm({
2170
2230
  }
2171
2231
  });
2172
2232
 
2233
+ // src/time-of-day-schema.ts
2234
+ function createTileflowTimeOfDaySchema(operations2, themeName) {
2235
+ return operations2.record(
2236
+ themeName,
2237
+ operations2.object({
2238
+ day: operations2.optional(themeName),
2239
+ dawn: operations2.optional(themeName),
2240
+ dusk: operations2.optional(themeName),
2241
+ night: operations2.optional(themeName)
2242
+ })
2243
+ );
2244
+ }
2245
+ var init_time_of_day_schema = __esm({
2246
+ "src/time-of-day-schema.ts"() {
2247
+ "use strict";
2248
+ }
2249
+ });
2250
+
2173
2251
  // src/manifest-types.ts
2174
- var tileflowRuntimeManifestVersion, tileflowRuntimeManifestLimits;
2252
+ var tileflowRuntimeManifestVersion, tileflowTimeOfDayManifestVersion, tileflowRuntimeManifestLimits;
2175
2253
  var init_manifest_types = __esm({
2176
2254
  "src/manifest-types.ts"() {
2177
2255
  "use strict";
2178
2256
  tileflowRuntimeManifestVersion = 1;
2257
+ tileflowTimeOfDayManifestVersion = 2;
2179
2258
  tileflowRuntimeManifestLimits = Object.freeze({ maximumBytes: 1024 * 1024 });
2180
2259
  }
2181
2260
  });
@@ -2252,12 +2331,24 @@ function createTileflowRuntimeManifestSchema(primitives, operations2, identities
2252
2331
  })
2253
2332
  ),
2254
2333
  themes: operations2.record(tileflowThemeNameSchema2, manifestThemeSchema),
2334
+ timeOfDay: operations2.optional(
2335
+ createTileflowTimeOfDaySchema(operations2, tileflowThemeNameSchema2)
2336
+ ),
2255
2337
  usageMode: operations2.optional(operations2.literal("session")),
2256
2338
  view: operations2.optional(viewSchema2),
2257
2339
  worldGeneration: operations2.optional(operations2.literal("v1"))
2258
2340
  }),
2259
2341
  (entry, context) => {
2260
2342
  const names = Object.keys(entry.themes);
2343
+ if (entry.timeOfDay) {
2344
+ for (const issue of validateTileflowTimeOfDayVariants(entry.timeOfDay, entry.themes)) {
2345
+ context.addIssue({
2346
+ code: "custom",
2347
+ message: issue.message,
2348
+ path: ["timeOfDay", ...issue.path]
2349
+ });
2350
+ }
2351
+ }
2261
2352
  if (names.length === 0) {
2262
2353
  context.addIssue({
2263
2354
  code: "custom",
@@ -2311,10 +2402,23 @@ function createTileflowRuntimeManifestSchema(primitives, operations2, identities
2311
2402
  operations2.object({
2312
2403
  apiUrl: operations2.optional(apiOriginSchema),
2313
2404
  maps: operations2.record(tileflowPortableIdSchema2, manifestMapSchema),
2314
- version: operations2.literal(tileflowRuntimeManifestVersion)
2405
+ version: operations2.union(
2406
+ operations2.literal(tileflowRuntimeManifestVersion),
2407
+ operations2.literal(2)
2408
+ )
2315
2409
  }),
2316
2410
  (manifest, context) => {
2317
2411
  const mapCount = Object.keys(manifest.maps).length;
2412
+ if (manifest.version === 1) {
2413
+ for (const [name, map] of Object.entries(manifest.maps)) {
2414
+ if (map.timeOfDay !== void 0)
2415
+ context.addIssue({
2416
+ code: "custom",
2417
+ message: "timeOfDay requires manifest version 2",
2418
+ path: ["maps", name, "timeOfDay"]
2419
+ });
2420
+ }
2421
+ }
2318
2422
  if (mapCount === 0) {
2319
2423
  context.addIssue({ code: "custom", message: "Expected at least one map", path: ["maps"] });
2320
2424
  }
@@ -2427,6 +2531,8 @@ var init_manifest_schema = __esm({
2427
2531
  init_portable_identity_schema();
2428
2532
  init_runtime_view_schema();
2429
2533
  init_model();
2534
+ init_time_of_day();
2535
+ init_time_of_day_schema();
2430
2536
  }
2431
2537
  });
2432
2538
 
@@ -2437,7 +2543,8 @@ __export(manifest_exports, {
2437
2543
  safeParseTileflowRuntimeManifest: () => safeParseTileflowRuntimeManifest,
2438
2544
  tileflowRuntimeManifestLimits: () => tileflowRuntimeManifestLimits,
2439
2545
  tileflowRuntimeManifestSchema: () => tileflowRuntimeManifestSchema,
2440
- tileflowRuntimeManifestVersion: () => tileflowRuntimeManifestVersion
2546
+ tileflowRuntimeManifestVersion: () => tileflowRuntimeManifestVersion,
2547
+ tileflowTimeOfDayManifestVersion: () => tileflowTimeOfDayManifestVersion
2441
2548
  });
2442
2549
  function parseTileflowRuntimeManifest(input) {
2443
2550
  return tileflowRuntimeManifestSchema.parse(input);
@@ -2464,6 +2571,277 @@ var init_manifest = __esm({
2464
2571
  }
2465
2572
  });
2466
2573
 
2574
+ // ../../node_modules/.pnpm/meshoptimizer@1.3.0/node_modules/meshoptimizer/meshopt_decoder.mjs
2575
+ var meshopt_decoder_exports = {};
2576
+ __export(meshopt_decoder_exports, {
2577
+ MeshoptDecoder: () => MeshoptDecoder
2578
+ });
2579
+ var MeshoptDecoder;
2580
+ var init_meshopt_decoder = __esm({
2581
+ "../../node_modules/.pnpm/meshoptimizer@1.3.0/node_modules/meshoptimizer/meshopt_decoder.mjs"() {
2582
+ "use strict";
2583
+ MeshoptDecoder = (function() {
2584
+ var wasm_base = "b9H79Tebbbe8Fv9Gbb9Gvuuuuueu9Giuuub9Geueu9Giuuueuixkbeeeddddillviebeoweuecj:Gdkr;Neqo9TW9T9VV95dbH9F9F939H79T9F9J9H229F9Jt9VV7bb8A9TW79O9V9Wt9F9KW9J9V9KW9wWVtW949c919M9MWVbeY9TW79O9V9Wt9F9KW9J9V9KW69U9KW949c919M9MWVbdE9TW79O9V9Wt9F9KW9J9V9KW69U9KW949tWG91W9U9JWbiL9TW79O9V9Wt9F9KW9J9V9KWS9P2tWV9p9JtblK9TW79O9V9Wt9F9KW9J9V9KWS9P2tWV9r919HtbvL9TW79O9V9Wt9F9KW9J9V9KWS9P2tWVT949WboY9TW79O9V9Wt9F9KW9J9V9KWS9P2tWVJ9V29VVbrl79IV9Rbwq;X8:kdbk:kYi5ud9:du8Jjjjjbcjq9Rgv8Kjjjjbc9:hodnalTmbcuhoaiRbbgrc;WeGc:Ge9hmbarcsGgwce0mbc9:hoalcufadcd4cbawEgDadfgrcKcaawEgqaraq0Egk6mbaicefhxcj;abad9Uc;WFbGcjdadca0EhmaialfgPar9Rgoadfhsavaoadz:jjjjbgzceVhHcbhOdndninaeaO9nmeaPax9RaD6mdamaeaO9RaOamfgoae6EgAcsfglc9WGhCaAcethXaxaDfhiaOaeaoaeao6E9RhQalcl4cifcd4hLazcjdfaAfhKcbhYabaOad2fg8AhEaHh3incbh5dnawTmbaxaYcd4fRbbh5kcbh8Eazcjdfhqinaih8Fdndndndna5a8Ecet4ciGgoc9:fPdebdkaPa8F9RaA6mrazcjdfa8EaA2fa8FaAz:jjjjb8Aa8FaAfhixdkazcjdfa8EaA2fcbaAz:kjjjb8Aa8FhixekaPa8F9RaL6mva8FaLfhidnaCTmbaPai9RcK6mbaocdtc:q:G:cjbfcj:G:cjbawEhaczhrcbhlinargoc9Wfghaqfhrdndndndndndnaaa8Fahco4fRbbalcoG4ciGcdtfydbPDbedvivvvlvkar9cb83bwar9cb83bbxlkarcbaiRbdai8Xbb9c:c:qj:bw9:9c:q;c1:I1e:d9c:b:c:e1z9:gg9cjjjjjz:dg8J9qE86bbaqaofgrcGfcbaicdfa8J9c8N1:NfghRbbag9cjjjjjw:dg8J9qE86bbarcVfcbaha8J9c8M1:NfghRbbag9cjjjjjl:dg8J9qE86bbarc7fcbaha8J9c8L1:NfghRbbag9cjjjjjd:dg8J9qE86bbarctfcbaha8J9c8K1:NfghRbbag9cjjjjje:dg8J9qE86bbarc91fcbaha8J9c8J1:NfghRbbag9cjjjj;ab:dg8J9qE86bbarc4fcbaha8J9cg1:NfghRbbag9cjjjja:dg8J9qE86bbarc93fcbaha8J9ch1:NfghRbbag9cjjjjz:dgg9qE86bbarc94fcbahag9ca1:NfghRbbai8Xbe9c:c:qj:bw9:9c:q;c1:I1e:d9c:b:c:e1z9:gg9cjjjjjz:dg8J9qE86bbarc95fcbaha8J9c8N1:NfgiRbbag9cjjjjjw:dg8J9qE86bbarc96fcbaia8J9c8M1:NfgiRbbag9cjjjjjl:dg8J9qE86bbarc97fcbaia8J9c8L1:NfgiRbbag9cjjjjjd:dg8J9qE86bbarc98fcbaia8J9c8K1:NfgiRbbag9cjjjjje:dg8J9qE86bbarc99fcbaia8J9c8J1:NfgiRbbag9cjjjj;ab:dg8J9qE86bbarc9:fcbaia8J9cg1:NfgiRbbag9cjjjja:dg8J9qE86bbarcufcbaia8J9ch1:NfgiRbbag9cjjjjz:dgg9qE86bbaiag9ca1:NfhixikaraiRblaiRbbghco4g8Ka8KciSg8KE86bbaqaofgrcGfaiclfa8Kfg8KRbbahcl4ciGg8La8LciSg8LE86bbarcVfa8Ka8Lfg8KRbbahcd4ciGg8La8LciSg8LE86bbarc7fa8Ka8Lfg8KRbbahciGghahciSghE86bbarctfa8Kahfg8KRbbaiRbeghco4g8La8LciSg8LE86bbarc91fa8Ka8Lfg8KRbbahcl4ciGg8La8LciSg8LE86bbarc4fa8Ka8Lfg8KRbbahcd4ciGg8La8LciSg8LE86bbarc93fa8Ka8Lfg8KRbbahciGghahciSghE86bbarc94fa8Kahfg8KRbbaiRbdghco4g8La8LciSg8LE86bbarc95fa8Ka8Lfg8KRbbahcl4ciGg8La8LciSg8LE86bbarc96fa8Ka8Lfg8KRbbahcd4ciGg8La8LciSg8LE86bbarc97fa8Ka8Lfg8KRbbahciGghahciSghE86bbarc98fa8KahfghRbbaiRbigico4g8Ka8KciSg8KE86bbarc99faha8KfghRbbaicl4ciGg8Ka8KciSg8KE86bbarc9:faha8KfghRbbaicd4ciGg8Ka8KciSg8KE86bbarcufaha8KfgrRbbaiciGgiaiciSgiE86bbaraifhixdkaraiRbwaiRbbghcl4g8Ka8KcsSg8KE86bbaqaofgrcGfaicwfa8Kfg8KRbbahcsGghahcsSghE86bbarcVfa8KahfghRbbaiRbeg8Kcl4g8La8LcsSg8LE86bbarc7faha8LfghRbba8KcsGg8Ka8KcsSg8KE86bbarctfaha8KfghRbbaiRbdg8Kcl4g8La8LcsSg8LE86bbarc91faha8LfghRbba8KcsGg8Ka8KcsSg8KE86bbarc4faha8KfghRbbaiRbig8Kcl4g8La8LcsSg8LE86bbarc93faha8LfghRbba8KcsGg8Ka8KcsSg8KE86bbarc94faha8KfghRbbaiRblg8Kcl4g8La8LcsSg8LE86bbarc95faha8LfghRbba8KcsGg8Ka8KcsSg8KE86bbarc96faha8KfghRbbaiRbvg8Kcl4g8La8LcsSg8LE86bbarc97faha8LfghRbba8KcsGg8Ka8KcsSg8KE86bbarc98faha8KfghRbbaiRbog8Kcl4g8La8LcsSg8LE86bbarc99faha8LfghRbba8KcsGg8Ka8KcsSg8KE86bbarc9:faha8KfghRbbaiRbrgicl4g8Ka8KcsSg8KE86bbarcufaha8KfgrRbbaicsGgiaicsSgiE86bbaraifhixekarai8Pbw83bwarai8Pbb83bbaiczfhikdnaoaC9pmbalcdfhlaoczfhraPai9RcL0mekkaoaC6moaimexokaCmva8FTmvkaqaAfhqa8Ecefg8Ecl9hmbkdndndndnawTmbasaYcd4fRbbgociGPlbedrbkaATmdazaYfh8Fazcjdfhhcbh8EaEhaina8FRbbhraahocbhlinaoahalfRbbgqce4cbaqceG9R7arfgr86bbaoadfhoaAalcefgl9hmbkaacefhaa8Fcefh8FahaAfhha8Ecefg8Ecl9hmbxikkaATmeazaYfhaazcjdfhhcbhoceh8EaKh8FinaEaofhlaa8Vbbhrcbhoinala8FaofRbbcwtahaofRbbgqVc;:FiGce4cbaqceG9R7arfgr87bbaladfhlaQaocefgofmbka8FaXfh8FcdhoaacdfhaahaXfhha8EceGhlcbh8EalmbxdkkaATmbaocl4h8EazaYfRbbhqcwhoa3hlinalRbbaotaqVhqalcefhlaocwfgoca9hmbkcbhhaEh8FaKhainazcjdfahfRbbhrcwhoaahlinalRbbaotarVhralaAfhlaocwfgoca9hmbkara8E94aq7hqcbhoa8Fhlinalaqao486bbalcefhlaocwfgoca9hmbka8Fadfh8FaacefhaahcefghaA9hmbkkaEclfhEa3clfh3aYclfgYad6mbkaza8AaAcufad2fadz:jjjjb8AaAaOfhOaihxaimbkc9:hoxdkcbc99aPax9RakSEhoxekc9:hokavcjqf8Kjjjjbaok:bsesu8Jjjjjbc;ae9Rgv8Kjjjjbc9:hodnalaeci9UgrcHf6mbcuhoaiRbbgwc;WeGc;Ge9hmbawcsGgwce0mbavc;abfcFecjez:kjjjb8Aav9cu83iUav9cu83i8Wav9cu83iyav9cu83iaav9cu83iKav9cu83izav9cu83iwav9cu83ibaialfc9WfhDaicefgiarfhqdndnaeci9pmbaqhexekcmcsawceSEhkcbhxcbhmaqhecbhlcbhoindndnaiRbbgrc;Ve0mbavc;abfaoarcu7gPcl4fcsGcitfgwydlhsawydbhzdndnarcsGgwak9pmbavalaPfcsGcdtfydbaxawEhraxawTgHfhxxekdnaeaD9nmbc9:hoxokdndnawcsSmbcehHamawcetfcWfhrxekaecefhrae8SbbgwcFeGhPdndnawcu9mmbarhexekaecvfheaPcFbGhPcrhwdninar8SbbgHcFbGawtaPVhPaHcu9kmearcefhrawcrfgwc8J9hmbxdkkarcefhekcehHaPce4cbaPceG9R7amfhrkarhmkavc;abfaocitfgwarBdbawasBdlavalcdtfarBdbavc;abfaocefcsGcitfgwazBdbawarBdlaocdfhoaHalfhldnadcd9hmbabar87elabas87edabaz87ebabcofhbxdkabarBdwabasBdlabazBdbabcxfhbxekdnarcpe0mbavalaDarcsGfRbbgwcl4gP9RcsGcdtfydbaxcefgsaPEhravalaw9RcsGcdtfydbasaPTgzfgsawcsGgPEhwaPThPdndnadcd9hmbabaw87elabar87edabax87ebcohHxekabawBdwabarBdlabaxBdbcxhHkavalcdtfaxBdbavc;abfaocitfgOarBdbaOaxBdlavalcefglcsGcdtfarBdbavc;abfaocefcsGcitfgOawBdbaOarBdlavalazfglcsGcdtfawBdbavc;abfaocdfcsGcitfgraxBdbarawBdlaocifhoabaHfhbalaPfhlasaPfhxxekdnaeaD9nmbc9:hoxlkaxcbaeRbbgwEgHarc;:eSgrfhsawcsGhOdndnawcl4gAmbascefhzxekashzavalaA9RcsGcdtfydbhskdndnaOmbazcefhxxekazhxavalaw9RcsGcdtfydbhzkdndnarTmbaecefhrxekaecdfhrae8SbegPcFeGhwdnaPcu9kmbaecofhHawcFbGhwcrhedninar8SbbgPcFbGaetawVhwaPcu9kmearcefhraecrfgec8J9hmbkaHhrxekarcefhrkawce4cbawceG9R7amfgmhHkdndnaAcsSmbarhwxekarcefhwar8SbbgecFeGhPdnaecu9kmbarcvfhsaPcFbGhPcrhedninaw8SbbgrcFbGaetaPVhParcu9kmeawcefhwaecrfgec8J9hmbkashwxekawcefhwkaPce4cbaPceG9R7amfgmhskdndnaOcsSmbawhexekawcefheaw8SbbgrcFeGhPdnarcu9kmbawcvfhzaPcFbGhPcrhrdninae8SbbgwcFbGartaPVhPawcu9kmeaecefhearcrfgrc8J9hmbkazhexekaecefhekaPce4cbaPceG9R7amfgmhzkdndnadcd9hmbabaz87elabas87edabaH87ebcohrxekabazBdwabasBdlabaHBdbcxhrkavc;abfaocitfgwasBdbawaHBdlavalcdtfaHBdbavc;abfaocefcsGcitfgwazBdbawasBdlavalcefglcsGcdtfasBdbavc;abfaocdfcsGcitfgwaHBdbawazBdlavalaATaAcsSVfglcsGcdtfazBdbalaOTaOcsSVfhlaocifhoabarfhbkaocsGhoalcsGhlaicefgiaq6mbkkcbc99aeaDSEhokavc;aef8Kjjjjbaok:clevu8Jjjjjbcz9Rhvdnalaecvf9pmbc9:skdnaiRbbc;:eGc;qeSmbcuskav9cb83iwaicefhoaialfc98fhrdnaeTmbdnadcdSmbcbhwindnaoar6mbc9:skaocefhlao8SbbgicFeGhddndnaicu9mmbalhoxekaocvfhoadcFbGhdcrhidninal8SbbgDcFbGaitadVhdaDcu9kmealcefhlaicrfgic8J9hmbxdkkalcefhokabawcdtfadc8Etc8F91adcd47avcwfadceGcdtVglydbfgiBdbalaiBdbawcefgwae9hmbxdkkcbhwindnaoar6mbc9:skaocefhlao8SbbgicFeGhddndnaicu9mmbalhoxekaocvfhoadcFbGhdcrhidninal8SbbgDcFbGaitadVhdaDcu9kmealcefhlaicrfgic8J9hmbxdkkalcefhokabawcetfadc8Etc8F91adcd47avcwfadceGcdtVglydbfgi87ebalaiBdbawcefgwae9hmbkkcbc99aoarSEk:Lvoeue99dud99eud99dndnadcl9hmbaeTmeindndnabcdfgd8Sbb:Yab8Sbbgi:Ygl:l:tabcefgv8Sbbgo:Ygr:l:tgwJbb;:9cawawNJbbbbawawJbbbb9GgDEgq:mgkaqaicb9iEalMgwawNakaqaocb9iEarMgqaqNMM:r:vglNJbbbZJbbb:;aDEMgr:lJbbb9p9DTmbar:Ohixekcjjjj94hikadai86bbdndnaqalNJbbbZJbbb:;aqJbbbb9GEMgq:lJbbb9p9DTmbaq:Ohdxekcjjjj94hdkavad86bbdndnawalNJbbbZJbbb:;awJbbbb9GEMgw:lJbbb9p9DTmbaw:Ohdxekcjjjj94hdkabad86bbabclfhbaecufgembxdkkaeTmbindndnabclfgd8Ueb:Yab8Uebgi:Ygl:l:tabcdfgv8Uebgo:Ygr:l:tgwJb;:FSawawNJbbbbawawJbbbb9GgDEgq:mgkaqaicb9iEalMgwawNakaqaocb9iEarMgqaqNMM:r:vglNJbbbZJbbb:;aDEMgr:lJbbb9p9DTmbar:Ohixekcjjjj94hikadai87ebdndnaqalNJbbbZJbbb:;aqJbbbb9GEMgq:lJbbb9p9DTmbaq:Ohdxekcjjjj94hdkavad87ebdndnawalNJbbbZJbbb:;awJbbbb9GEMgw:lJbbb9p9DTmbaw:Ohdxekcjjjj94hdkabad87ebabcwfhbaecufgembkkk:4ioiue99dud99dud99dnaeTmbcbhiabhlindndnal8Uebgv:YgoJ:ji:1Salcof8UebgrciVgw:Y:vgDNJbbbZJbbb:;avcu9kEMgq:lJbbb9p9DTmbaq:Ohkxekcjjjj94hkkalclf8Uebhvalcdf8UebhxalarcefciGcetfak87ebdndnax:YgqaDNJbbbZJbbb:;axcu9kEMgm:lJbbb9p9DTmbam:Ohxxekcjjjj94hxkabaiarciGgkfcd7cetfax87ebdndnav:YgmaDNJbbbZJbbb:;avcu9kEMgP:lJbbb9p9DTmbaP:Ohvxekcjjjj94hvkalarcufciGcetfav87ebdndnawaw2:ZgPaPMaoaoN:taqaqN:tamamN:tgoJbbbbaoJbbbb9GE:raDNJbbbZMgD:lJbbb9p9DTmbaD:Ohrxekcjjjj94hrkalakcetfar87ebalcwfhlaiclfhiaecufgembkkk9mbdnadcd4ae2gdTmbinababydbgecwtcw91:Yaece91cjjj98Gcjjj;8if::NUdbabclfhbadcufgdmbkkk:Tvirud99eudndnadcl9hmbaeTmeindndnabRbbgiabcefgl8Sbbgvabcdfgo8Sbbgrf9R:YJbbuJabcifgwRbbgdce4adVgDcd4aDVgDcl4aDVgD:Z:vgqNJbbbZMgk:lJbbb9p9DTmbak:Ohxxekcjjjj94hxkaoax86bbdndnaraif:YaqNJbbbZMgk:lJbbb9p9DTmbak:Ohoxekcjjjj94hokalao86bbdndnavaifar9R:YaqNJbbbZMgk:lJbbb9p9DTmbak:Ohixekcjjjj94hikabai86bbdndnaDadcetGadceGV:ZaqNJbbbZMgq:lJbbb9p9DTmbaq:Ohdxekcjjjj94hdkawad86bbabclfhbaecufgembxdkkaeTmbindndnab8Vebgiabcdfgl8Uebgvabclfgo8Uebgrf9R:YJbFu9habcofgw8Vebgdce4adVgDcd4aDVgDcl4aDVgDcw4aDVgD:Z:vgqNJbbbZMgk:lJbbb9p9DTmbak:Ohxxekcjjjj94hxkaoax87ebdndnaraif:YaqNJbbbZMgk:lJbbb9p9DTmbak:Ohoxekcjjjj94hokalao87ebdndnavaifar9R:YaqNJbbbZMgk:lJbbb9p9DTmbak:Ohixekcjjjj94hikabai87ebdndnaDadcetGadceGV:ZaqNJbbbZMgq:lJbbb9p9DTmbaq:Ohdxekcjjjj94hdkawad87ebabcwfhbaecufgembkkk9teiucbcbyd:K:G:cjbgeabcifc98GfgbBd:K:G:cjbdndnabZbcztgd9nmbcuhiabad9RcFFifcz4nbcuSmekaehikaik;LeeeudndnaeabVciGTmbabhixekdndnadcz9pmbabhixekabhiinaiaeydbBdbaiclfaeclfydbBdbaicwfaecwfydbBdbaicxfaecxfydbBdbaeczfheaiczfhiadc9Wfgdcs0mbkkadcl6mbinaiaeydbBdbaeclfheaiclfhiadc98fgdci0mbkkdnadTmbinaiaeRbb86bbaicefhiaecefheadcufgdmbkkabk;aeedudndnabciGTmbabhixekaecFeGc:b:c:ew2hldndnadcz9pmbabhixekabhiinaialBdbaicxfalBdbaicwfalBdbaiclfalBdbaiczfhiadc9Wfgdcs0mbkkadcl6mbinaialBdbaiclfhiadc98fgdci0mbkkdnadTmbinaiae86bbaicefhiadcufgdmbkkabkk83dbcj:Gdk8Kbbbbdbbblbbbwbbbbbbbebbbdbbblbbbwbbbbc:K:Gdkl8W:qbb";
2585
+ var wasm_simd = "b9H79TebbbeKl9Gbb9Gvuuuuueu9Giuuub9Geueuixkbbebeeddddilve9Weeeviebeoweuecj:Gdkr;Neqo9TW9T9VV95dbH9F9F939H79T9F9J9H229F9Jt9VV7bb8A9TW79O9V9Wt9F9KW9J9V9KW9wWVtW949c919M9MWVbdY9TW79O9V9Wt9F9KW9J9V9KW69U9KW949c919M9MWVblE9TW79O9V9Wt9F9KW9J9V9KW69U9KW949tWG91W9U9JWbvL9TW79O9V9Wt9F9KW9J9V9KWS9P2tWV9p9JtboK9TW79O9V9Wt9F9KW9J9V9KWS9P2tWV9r919HtbrL9TW79O9V9Wt9F9KW9J9V9KWS9P2tWVT949WbwY9TW79O9V9Wt9F9KW9J9V9KWS9P2tWVJ9V29VVbDl79IV9Rbqq:I9Dklbzik94evu8Jjjjjbcz9Rhbcbheincbhdcbhiinabcwfadfaicjuaead4ceGglE86bbaialfhiadcefgdcw9hmbkaeai86b:q:W:cjbaecitab8Piw83i:q:G:cjbaecefgecjd9hmbkk:SBlEud97dur978Jjjjjbcj;kb9Rgv8Kjjjjbc9:hodnalTmbcuhoaiRbbgrc;WeGc:Ge9hmbarcsGgwce0mbc9:hoalcufadcd4cbawEgDadfgrcKcaawEgqaraq0Egk6mbaialfgxar9RhodnadTgmmbavaoad;8qbbkaicefhPcj;abad9Uc;WFbGcjdadca0EhsdndndnadTmbaoadfhzcbhHinaeaH9nmdaxaP9RaD6miabaHad2fgOavcjdfasaeaH9RaHasfae6EgAaAcsfgoc9WGgCSEhXaPaDfhQaocl4cifcd4hLavcj;cbfaCcetfhKavcj;cbfaCci2fhYavcj;cbfaCfh8AcbhEaoc;ab6h3incbh5dnawTmbaPaEcd4fRbbh5kcbh8Eavcj;cbfh8Findndndndna5a8Ecet4ciGgoc9:fPdebdkaxaQ9RaC6mwdnaCTmbavcj;cbfa8EaC2faQaC;8qbbkaQaAfhQxdkaCTmeavcj;cbfa8EaC2fcbaC;8kbxekaxaQ9RaL6moaoclVcbawEhraQaLfhocbhidna3mbaxao9Rc;Gb6mbcbhlina8FalfhidndndndndndnaQalco4fRbbgqciGarfPDbedibledibkaipxbbbbbbbbbbbbbbbbpklbxlkaiaopbblaopbbbgaclp:meaapmbzeHdOiAlCvXoQrLgacdp:meaapmbzeHdOiAlCvXoQrLpxiiiiiiiiiiiiiiiip9oghpxiiiiiiiiiiiiiiiip8Jgap5b9cjF;8;4;W;G;ab9:9cU1:Nggcitpbi:q:G:cjbagRb:q:W:cjbggpsaap5e9cjF;8;4;W;G;ab9:9cU1:Ng8Jcitpbi:q:G:cjbp9UpmbedilvorzHOACXQLpPahaap9spklbagaoclffa8JRb:q:W:cjbfhoxikaiaopbbwaopbbbgaclp:meaapmbzeHdOiAlCvXoQrLpxssssssssssssssssp9oghpxssssssssssssssssp8Jgap5b9cjF;8;4;W;G;ab9:9cU1:Nggcitpbi:q:G:cjbagRb:q:W:cjbggpsaap5e9cjF;8;4;W;G;ab9:9cU1:Ng8Jcitpbi:q:G:cjbp9UpmbedilvorzHOACXQLpPahaap9spklbagaocwffa8JRb:q:W:cjbfhoxdkaiaopbbbpklbaoczfhoxekaiaopbbdaoRbbggcitpbi:q:G:cjbagRb:q:W:cjbggpsaoRbeg8Jcitpbi:q:G:cjbp9UpmbedilvorzHOACXQLpPpklbagaocdffa8JRb:q:W:cjbfhokdndndndndndnaqcd4ciGarfPDbedibledibkaiczfpxbbbbbbbbbbbbbbbbpklbxlkaiczfaopbblaopbbbgaclp:meaapmbzeHdOiAlCvXoQrLgacdp:meaapmbzeHdOiAlCvXoQrLpxiiiiiiiiiiiiiiiip9oghpxiiiiiiiiiiiiiiiip8Jgap5b9cjF;8;4;W;G;ab9:9cU1:Nggcitpbi:q:G:cjbagRb:q:W:cjbggpsaap5e9cjF;8;4;W;G;ab9:9cU1:Ng8Jcitpbi:q:G:cjbp9UpmbedilvorzHOACXQLpPahaap9spklbagaoclffa8JRb:q:W:cjbfhoxikaiczfaopbbwaopbbbgaclp:meaapmbzeHdOiAlCvXoQrLpxssssssssssssssssp9oghpxssssssssssssssssp8Jgap5b9cjF;8;4;W;G;ab9:9cU1:Nggcitpbi:q:G:cjbagRb:q:W:cjbggpsaap5e9cjF;8;4;W;G;ab9:9cU1:Ng8Jcitpbi:q:G:cjbp9UpmbedilvorzHOACXQLpPahaap9spklbagaocwffa8JRb:q:W:cjbfhoxdkaiczfaopbbbpklbaoczfhoxekaiczfaopbbdaoRbbggcitpbi:q:G:cjbagRb:q:W:cjbggpsaoRbeg8Jcitpbi:q:G:cjbp9UpmbedilvorzHOACXQLpPpklbagaocdffa8JRb:q:W:cjbfhokdndndndndndnaqcl4ciGarfPDbedibledibkaicafpxbbbbbbbbbbbbbbbbpklbxlkaicafaopbblaopbbbgaclp:meaapmbzeHdOiAlCvXoQrLgacdp:meaapmbzeHdOiAlCvXoQrLpxiiiiiiiiiiiiiiiip9oghpxiiiiiiiiiiiiiiiip8Jgap5b9cjF;8;4;W;G;ab9:9cU1:Nggcitpbi:q:G:cjbagRb:q:W:cjbggpsaap5e9cjF;8;4;W;G;ab9:9cU1:Ng8Jcitpbi:q:G:cjbp9UpmbedilvorzHOACXQLpPahaap9spklbagaoclffa8JRb:q:W:cjbfhoxikaicafaopbbwaopbbbgaclp:meaapmbzeHdOiAlCvXoQrLpxssssssssssssssssp9oghpxssssssssssssssssp8Jgap5b9cjF;8;4;W;G;ab9:9cU1:Nggcitpbi:q:G:cjbagRb:q:W:cjbggpsaap5e9cjF;8;4;W;G;ab9:9cU1:Ng8Jcitpbi:q:G:cjbp9UpmbedilvorzHOACXQLpPahaap9spklbagaocwffa8JRb:q:W:cjbfhoxdkaicafaopbbbpklbaoczfhoxekaicafaopbbdaoRbbggcitpbi:q:G:cjbagRb:q:W:cjbggpsaoRbeg8Jcitpbi:q:G:cjbp9UpmbedilvorzHOACXQLpPpklbagaocdffa8JRb:q:W:cjbfhokdndndndndndnaqco4arfPDbedibledibkaic8Wfpxbbbbbbbbbbbbbbbbpklbxlkaic8Wfaopbblaopbbbgaclp:meaapmbzeHdOiAlCvXoQrLgacdp:meaapmbzeHdOiAlCvXoQrLpxiiiiiiiiiiiiiiiip9oghpxiiiiiiiiiiiiiiiip8Jgap5b9cjF;8;4;W;G;ab9:9cU1:Ngicitpbi:q:G:cjbaiRb:q:W:cjbgipsaap5e9cjF;8;4;W;G;ab9:9cU1:Ngqcitpbi:q:G:cjbp9UpmbedilvorzHOACXQLpPahaap9spklbaiaoclffaqRb:q:W:cjbfhoxikaic8Wfaopbbwaopbbbgaclp:meaapmbzeHdOiAlCvXoQrLpxssssssssssssssssp9oghpxssssssssssssssssp8Jgap5b9cjF;8;4;W;G;ab9:9cU1:Ngicitpbi:q:G:cjbaiRb:q:W:cjbgipsaap5e9cjF;8;4;W;G;ab9:9cU1:Ngqcitpbi:q:G:cjbp9UpmbedilvorzHOACXQLpPahaap9spklbaiaocwffaqRb:q:W:cjbfhoxdkaic8Wfaopbbbpklbaoczfhoxekaic8WfaopbbdaoRbbgicitpbi:q:G:cjbaiRb:q:W:cjbgipsaoRbegqcitpbi:q:G:cjbp9UpmbedilvorzHOACXQLpPpklbaiaocdffaqRb:q:W:cjbfhokalc;abfhialcjefaC0meaihlaxao9Rc;Fb0mbkkdnaiaC9pmbaici4hlinaxao9RcK6mwa8FaifhqdndndndndndnaQaico4fRbbalcoG4ciGarfPDbedibledibkaqpxbbbbbbbbbbbbbbbbpkbbxlkaqaopbblaopbbbgaclp:meaapmbzeHdOiAlCvXoQrLgacdp:meaapmbzeHdOiAlCvXoQrLpxiiiiiiiiiiiiiiiip9oghpxiiiiiiiiiiiiiiiip8Jgap5b9cjF;8;4;W;G;ab9:9cU1:Nggcitpbi:q:G:cjbagRb:q:W:cjbggpsaap5e9cjF;8;4;W;G;ab9:9cU1:Ng8Jcitpbi:q:G:cjbp9UpmbedilvorzHOACXQLpPahaap9spkbbagaoclffa8JRb:q:W:cjbfhoxikaqaopbbwaopbbbgaclp:meaapmbzeHdOiAlCvXoQrLpxssssssssssssssssp9oghpxssssssssssssssssp8Jgap5b9cjF;8;4;W;G;ab9:9cU1:Nggcitpbi:q:G:cjbagRb:q:W:cjbggpsaap5e9cjF;8;4;W;G;ab9:9cU1:Ng8Jcitpbi:q:G:cjbp9UpmbedilvorzHOACXQLpPahaap9spkbbagaocwffa8JRb:q:W:cjbfhoxdkaqaopbbbpkbbaoczfhoxekaqaopbbdaoRbbggcitpbi:q:G:cjbagRb:q:W:cjbggpsaoRbeg8Jcitpbi:q:G:cjbp9UpmbedilvorzHOACXQLpPpkbbagaocdffa8JRb:q:W:cjbfhokalcdfhlaiczfgiaC6mbkkaohQaoTmoka8FaCfh8Fa8Ecefg8Ecl9hmbkdndndndnawTmbazaEcd4fRbbglciGPlbedwbkaCTmdaXaEfhlavaEfpbdbh8Kcbhoinalavcj;cbfaofpblbg8La8Aaofpblbg8MpmbzeHdOiAlCvXoQrLg8NaKaofpblbgyaYaofpblbg8PpmbzeHdOiAlCvXoQrLgIpmbezHdiOAlvCXorQLgacep9Taapxeeeeeeeeeeeeeeeeghp9op9Hp9rgaa8Kp9Ug8Kp9Abbbaladfgla8Kaaaapmlvorlvorlvorlvorp9Ug8Kp9Abbbaladfgla8KaaaapmwDqkwDqkwDqkwDqkp9Ug8Kp9Abbbaladfgla8KaaaapmxmPsxmPsxmPsxmPsp9Ug8Kp9Abbbaladfgla8Ka8NaIpmwDKYqk8AExm35Ps8E8Fgacep9Taaahp9op9Hp9rgap9Ug8Kp9Abbbaladfgla8Kaaaapmlvorlvorlvorlvorp9Ug8Kp9Abbbaladfgla8KaaaapmwDqkwDqkwDqkwDqkp9Ug8Kp9Abbbaladfgla8KaaaapmxmPsxmPsxmPsxmPsp9Ug8Kp9Abbbaladfgla8Ka8La8MpmwKDYq8AkEx3m5P8Es8Fg8Laya8PpmwKDYq8AkEx3m5P8Es8Fg8MpmbezHdiOAlvCXorQLgacep9Taaahp9op9Hp9rgap9Ug8Kp9Abbbaladfgla8Kaaaapmlvorlvorlvorlvorp9Ug8Kp9Abbbaladfgla8KaaaapmwDqkwDqkwDqkwDqkp9Ug8Kp9Abbbaladfgla8KaaaapmxmPsxmPsxmPsxmPsp9Ug8Kp9Abbbaladfgla8Ka8La8MpmwDKYqk8AExm35Ps8E8Fgacep9Taaahp9op9Hp9rgap9Ughp9Abbbaladfglahaaaapmlvorlvorlvorlvorp9Ughp9AbbbaladfglahaaaapmwDqkwDqkwDqkwDqkp9Ughp9AbbbaladfglahaaaapmxmPsxmPsxmPsxmPsp9Ug8Kp9AbbbaladfhlaoczfgoaC6mbxikkaCTmeaXaEfhlavaEfpbdbh8Kcbhoinalavcj;cbfaofpblbg8La8Aaofpblbg8MpmbzeHdOiAlCvXoQrLg8NaKaofpblbgyaYaofpblbg8PpmbzeHdOiAlCvXoQrLgIpmbezHdiOAlvCXorQLgacep:neaapxebebebebebebebebghp9op:bep9rgaa8Kp:oeg8Kp9Abbbaladfgla8Kaaaapmlvorlvorlvorlvorp:oeg8Kp9Abbbaladfgla8KaaaapmwDqkwDqkwDqkwDqkp:oeg8Kp9Abbbaladfgla8KaaaapmxmPsxmPsxmPsxmPsp:oeg8Kp9Abbbaladfgla8Ka8NaIpmwDKYqk8AExm35Ps8E8Fgacep:neaaahp9op:bep9rgap:oeg8Kp9Abbbaladfgla8Kaaaapmlvorlvorlvorlvorp:oeg8Kp9Abbbaladfgla8KaaaapmwDqkwDqkwDqkwDqkp:oeg8Kp9Abbbaladfgla8KaaaapmxmPsxmPsxmPsxmPsp:oeg8Kp9Abbbaladfgla8Ka8La8MpmwKDYq8AkEx3m5P8Es8Fg8Laya8PpmwKDYq8AkEx3m5P8Es8Fg8MpmbezHdiOAlvCXorQLgacep:neaaahp9op:bep9rgap:oeg8Kp9Abbbaladfgla8Kaaaapmlvorlvorlvorlvorp:oeg8Kp9Abbbaladfgla8KaaaapmwDqkwDqkwDqkwDqkp:oeg8Kp9Abbbaladfgla8KaaaapmxmPsxmPsxmPsxmPsp:oeg8Kp9Abbbaladfgla8Ka8La8MpmwDKYqk8AExm35Ps8E8Fgacep:neaaahp9op:bep9rgap:oeghp9Abbbaladfglahaaaapmlvorlvorlvorlvorp:oeghp9AbbbaladfglahaaaapmwDqkwDqkwDqkwDqkp:oeghp9AbbbaladfglahaaaapmxmPsxmPsxmPsxmPsp:oeg8Kp9AbbbaladfhlaoczfgoaC6mbxdkkaCTmbaXaEfhrcbhocbalcl4gl9Rc8FGhiavaEfpbdbhhinaravcj;cbfaofpblbg8Ka8Aaofpblbg8LpmbzeHdOiAlCvXoQrLg8MaKaofpblbg8NaYaofpblbgypmbzeHdOiAlCvXoQrLg8PpmbezHdiOAlvCXorQLgaaip:Reaaalp:Tep9qgaahp9rghp9Abbbaradfgrahaaaapmlvorlvorlvorlvorp9rghp9AbbbaradfgrahaaaapmwDqkwDqkwDqkwDqkp9rghp9AbbbaradfgrahaaaapmxmPsxmPsxmPsxmPsp9rghp9Abbbaradfgraha8Ma8PpmwDKYqk8AExm35Ps8E8Fgaaip:Reaaalp:Tep9qgap9rghp9Abbbaradfgrahaaaapmlvorlvorlvorlvorp9rghp9AbbbaradfgrahaaaapmwDqkwDqkwDqkwDqkp9rghp9AbbbaradfgrahaaaapmxmPsxmPsxmPsxmPsp9rghp9Abbbaradfgraha8Ka8LpmwKDYq8AkEx3m5P8Es8Fg8Ka8NaypmwKDYq8AkEx3m5P8Es8Fg8LpmbezHdiOAlvCXorQLgaaip:Reaaalp:Tep9qgap9rghp9Abbbaradfgrahaaaapmlvorlvorlvorlvorp9rghp9AbbbaradfgrahaaaapmwDqkwDqkwDqkwDqkp9rghp9AbbbaradfgrahaaaapmxmPsxmPsxmPsxmPsp9rghp9Abbbaradfgraha8Ka8LpmwDKYqk8AExm35Ps8E8Fgaaip:Reaaalp:Tep9qgap9rghp9Abbbaradfgrahaaaapmlvorlvorlvorlvorp9rghp9AbbbaradfgrahaaaapmwDqkwDqkwDqkwDqkp9rghp9AbbbaradfgrahaaaapmxmPsxmPsxmPsxmPsp9rghp9AbbbaradfhraoczfgoaC6mbkkaEclfgEad6mbkdnaXavcjdf9hmbaAad2goTmbaOavcjdfao;8qbbkdnammbavaXaAcufad2fad;8qbbkaAaHfhHc9:hoaQhPaQmbxlkkaeTmbaDalfhrcbhocuhlinaralaD9RglfaD6mdasaeao9Raoasfae6Eaofgoae6mbkaial9RhPkcbc99axaP9RakSEhoxekc9:hokavcj;kbf8Kjjjjbaokwbz:bjjjbkpPesu8Jjjjjbc;ae9Rgv8Kjjjjbc9:hodnalaeci9UgrcHf6mbcuhoaiRbbgwc;WeGc;Ge9hmbawcsGgwce0mbavc;abfcFecje;8kbav9cu83iUav9cu83i8Wav9cu83iyav9cu83iaav9cu83iKav9cu83izav9cu83iwav9cu83ibaialfc9WfhDaicefgiarfhqdndnaeci9pmbaqhexekcmcsawceSEhkcbhxcbhmaqhecbhlcbhoindndnaiRbbgrc;Ve0mbavc;abfaoarcu7gPcl4fcsGcitfgwydlhsawydbhzdndnarcsGgwak9pmbavalaPfcsGcdtfydbaxawEhraxawTgHfhxxekdnaeaD9nmbc9:hoxokdndnawcsSmbcehHamawcetfcWfhrxekaecefhrae8SbbgwcFeGhPdndnawcu9mmbarhexekaecvfheaPcFbGhPcrhwdninar8SbbgHcFbGawtaPVhPaHcu9kmearcefhrawcrfgwc8J9hmbxdkkarcefhekcehHaPce4cbaPceG9R7amfhrkarhmkavc;abfaocitfgwarBdbawasBdlavalcdtfarBdbavc;abfaocefcsGcitfgwazBdbawarBdlaocdfhoaHalfhldnadcd9hmbabar87elabas87edabaz87ebabcofhbxdkabarBdwabasBdlabazBdbabcxfhbxekdnarcpe0mbavalaDarcsGfRbbgwcl4gP9RcsGcdtfydbaxcefgsaPEhravalaw9RcsGcdtfydbasaPTgzfgsawcsGgPEhwaPThPdndnadcd9hmbabaw87elabar87edabax87ebcohHxekabawBdwabarBdlabaxBdbcxhHkavalcdtfaxBdbavc;abfaocitfgOarBdbaOaxBdlavalcefglcsGcdtfarBdbavc;abfaocefcsGcitfgOawBdbaOarBdlavalazfglcsGcdtfawBdbavc;abfaocdfcsGcitfgraxBdbarawBdlaocifhoabaHfhbalaPfhlasaPfhxxekdnaeaD9nmbc9:hoxlkaxcbaeRbbgwEgHarc;:eSgrfhsawcsGhOdndnawcl4gAmbascefhzxekashzavalaA9RcsGcdtfydbhskdndnaOmbazcefhxxekazhxavalaw9RcsGcdtfydbhzkdndnarTmbaecefhrxekaecdfhrae8SbegPcFeGhwdnaPcu9kmbaecofhHawcFbGhwcrhedninar8SbbgPcFbGaetawVhwaPcu9kmearcefhraecrfgec8J9hmbkaHhrxekarcefhrkawce4cbawceG9R7amfgmhHkdndnaAcsSmbarhwxekarcefhwar8SbbgecFeGhPdnaecu9kmbarcvfhsaPcFbGhPcrhedninaw8SbbgrcFbGaetaPVhParcu9kmeawcefhwaecrfgec8J9hmbkashwxekawcefhwkaPce4cbaPceG9R7amfgmhskdndnaOcsSmbawhexekawcefheaw8SbbgrcFeGhPdnarcu9kmbawcvfhzaPcFbGhPcrhrdninae8SbbgwcFbGartaPVhPawcu9kmeaecefhearcrfgrc8J9hmbkazhexekaecefhekaPce4cbaPceG9R7amfgmhzkdndnadcd9hmbabaz87elabas87edabaH87ebcohrxekabazBdwabasBdlabaHBdbcxhrkavc;abfaocitfgwasBdbawaHBdlavalcdtfaHBdbavc;abfaocefcsGcitfgwazBdbawasBdlavalcefglcsGcdtfasBdbavc;abfaocdfcsGcitfgwaHBdbawazBdlavalaATaAcsSVfglcsGcdtfazBdbalaOTaOcsSVfhlaocifhoabarfhbkaocsGhoalcsGhlaicefgiaq6mbkkcbc99aeaDSEhokavc;aef8Kjjjjbaok:clevu8Jjjjjbcz9Rhvdnalaecvf9pmbc9:skdnaiRbbc;:eGc;qeSmbcuskav9cb83iwaicefhoaialfc98fhrdnaeTmbdnadcdSmbcbhwindnaoar6mbc9:skaocefhlao8SbbgicFeGhddndnaicu9mmbalhoxekaocvfhoadcFbGhdcrhidninal8SbbgDcFbGaitadVhdaDcu9kmealcefhlaicrfgic8J9hmbxdkkalcefhokabawcdtfadc8Etc8F91adcd47avcwfadceGcdtVglydbfgiBdbalaiBdbawcefgwae9hmbxdkkcbhwindnaoar6mbc9:skaocefhlao8SbbgicFeGhddndnaicu9mmbalhoxekaocvfhoadcFbGhdcrhidninal8SbbgDcFbGaitadVhdaDcu9kmealcefhlaicrfgic8J9hmbxdkkalcefhokabawcetfadc8Etc8F91adcd47avcwfadceGcdtVglydbfgi87ebalaiBdbawcefgwae9hmbkkcbc99aoarSEk;Toio97eue97aec98Ghedndnadcl9hmbaeTmecbhdinababpbbbgicKp:RecKp:Sep;6eglaicwp:RecKp:Sep;6ealp;Geaiczp:RecKp:Sep;6egvp;Gep;Kep;Legopxbbbbbbbbbbbbbbbbp:2egralpxbbbjbbbjbbbjbbbjgwp9op9rp;Keglpxbb;:9cbb;:9cbb;:9cbb;:9calalp;Meaoaop;Meavaravawp9op9rp;Keglalp;Mep;Kep;Kep;Jep;Negvp;Mepxbbn0bbn0bbn0bbn0grp;KepxFbbbFbbbFbbbFbbbp9oaipxbbbFbbbFbbbFbbbFp9op9qalavp;Mearp;Kecwp:RepxbFbbbFbbbFbbbFbbp9op9qaoavp;Mearp;Keczp:RepxbbFbbbFbbbFbbbFbp9op9qpkbbabczfhbadclfgdae6mbxdkkaeTmbcbhdinabczfgDaDpbbbgipxbbbbbbFFbbbbbbFFgwp9oabpbbbgoaipmbediwDqkzHOAKY8AEgvczp:Reczp:Sep;6eglaoaipmlvorxmPsCXQL358E8FpxFubbFubbFubbFubbp9op;6eavczp:Sep;6egvp;Gealp;Gep;Kep;Legipxbbbbbbbbbbbbbbbbp:2egralpxbbbjbbbjbbbjbbbjgqp9op9rp;Keglpxb;:FSb;:FSb;:FSb;:FSalalp;Meaiaip;Meavaravaqp9op9rp;Keglalp;Mep;Kep;Kep;Jep;Negvp;Mepxbbn0bbn0bbn0bbn0grp;KepxFFbbFFbbFFbbFFbbp9oaiavp;Mearp;Keczp:Rep9qgialavp;Mearp;KepxFFbbFFbbFFbbFFbbp9oglpmwDKYqk8AExm35Ps8E8Fp9qpkbbabaoawp9oaialpmbezHdiOAlvCXorQLp9qpkbbabcafhbadclfgdae6mbkkk;2ileue97euo97dnaec98GgiTmbcbheinabcKfpx:ji:1S:ji:1S:ji:1S:ji:1SabpbbbglabczfgvpbbbgopmlvorxmPsCXQL358E8Fgrczp:Segwpxibbbibbbibbbibbbp9qp;6egDp;NegqaDaDp;MegDaDp;KealaopmbediwDqkzHOAKY8AEgDczp:Reczp:Sep;6eglalp;MeaDczp:Sep;6egoaop;Mearczp:Reczp:Sep;6egrarp;Mep;Kep;Kep;Lepxbbbbbbbbbbbbbbbbp:4ep;Jep;Mepxbbn0bbn0bbn0bbn0gDp;KepxFFbbFFbbFFbbFFbbgkp9oaqaop;MeaDp;Keczp:Rep9qgoaqalp;MeaDp;Keakp9oaqarp;MeaDp;Keczp:Rep9qgDpmwDKYqk8AExm35Ps8E8Fglp5eawclp:RegqpEi:T:j83ibavalp5baqpEd:T:j83ibabcwfaoaDpmbezHdiOAlvCXorQLgDp5eaqpEe:T:j83ibabaDp5baqpEb:T:j83ibabcafhbaeclfgeai6mbkkkuee97dnadcd4ae2c98GgeTmbcbhdinababpbbbgicwp:Recwp:Sep;6eaicep:SepxbbjFbbjFbbjFbbjFp9opxbbjZbbjZbbjZbbjZp:Uep;Mepkbbabczfhbadclfgdae6mbkkk:Sodw97euaec98Ghedndnadcl9hmbaeTmecbhdinabpxbbuJbbuJbbuJbbuJabpbbbgicKp:TeglaicYp:Tep9qgvcdp:Teavp9qgvclp:Teavp9qgop;6ep;Negvaicwp:RecKp:SegraipxFbbbFbbbFbbbFbbbgwp9ogDp:Uep;6ep;Mepxbbn0bbn0bbn0bbn0gqp;Kecwp:RepxbFbbbFbbbFbbbFbbp9oavaDarp:Xeaiczp:RecKp:Segip:Uep;6ep;Meaqp;Keawp9op9qavaDaraip:Uep:Xep;6ep;Meaqp;Keczp:RepxbbFbbbFbbbFbbbFbp9op9qavaoalcep:Rep9oalpxebbbebbbebbbebbbp9op9qp;6ep;Meaqp;KecKp:Rep9qpkbbabczfhbadclfgdae6mbxdkkaeTmbcbhdinabczfgkpxbFu9hbFu9hbFu9hbFu9habpbbbglakpbbbgrpmlvorxmPsCXQL358E8Fgvczp:TegqavcHp:Tep9qgicdp:Teaip9qgiclp:Teaip9qgicwp:Teaip9qgop;6ep;NegialarpmbediwDqkzHOAKY8AEgDpxFFbbFFbbFFbbFFbbglp9ograDczp:Segwp:Ueavczp:Reczp:SegDp:Xep;6ep;Mepxbbn0bbn0bbn0bbn0gvp;Kealp9oaiarawaDp:Uep:Xep;6ep;Meavp;Keczp:Rep9qgwaiaoaqcep:Rep9oaqpxebbbebbbebbbebbbp9op9qp;6ep;Meavp;Keczp:ReaiaDarp:Uep;6ep;Meavp;Kealp9op9qgipmwDKYqk8AExm35Ps8E8FpkbbabawaipmbezHdiOAlvCXorQLpkbbabcafhbadclfgdae6mbkkk9teiucbcbydj:G:cjbgeabcifc98GfgbBdj:G:cjbdndnabZbcztgd9nmbcuhiabad9RcFFifcz4nbcuSmekaehikaikkxebcj:Gdklz:zbb";
2586
+ var detector = new Uint8Array([
2587
+ 0,
2588
+ 97,
2589
+ 115,
2590
+ 109,
2591
+ 1,
2592
+ 0,
2593
+ 0,
2594
+ 0,
2595
+ 1,
2596
+ 4,
2597
+ 1,
2598
+ 96,
2599
+ 0,
2600
+ 0,
2601
+ 3,
2602
+ 3,
2603
+ 2,
2604
+ 0,
2605
+ 0,
2606
+ 5,
2607
+ 3,
2608
+ 1,
2609
+ 0,
2610
+ 1,
2611
+ 12,
2612
+ 1,
2613
+ 0,
2614
+ 10,
2615
+ 22,
2616
+ 2,
2617
+ 12,
2618
+ 0,
2619
+ 65,
2620
+ 0,
2621
+ 65,
2622
+ 0,
2623
+ 65,
2624
+ 0,
2625
+ 252,
2626
+ 10,
2627
+ 0,
2628
+ 0,
2629
+ 11,
2630
+ 7,
2631
+ 0,
2632
+ 65,
2633
+ 0,
2634
+ 253,
2635
+ 15,
2636
+ 26,
2637
+ 11
2638
+ ]);
2639
+ var wasmpack = new Uint8Array([
2640
+ 32,
2641
+ 0,
2642
+ 65,
2643
+ 2,
2644
+ 1,
2645
+ 106,
2646
+ 34,
2647
+ 33,
2648
+ 3,
2649
+ 128,
2650
+ 11,
2651
+ 4,
2652
+ 13,
2653
+ 64,
2654
+ 6,
2655
+ 253,
2656
+ 10,
2657
+ 7,
2658
+ 15,
2659
+ 116,
2660
+ 127,
2661
+ 5,
2662
+ 8,
2663
+ 12,
2664
+ 40,
2665
+ 16,
2666
+ 19,
2667
+ 54,
2668
+ 20,
2669
+ 9,
2670
+ 27,
2671
+ 255,
2672
+ 113,
2673
+ 17,
2674
+ 42,
2675
+ 67,
2676
+ 24,
2677
+ 23,
2678
+ 146,
2679
+ 148,
2680
+ 18,
2681
+ 14,
2682
+ 22,
2683
+ 45,
2684
+ 70,
2685
+ 69,
2686
+ 56,
2687
+ 114,
2688
+ 101,
2689
+ 21,
2690
+ 25,
2691
+ 63,
2692
+ 75,
2693
+ 136,
2694
+ 108,
2695
+ 28,
2696
+ 118,
2697
+ 29,
2698
+ 73,
2699
+ 115
2700
+ ]);
2701
+ if (typeof WebAssembly !== "object") {
2702
+ return {
2703
+ supported: false
2704
+ };
2705
+ }
2706
+ var wasm = WebAssembly.validate(detector) ? unpack(wasm_simd) : unpack(wasm_base);
2707
+ var instance;
2708
+ var ready = WebAssembly.instantiate(wasm, {}).then(function(result) {
2709
+ instance = result.instance;
2710
+ instance.exports.__wasm_call_ctors();
2711
+ });
2712
+ function unpack(data) {
2713
+ var result = new Uint8Array(data.length);
2714
+ for (var i = 0; i < data.length; ++i) {
2715
+ var ch = data.charCodeAt(i);
2716
+ result[i] = ch > 96 ? ch - 97 : ch > 64 ? ch - 39 : ch + 4;
2717
+ }
2718
+ var write = 0;
2719
+ for (var i = 0; i < data.length; ++i) {
2720
+ result[write++] = result[i] < 60 ? wasmpack[result[i]] : (result[i] - 60) * 64 + result[++i];
2721
+ }
2722
+ return result.buffer.slice(0, write);
2723
+ }
2724
+ function decode(instance2, fun, target, count, size, source, filter) {
2725
+ var sbrk = instance2.exports.sbrk;
2726
+ var count4 = count + 3 & ~3;
2727
+ var tp = sbrk(count4 * size);
2728
+ var sp = sbrk(source.length);
2729
+ var heap = new Uint8Array(instance2.exports.memory.buffer);
2730
+ heap.set(source, sp);
2731
+ var res = fun(tp, count, size, sp, source.length);
2732
+ if (res == 0 && filter) {
2733
+ filter(tp, count4, size);
2734
+ }
2735
+ target.set(heap.subarray(tp, tp + count * size));
2736
+ sbrk(tp - sbrk(0));
2737
+ if (res != 0) {
2738
+ throw new Error("Malformed buffer data: " + res);
2739
+ }
2740
+ }
2741
+ var filters = {
2742
+ NONE: "",
2743
+ OCTAHEDRAL: "meshopt_decodeFilterOct",
2744
+ QUATERNION: "meshopt_decodeFilterQuat",
2745
+ EXPONENTIAL: "meshopt_decodeFilterExp",
2746
+ COLOR: "meshopt_decodeFilterColor"
2747
+ };
2748
+ var decoders = {
2749
+ ATTRIBUTES: "meshopt_decodeVertexBuffer",
2750
+ TRIANGLES: "meshopt_decodeIndexBuffer",
2751
+ INDICES: "meshopt_decodeIndexSequence"
2752
+ };
2753
+ var workers = [];
2754
+ var requestId = 0;
2755
+ function createWorker(url) {
2756
+ var worker = {
2757
+ object: new Worker(url),
2758
+ pending: 0,
2759
+ requests: {}
2760
+ };
2761
+ worker.object.onmessage = function(event) {
2762
+ var data = event.data;
2763
+ worker.pending -= data.count;
2764
+ worker.requests[data.id][data.action](data.value);
2765
+ delete worker.requests[data.id];
2766
+ };
2767
+ return worker;
2768
+ }
2769
+ function initWorkers(count) {
2770
+ var source = "self.ready = WebAssembly.instantiate(new Uint8Array([" + new Uint8Array(wasm) + "]), {}).then(function(result) { result.instance.exports.__wasm_call_ctors(); return result.instance; });self.onmessage = " + workerProcess.name + ";" + decode.toString() + workerProcess.toString();
2771
+ var blob = new Blob([source], { type: "text/javascript" });
2772
+ var url = URL.createObjectURL(blob);
2773
+ for (var i = workers.length; i < count; ++i) {
2774
+ workers[i] = createWorker(url);
2775
+ }
2776
+ for (var i = count; i < workers.length; ++i) {
2777
+ workers[i].object.postMessage({});
2778
+ }
2779
+ workers.length = count;
2780
+ URL.revokeObjectURL(url);
2781
+ }
2782
+ function decodeWorker(count, size, source, mode, filter) {
2783
+ var worker = workers[0];
2784
+ for (var i = 1; i < workers.length; ++i) {
2785
+ if (workers[i].pending < worker.pending) {
2786
+ worker = workers[i];
2787
+ }
2788
+ }
2789
+ return new Promise(function(resolve, reject) {
2790
+ var data = new Uint8Array(source);
2791
+ var id2 = ++requestId;
2792
+ worker.pending += count;
2793
+ worker.requests[id2] = { resolve, reject };
2794
+ worker.object.postMessage({ id: id2, count, size, source: data, mode, filter }, [data.buffer]);
2795
+ });
2796
+ }
2797
+ function workerProcess(event) {
2798
+ var data = event.data;
2799
+ self.ready.then(function(instance2) {
2800
+ if (!data.id) {
2801
+ return self.close();
2802
+ }
2803
+ try {
2804
+ var target = new Uint8Array(data.count * data.size);
2805
+ decode(instance2, instance2.exports[data.mode], target, data.count, data.size, data.source, instance2.exports[data.filter]);
2806
+ self.postMessage({ id: data.id, count: data.count, action: "resolve", value: target }, [target.buffer]);
2807
+ } catch (error) {
2808
+ self.postMessage({ id: data.id, count: data.count, action: "reject", value: error });
2809
+ }
2810
+ });
2811
+ }
2812
+ return {
2813
+ ready,
2814
+ supported: true,
2815
+ useWorkers: function(count) {
2816
+ initWorkers(count);
2817
+ },
2818
+ decodeVertexBuffer: function(target, count, size, source, filter) {
2819
+ decode(instance, instance.exports.meshopt_decodeVertexBuffer, target, count, size, source, instance.exports[filters[filter]]);
2820
+ },
2821
+ decodeIndexBuffer: function(target, count, size, source) {
2822
+ decode(instance, instance.exports.meshopt_decodeIndexBuffer, target, count, size, source);
2823
+ },
2824
+ decodeIndexSequence: function(target, count, size, source) {
2825
+ decode(instance, instance.exports.meshopt_decodeIndexSequence, target, count, size, source);
2826
+ },
2827
+ decodeGltfBuffer: function(target, count, size, source, mode, filter) {
2828
+ decode(instance, instance.exports[decoders[mode]], target, count, size, source, instance.exports[filters[filter]]);
2829
+ },
2830
+ decodeGltfBufferAsync: function(count, size, source, mode, filter) {
2831
+ if (workers.length > 0) {
2832
+ return decodeWorker(count, size, source, decoders[mode], filters[filter]);
2833
+ }
2834
+ return ready.then(function() {
2835
+ var target = new Uint8Array(count * size);
2836
+ decode(instance, instance.exports[decoders[mode]], target, count, size, source, instance.exports[filters[filter]]);
2837
+ return target;
2838
+ });
2839
+ }
2840
+ };
2841
+ })();
2842
+ }
2843
+ });
2844
+
2467
2845
  // src/capture-scene.ts
2468
2846
  init_portable_identity();
2469
2847
  import { z as z3 } from "zod";
@@ -2984,6 +3362,192 @@ function compileTileflowSky(options) {
2984
3362
  };
2985
3363
  }
2986
3364
 
3365
+ // src/models-3d-model.ts
3366
+ var tileflowModelParts = Object.freeze({
3367
+ surface: 0,
3368
+ secondary: 1,
3369
+ glass: 2,
3370
+ accent: 3,
3371
+ roof: 4
3372
+ });
3373
+ var tileflowModelLimits = Object.freeze({
3374
+ /** Levels of detail, nearest first. */
3375
+ levels: 3,
3376
+ /** Vertices of one level. */
3377
+ vertices: 2e5,
3378
+ /** Triangles of one level. */
3379
+ triangles: 2e5,
3380
+ /** Points of the footprint's rings, together. */
3381
+ footprintPoints: 4096,
3382
+ /** Half the model's widest extent, in metres. */
3383
+ radius: 2e3,
3384
+ /** The model's height, in metres. */
3385
+ height: 1e3,
3386
+ /** Models in one prepared file, as a landmark tile holds them. */
3387
+ models: 512,
3388
+ /** Bytes of one prepared file. */
3389
+ bytes: 16 * 1024 * 1024
3390
+ });
3391
+ var tileflowModelVertexBytes = 16;
3392
+ function tileflowInsideRings(rings, px, py) {
3393
+ for (const ring of rings) {
3394
+ let inside = false;
3395
+ for (let a = 0, b = ring.length - 2; a < ring.length; b = a, a += 2) {
3396
+ const ax = ring[a];
3397
+ const ay = ring[a + 1];
3398
+ const bx = ring[b];
3399
+ const by = ring[b + 1];
3400
+ if (ay > py !== by > py && px < (bx - ax) * (py - ay) / (by - ay) + ax) inside = !inside;
3401
+ }
3402
+ if (inside) return true;
3403
+ }
3404
+ return false;
3405
+ }
3406
+ function tileflowRingsOverlap(outline, footprints, margin) {
3407
+ for (const footprint of footprints) {
3408
+ const [fl, ft, fr, fb] = boxOf(footprint);
3409
+ for (const ring of outline) {
3410
+ const [left, top, right, bottom] = boxOf(ring);
3411
+ if (left > fr - margin || right < fl + margin || top > fb - margin || bottom < ft + margin)
3412
+ continue;
3413
+ if (reachesInto(ring, footprint, margin) || reachesInto(footprint, ring, margin)) return true;
3414
+ }
3415
+ }
3416
+ return false;
3417
+ }
3418
+ function reachesInto(ring, into, margin) {
3419
+ const deep = (x, y) => tileflowInsideRings([into], x, y) && distanceToRing(into, x, y) > margin;
3420
+ for (let a = 0; a + 1 < ring.length; a += 2) if (deep(ring[a], ring[a + 1])) return true;
3421
+ for (let a = 0, b = ring.length - 2; a < ring.length; b = a, a += 2) {
3422
+ const [ax, ay, bx, by] = [ring[b], ring[b + 1], ring[a], ring[a + 1]];
3423
+ const cuts = [0, 1];
3424
+ for (let c = 0, d = into.length - 2; c < into.length; d = c, c += 2) {
3425
+ const t = crossingOf(ax, ay, bx, by, into[d], into[d + 1], into[c], into[c + 1]);
3426
+ if (t !== void 0) cuts.push(t);
3427
+ }
3428
+ if (cuts.length === 2) continue;
3429
+ cuts.sort((p, q) => p - q);
3430
+ for (let at = 1; at < cuts.length; at += 1) {
3431
+ const t = (cuts[at - 1] + cuts[at]) / 2;
3432
+ if (deep(ax + (bx - ax) * t, ay + (by - ay) * t)) return true;
3433
+ }
3434
+ }
3435
+ return false;
3436
+ }
3437
+ function crossingOf(ax, ay, bx, by, cx, cy, dx, dy) {
3438
+ const rx = bx - ax;
3439
+ const ry = by - ay;
3440
+ const sx = dx - cx;
3441
+ const sy = dy - cy;
3442
+ const denominator = rx * sy - ry * sx;
3443
+ if (denominator === 0) return void 0;
3444
+ const t = ((cx - ax) * sy - (cy - ay) * sx) / denominator;
3445
+ const u = ((cx - ax) * ry - (cy - ay) * rx) / denominator;
3446
+ return t > 0 && t < 1 && u >= 0 && u <= 1 ? t : void 0;
3447
+ }
3448
+ function distanceToRing(ring, px, py) {
3449
+ let nearest = Infinity;
3450
+ for (let a = 0, b = ring.length - 2; a < ring.length; b = a, a += 2) {
3451
+ const [ax, ay, bx, by] = [ring[b], ring[b + 1], ring[a], ring[a + 1]];
3452
+ const length = (bx - ax) ** 2 + (by - ay) ** 2;
3453
+ const t = length > 0 ? Math.max(0, Math.min(1, ((px - ax) * (bx - ax) + (py - ay) * (by - ay)) / length)) : 0;
3454
+ nearest = Math.min(nearest, Math.hypot(px - (ax + (bx - ax) * t), py - (ay + (by - ay) * t)));
3455
+ }
3456
+ return nearest;
3457
+ }
3458
+ function boxOf(ring) {
3459
+ let [left, top, right, bottom] = [Infinity, Infinity, -Infinity, -Infinity];
3460
+ for (let at = 0; at + 1 < ring.length; at += 2) {
3461
+ left = Math.min(left, ring[at]);
3462
+ right = Math.max(right, ring[at]);
3463
+ top = Math.min(top, ring[at + 1]);
3464
+ bottom = Math.max(bottom, ring[at + 1]);
3465
+ }
3466
+ return [left, top, right, bottom];
3467
+ }
3468
+
3469
+ // src/buildings-3d-design.ts
3470
+ var tileflowBuildingsMetadataKey = "tileflow:buildings";
3471
+ var tileflowDefaultBuildings3DDesign = Object.freeze({
3472
+ source: "tileflow",
3473
+ layers: Object.freeze({ building: "building", places: "poi" }),
3474
+ color: "#d8d0c0",
3475
+ edges: 0,
3476
+ lighting: "style",
3477
+ colorVariation: 0,
3478
+ verticalGradient: true,
3479
+ nightLight: 0,
3480
+ windows: false,
3481
+ shadows: false,
3482
+ occlusion: false
3483
+ });
3484
+ function tileflowBuildingsMetadata(design) {
3485
+ return { version: 1, ...design };
3486
+ }
3487
+ function readTileflowBuildings3D(metadata) {
3488
+ if (!isRecord(metadata)) return void 0;
3489
+ const value = metadata[tileflowBuildingsMetadataKey];
3490
+ if (!isRecord(value) || value.version !== 1) return void 0;
3491
+ const { source, layers, color: color3 } = value;
3492
+ if (typeof source !== "string" || !isRecord(layers) || typeof layers.building !== "string")
3493
+ return void 0;
3494
+ if (typeof color3 !== "string" && !Array.isArray(color3)) return void 0;
3495
+ const within = (number, high, fallback) => typeof number === "number" && number >= 0 && number <= high ? number : fallback;
3496
+ return {
3497
+ source,
3498
+ layers: {
3499
+ building: layers.building,
3500
+ ...typeof layers.places === "string" ? { places: layers.places } : {}
3501
+ },
3502
+ color: color3,
3503
+ edges: within(value.edges, 1, 0),
3504
+ lighting: value.lighting === "sun" ? "sun" : "style",
3505
+ colorVariation: within(value.colorVariation, 1, 0),
3506
+ verticalGradient: value.verticalGradient !== false,
3507
+ ...typeof value.edgeColor === "string" ? { edgeColor: value.edgeColor } : {},
3508
+ nightLight: within(value.nightLight, 2, 0),
3509
+ windows: value.windows === true,
3510
+ shadows: value.shadows === true,
3511
+ occlusion: value.occlusion === true,
3512
+ ...modelsOf(value.models),
3513
+ ...modelColorsOf(value.modelColors),
3514
+ ...landmarksOf(value.landmarks)
3515
+ };
3516
+ }
3517
+ var modelId = /^[a-z0-9]+(?:-[a-z0-9]+)*$/u;
3518
+ var tileflowBuildingModelPlacementLimit = 256;
3519
+ function modelsOf(value) {
3520
+ if (!Array.isArray(value)) return {};
3521
+ const models = [];
3522
+ for (const entry of value.slice(0, tileflowBuildingModelPlacementLimit)) {
3523
+ if (!isRecord(entry)) continue;
3524
+ const { model, url, at, heading } = entry;
3525
+ if (typeof model !== "string" || !modelId.test(model) || typeof url !== "string" || !url)
3526
+ continue;
3527
+ if (!Array.isArray(at) || at.length !== 2) continue;
3528
+ const [longitude, latitude] = at;
3529
+ if (typeof longitude !== "number" || typeof latitude !== "number" || !(longitude >= -180 && longitude <= 180) || !(latitude >= -85 && latitude <= 85))
3530
+ continue;
3531
+ const turn = typeof heading === "number" && Number.isFinite(heading) ? heading : 0;
3532
+ models.push({ model, url, at: [longitude, latitude], heading: (turn % 360 + 360) % 360 });
3533
+ }
3534
+ return models.length > 0 ? { models } : {};
3535
+ }
3536
+ function modelColorsOf(value) {
3537
+ if (!isRecord(value)) return {};
3538
+ const colors = {};
3539
+ for (const part of Object.keys(tileflowModelParts))
3540
+ if (typeof value[part] === "string") colors[part] = value[part];
3541
+ return Object.keys(colors).length > 0 ? { modelColors: colors } : {};
3542
+ }
3543
+ function landmarksOf(value) {
3544
+ if (!isRecord(value) || typeof value.url !== "string" || !value.url) return {};
3545
+ return { landmarks: { url: value.url } };
3546
+ }
3547
+ function isRecord(value) {
3548
+ return typeof value === "object" && value !== null && !Array.isArray(value);
3549
+ }
3550
+
2987
3551
  // src/data/world-generation.ts
2988
3552
  var tileflowWorldGeneration = "v1";
2989
3553
  var tileflowWorldTileJsonUrl = "https://api.tileflow.dev/tiles/world/tiles.json";
@@ -3075,6 +3639,7 @@ var canonicalFields = {
3075
3639
  markings: "markings",
3076
3640
  minHeight: "min_height",
3077
3641
  minZoom: "min_zoom",
3642
+ mode: "mode",
3078
3643
  mtbScale: "mtb_scale",
3079
3644
  name: "name",
3080
3645
  nameEnglish: "name:en",
@@ -3872,7 +4437,16 @@ var tileflowBathymetrySourceId = "tileflow-bathymetry";
3872
4437
  var tileflowBathymetryDemSourceId = "tileflow-bathymetry-dem";
3873
4438
  var tileflowNauticalSourceId = "tileflow-nautical";
3874
4439
  var tileflowBathymetryV1Schema = Object.freeze({
3875
- fields: Object.freeze({ minDepth: "min_depth", sortKey: "sort_key" }),
4440
+ fields: Object.freeze({
4441
+ class: "class",
4442
+ depth: "depth",
4443
+ id: "id",
4444
+ maxZoom: "max_zoom",
4445
+ minDepth: "min_depth",
4446
+ minZoom: "min_zoom",
4447
+ name: "name",
4448
+ sortKey: "sort_key"
4449
+ }),
3876
4450
  layer: "bathymetry",
3877
4451
  layers: Object.freeze({
3878
4452
  bands: "bathymetry",
@@ -3937,6 +4511,7 @@ var tileflowNauticalV1Schema = Object.freeze({
3937
4511
  product: "nautical-v1",
3938
4512
  schemaVersion: 1
3939
4513
  });
4514
+ var tileflowBathymetryNameLayerLimits = Object.freeze({ maxZoomRanges: 128 });
3940
4515
  function bathymetry(options = {}) {
3941
4516
  return { type: "bathymetry", ...cloneJson(options) };
3942
4517
  }
@@ -3979,6 +4554,7 @@ function resolveBathymetry(input, apiBaseUrl) {
3979
4554
  ...advanced?.contours === void 0 ? {} : { contours: advanced.contours },
3980
4555
  display,
3981
4556
  ...advanced?.labels === void 0 ? {} : { labels: advanced.labels },
4557
+ ...advanced?.vectorLayers === void 0 ? {} : { vectorLayers: cloneJson(advanced.vectorLayers) },
3982
4558
  ...reliefVisible ? { relief: resolveBathymetryRelief(reliefConfig ?? {}, apiBaseUrl) } : {},
3983
4559
  ...usesVector ? {
3984
4560
  vector: resolveMarineSource({
@@ -4153,20 +4729,20 @@ function createTileflowLineBackgroundFontStack(source, metrics = {}) {
4153
4729
  return stack;
4154
4730
  }
4155
4731
  function parseTileflowLineBackgroundFontStack(stack) {
4156
- const match2 = STACK_PATTERN.exec(stack);
4157
- if (!match2 || stack.length > MAX_STACK_LENGTH || !SOURCE_PATTERN.test(match2[1]))
4732
+ const match3 = STACK_PATTERN.exec(stack);
4733
+ if (!match3 || stack.length > MAX_STACK_LENGTH || !SOURCE_PATTERN.test(match3[1]))
4158
4734
  return void 0;
4159
4735
  const metrics = {
4160
- letterSpacing: Number(match2[2]) / 1e3,
4161
- lineHeight: Number(match2[3]) / 1e3,
4162
- padding: Number(match2[4]) / 1e3
4736
+ letterSpacing: Number(match3[2]) / 1e3,
4737
+ lineHeight: Number(match3[3]) / 1e3,
4738
+ padding: Number(match3[4]) / 1e3
4163
4739
  };
4164
4740
  try {
4165
4741
  const normalized = normalizeTileflowLineBackgroundMetrics(metrics);
4166
- if (`lines-v1-t${thousandths(normalized.letterSpacing)}-l${thousandths(normalized.lineHeight)}-p${thousandths(normalized.padding)}` !== stack.slice(match2[1].length + 1)) {
4742
+ if (`lines-v1-t${thousandths(normalized.letterSpacing)}-l${thousandths(normalized.lineHeight)}-p${thousandths(normalized.padding)}` !== stack.slice(match3[1].length + 1)) {
4167
4743
  return void 0;
4168
4744
  }
4169
- return { metrics: normalized, source: match2[1] };
4745
+ return { metrics: normalized, source: match3[1] };
4170
4746
  } catch {
4171
4747
  return void 0;
4172
4748
  }
@@ -4276,15 +4852,15 @@ var GlyphReader = class {
4276
4852
  varint() {
4277
4853
  let result = 0;
4278
4854
  let shift = 0;
4279
- let byte;
4855
+ let byte2;
4280
4856
  do {
4281
4857
  if (this.position >= this.bytes.length || shift > 49) {
4282
4858
  throw new RangeError("Invalid glyph PBF varint.");
4283
4859
  }
4284
- byte = this.bytes[this.position++];
4285
- result += (byte & 127) * 2 ** shift;
4860
+ byte2 = this.bytes[this.position++];
4861
+ result += (byte2 & 127) * 2 ** shift;
4286
4862
  shift += 7;
4287
- } while (byte & 128);
4863
+ } while (byte2 & 128);
4288
4864
  return result;
4289
4865
  }
4290
4866
  signed() {
@@ -4731,10 +5307,10 @@ function mergeTileflowDesign(base, ...overlays) {
4731
5307
  }
4732
5308
  function mergeValue(base, overlay) {
4733
5309
  if (overlay === void 0) return cloneJson3(base);
4734
- if (Array.isArray(overlay) || isTileflowExpression(overlay) || isTileflowThemeValueNode(overlay) || isTileflowZoomValue(overlay) || !isRecord2(overlay)) {
5310
+ if (Array.isArray(overlay) || isTileflowExpression(overlay) || isTileflowThemeValueNode(overlay) || isTileflowZoomValue(overlay) || !isRecord3(overlay)) {
4735
5311
  return cloneJson3(overlay);
4736
5312
  }
4737
- const baseRecord = isRecord2(base) ? base : {};
5313
+ const baseRecord = isRecord3(base) ? base : {};
4738
5314
  const result = {};
4739
5315
  for (const key of /* @__PURE__ */ new Set([...Object.keys(baseRecord), ...Object.keys(overlay)])) {
4740
5316
  const overlayValue = overlay[key];
@@ -4750,7 +5326,7 @@ function cloneJson3(value) {
4750
5326
  if (value === void 0) return value;
4751
5327
  return JSON.parse(JSON.stringify(value));
4752
5328
  }
4753
- function isRecord2(value) {
5329
+ function isRecord3(value) {
4754
5330
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
4755
5331
  }
4756
5332
 
@@ -4854,13 +5430,13 @@ function tileflowVegetationMetadata(vegetation2) {
4854
5430
  return { version: 1, ...vegetation2 };
4855
5431
  }
4856
5432
  function readTileflowVegetation3D(metadata) {
4857
- if (!isRecord3(metadata)) return void 0;
5433
+ if (!isRecord4(metadata)) return void 0;
4858
5434
  const value = metadata[tileflowVegetationMetadataKey];
4859
- if (!isRecord3(value) || value.version !== 1) return void 0;
5435
+ if (!isRecord4(value) || value.version !== 1) return void 0;
4860
5436
  const { source, layers, fields, colors, heightScale, crownScale, unknownForms, regions: regions2 } = value;
4861
- if (typeof source !== "string" || !isRecord3(layers) || typeof layers.tree !== "string")
5437
+ if (typeof source !== "string" || !isRecord4(layers) || typeof layers.tree !== "string")
4862
5438
  return void 0;
4863
- if (!isRecord3(fields) || !isRecord3(colors) || typeof colors.bark !== "string") return void 0;
5439
+ if (!isRecord4(fields) || !isRecord4(colors) || typeof colors.bark !== "string") return void 0;
4864
5440
  const palette = (list) => Array.isArray(list) && list.length > 0 && list.every((entry) => typeof entry === "string") ? list : void 0;
4865
5441
  const broadleaf = palette(colors.broadleaf);
4866
5442
  const conifer = palette(colors.conifer);
@@ -4869,18 +5445,18 @@ function readTileflowVegetation3D(metadata) {
4869
5445
  const scale = (number) => typeof number === "number" && number > 0 && number <= 10 ? number : 1;
4870
5446
  const mix2 = tileflowTreeFormMixProblem(unknownForms) === void 0 ? unknownForms : void 0;
4871
5447
  const models = Object.fromEntries(
4872
- Object.entries(isRecord3(value.models) ? value.models : {}).filter(
4873
- ([id2, model]) => tileflowTreeModelIdPattern.test(id2) && isRecord3(model) && typeof model.near === "string" && (model.far === void 0 || typeof model.far === "string")
5448
+ Object.entries(isRecord4(value.models) ? value.models : {}).filter(
5449
+ ([id2, model]) => tileflowTreeModelIdPattern.test(id2) && isRecord4(model) && typeof model.near === "string" && (model.far === void 0 || typeof model.far === "string")
4874
5450
  ).slice(0, 16).map(([id2, model]) => {
4875
5451
  const { near, far } = model;
4876
5452
  return [id2, far === void 0 ? { near } : { near, far }];
4877
5453
  })
4878
5454
  );
4879
- const ownScales = isRecord3(value.forms) ? value.forms : {};
5455
+ const ownScales = isRecord4(value.forms) ? value.forms : {};
4880
5456
  const forms = Object.fromEntries(
4881
5457
  tileflowTreeForms.flatMap((form) => {
4882
5458
  const own = ownScales[form];
4883
- if (!isRecord3(own)) return [];
5459
+ if (!isRecord4(own)) return [];
4884
5460
  const drawn = Array.isArray(own.models) ? [...new Set(own.models)].filter((id2) => typeof id2 === "string" && id2 in models).slice(0, 4) : [];
4885
5461
  return [
4886
5462
  [
@@ -4897,7 +5473,7 @@ function readTileflowVegetation3D(metadata) {
4897
5473
  const finish = tileflowTreeFinishes.find((name) => name === value.finish) ?? "faceted";
4898
5474
  const edges = typeof value.edges === "number" && value.edges >= 0 && value.edges <= 1 ? value.edges : 0;
4899
5475
  const zones = Array.isArray(regions2) ? regions2.filter(
4900
- (region) => isRecord3(region) && tileflowTreeRegionProblem(region) === void 0
5476
+ (region) => isRecord4(region) && tileflowTreeRegionProblem(region) === void 0
4901
5477
  ) : [];
4902
5478
  const named = Object.fromEntries(
4903
5479
  Object.entries(tileflowWorldTreeFields).map(([key, fallback]) => [
@@ -4926,7 +5502,7 @@ function readTileflowVegetation3D(metadata) {
4926
5502
  };
4927
5503
  }
4928
5504
  function tileflowTreeRegionProblem(region) {
4929
- if (!isRecord3(region)) return "a region is an object with bounds and unknownForms";
5505
+ if (!isRecord4(region)) return "a region is an object with bounds and unknownForms";
4930
5506
  const bounds = region.bounds;
4931
5507
  if (!Array.isArray(bounds) || bounds.length !== 4 || !bounds.every((value) => typeof value === "number" && Number.isFinite(value)))
4932
5508
  return "bounds are [west, south, east, north] in degrees";
@@ -4937,7 +5513,7 @@ function tileflowTreeRegionProblem(region) {
4937
5513
  const mix2 = tileflowTreeFormMixProblem(region.unknownForms);
4938
5514
  return mix2 ? `unknownForms: ${mix2}` : void 0;
4939
5515
  }
4940
- function isRecord3(value) {
5516
+ function isRecord4(value) {
4941
5517
  return typeof value === "object" && value !== null && !Array.isArray(value);
4942
5518
  }
4943
5519
 
@@ -5004,7 +5580,7 @@ function compileVegetation(request, context) {
5004
5580
  }
5005
5581
  function tileflowVegetationDescription(request, context) {
5006
5582
  const { schema } = context.data;
5007
- if (request?.enabled === false || (request?.mode ?? "3d") !== "3d" || !schema.layers.tree)
5583
+ if (request?.enabled === false || request?.mode === "flat" || !schema.layers.tree)
5008
5584
  return void 0;
5009
5585
  const tree = context.colors.vegetation.tree;
5010
5586
  const style = request?.threeDimensional ?? {};
@@ -5067,153 +5643,6 @@ function tileflowVegetationDescription(request, context) {
5067
5643
  };
5068
5644
  }
5069
5645
 
5070
- // src/buildings-3d-design.ts
5071
- var tileflowBuildingsMetadataKey = "tileflow:buildings";
5072
- var tileflowDefaultBuildings3DDesign = Object.freeze({
5073
- source: "tileflow",
5074
- layers: Object.freeze({ building: "building", places: "poi" }),
5075
- color: "#d8d0c0",
5076
- edges: 1,
5077
- nightLight: 1,
5078
- windows: false,
5079
- shadows: true,
5080
- occlusion: true
5081
- });
5082
- function tileflowBuildingsMetadata(design) {
5083
- return { version: 1, ...design };
5084
- }
5085
- function readTileflowBuildings3D(metadata) {
5086
- if (!isRecord4(metadata)) return void 0;
5087
- const value = metadata[tileflowBuildingsMetadataKey];
5088
- if (!isRecord4(value) || value.version !== 1) return void 0;
5089
- const { source, layers, color: color3 } = value;
5090
- if (typeof source !== "string" || !isRecord4(layers) || typeof layers.building !== "string")
5091
- return void 0;
5092
- if (typeof color3 !== "string" && !Array.isArray(color3)) return void 0;
5093
- const within = (number, high, fallback) => typeof number === "number" && number >= 0 && number <= high ? number : fallback;
5094
- return {
5095
- source,
5096
- layers: {
5097
- building: layers.building,
5098
- ...typeof layers.places === "string" ? { places: layers.places } : {}
5099
- },
5100
- color: color3,
5101
- edges: within(value.edges, 1, 1),
5102
- ...typeof value.edgeColor === "string" ? { edgeColor: value.edgeColor } : {},
5103
- nightLight: within(value.nightLight, 2, 1),
5104
- windows: value.windows === true,
5105
- shadows: value.shadows !== false,
5106
- occlusion: value.occlusion !== false
5107
- };
5108
- }
5109
- function isRecord4(value) {
5110
- return typeof value === "object" && value !== null && !Array.isArray(value);
5111
- }
5112
-
5113
- // src/street-lights.ts
5114
- init_theme_blend();
5115
- var tileflowStreetLightsMetadataKey = "tileflow:street-lights";
5116
- var tileflowDefaultStreetLightsDesign = Object.freeze({
5117
- source: "tileflow",
5118
- layers: Object.freeze({
5119
- streetFurniture: "street_furniture",
5120
- transportation: "transportation",
5121
- sidewalk: "sidewalk"
5122
- }),
5123
- estimate: "lit",
5124
- color: "#ffcf8f",
5125
- intensity: 1
5126
- });
5127
- function tileflowStreetLightsMetadata(design) {
5128
- return { version: 1, ...design };
5129
- }
5130
- function readTileflowStreetLights(metadata) {
5131
- if (typeof metadata !== "object" || metadata === null || Array.isArray(metadata))
5132
- return void 0;
5133
- const value = metadata[tileflowStreetLightsMetadataKey];
5134
- if (typeof value !== "object" || value === null || value.version !== 1) return void 0;
5135
- const layers = value.layers;
5136
- if (typeof value.source !== "string" || typeof layers?.streetFurniture !== "string" || typeof layers.transportation !== "string")
5137
- return void 0;
5138
- const estimate = ["lit", "streets", "none"].find((name) => name === value.estimate);
5139
- const intensity = typeof value.intensity === "number" && value.intensity >= 0 && value.intensity <= 2 ? value.intensity : 1;
5140
- return {
5141
- source: value.source,
5142
- layers: {
5143
- streetFurniture: layers.streetFurniture,
5144
- transportation: layers.transportation,
5145
- ...typeof layers.sidewalk === "string" ? { sidewalk: layers.sidewalk } : {}
5146
- },
5147
- estimate: estimate ?? "lit",
5148
- color: typeof value.color === "string" && tileflowColourChannels(value.color) ? value.color : tileflowDefaultStreetLightsDesign.color,
5149
- intensity
5150
- };
5151
- }
5152
-
5153
- // src/cartography/scene-3d-metadata.ts
5154
- init_values();
5155
- var colourSources = [
5156
- ["tileflow-buildings-render-extrusion", "fill-extrusion-color"],
5157
- ["tileflow-buildings-3d", "fill-extrusion-color"],
5158
- ["tileflow-buildings-fill", "fill-color"]
5159
- ];
5160
- function tileflowBuildings3DDesignOf(module, context, layers) {
5161
- const config = isRecord5(module) ? module : {};
5162
- if (config.enabled === false) return void 0;
5163
- const style = config.threeDimensional ?? {};
5164
- let color3;
5165
- for (const [id2, property] of colourSources) {
5166
- const value = layers.find((layer) => layer.id === id2)?.paint?.[property];
5167
- if (typeof value === "string" || Array.isArray(value)) {
5168
- color3 = value;
5169
- break;
5170
- }
5171
- }
5172
- const number = (value, fallback) => {
5173
- const resolved = value === void 0 ? void 0 : toMapLibreStyleValue(value);
5174
- return typeof resolved === "number" ? resolved : fallback;
5175
- };
5176
- const edgeColor = style.edgeColor === void 0 ? void 0 : toMapLibreStyleValue(style.edgeColor);
5177
- return {
5178
- source: context.data.sourceId,
5179
- layers: {
5180
- building: context.data.schema.layers.building,
5181
- ...context.data.schema.layers.poi ? { places: context.data.schema.layers.poi } : {}
5182
- },
5183
- color: color3 ?? context.colors.buildings.generic,
5184
- edges: number(style.edges, 1),
5185
- ...typeof edgeColor === "string" ? { edgeColor } : {},
5186
- nightLight: number(style.nightLight, 1),
5187
- windows: style.windows === true,
5188
- shadows: style.shadows !== false,
5189
- occlusion: style.occlusion !== false
5190
- };
5191
- }
5192
- function tileflowStreetLightsDesignOf(module, context) {
5193
- const config = isRecord5(module) ? module : {};
5194
- const layers = context.data.schema.layers;
5195
- const style = config.streetLights ?? {};
5196
- if (config.enabled === false || style.enabled === false || !layers.streetFurniture)
5197
- return void 0;
5198
- const color3 = style.color === void 0 ? void 0 : toMapLibreStyleValue(style.color);
5199
- const intensity = style.intensity === void 0 ? void 0 : toMapLibreStyleValue(style.intensity);
5200
- const estimate = style.estimate;
5201
- return {
5202
- source: context.data.sourceId,
5203
- layers: {
5204
- streetFurniture: layers.streetFurniture,
5205
- transportation: layers.road,
5206
- ...layers.sidewalk ? { sidewalk: layers.sidewalk } : {}
5207
- },
5208
- estimate: estimate === "streets" || estimate === "none" || estimate === "lit" ? estimate : "lit",
5209
- color: typeof color3 === "string" ? color3 : tileflowDefaultStreetLightsDesign.color,
5210
- intensity: typeof intensity === "number" ? intensity : 1
5211
- };
5212
- }
5213
- function isRecord5(value) {
5214
- return typeof value === "object" && value !== null && !Array.isArray(value);
5215
- }
5216
-
5217
5646
  // src/cartography/contributions.ts
5218
5647
  var tileflowLayerSlots = [
5219
5648
  "background",
@@ -5776,7 +6205,21 @@ function buildingColorExpression(context) {
5776
6205
  colors.destination,
5777
6206
  ["==", ["coalesce", ["get", fields.buildingTone], ""], "commercial"],
5778
6207
  colors.commercial,
5779
- colors.generic
6208
+ // Without a tone, World's use class: housing, shops and offices, public buildings and works
6209
+ // each take their theme colour; a shed, a garage or an unknown use the generic one.
6210
+ [
6211
+ "match",
6212
+ ["coalesce", ["get", fields.class], ""],
6213
+ "residential",
6214
+ colors.residential,
6215
+ "commercial",
6216
+ colors.commercial,
6217
+ ["civic", "education", "entertainment", "medical", "military", "religious", "transportation"],
6218
+ colors.civic,
6219
+ ["agricultural", "industrial", "service"],
6220
+ colors.industrial,
6221
+ colors.generic
6222
+ ]
5780
6223
  ];
5781
6224
  }
5782
6225
  function buildingVisibilityFilter() {
@@ -6041,6 +6484,9 @@ init_values();
6041
6484
  function labelField(language, context) {
6042
6485
  return expression(labelFieldExpression(language, context));
6043
6486
  }
6487
+ function labelNameFields(language, context) {
6488
+ return labelFieldExpression(language, context).slice(1).map((entry) => entry[1]);
6489
+ }
6044
6490
  function labelFieldExpression(language, context) {
6045
6491
  const fields = context.data.schema.fields;
6046
6492
  if (language === "local") {
@@ -6900,12 +7346,12 @@ function compileLand(request, context) {
6900
7346
  if (name === "recreation") continue;
6901
7347
  appendLanduse(name, classes);
6902
7348
  }
6903
- for (const [name, match2] of landcoverClasses) {
7349
+ for (const [name, match3] of landcoverClasses) {
6904
7350
  const style = config.landcover?.[name];
6905
7351
  if (!style) continue;
6906
7352
  const protectedSource = name === "protected";
6907
7353
  const sourceLayer = protectedSource ? schema.layers.park : schema.layers.landcover;
6908
- const filter = protectedSource && schema.semantics.parkLayer === "protected-only" ? void 0 : landcoverFilter(classField, subclassField, match2);
7354
+ const filter = protectedSource && schema.semantics.parkLayer === "protected-only" ? void 0 : landcoverFilter(classField, subclassField, match3);
6909
7355
  for (const area of createAreaLayers(
6910
7356
  {
6911
7357
  id: `tileflow-landcover-${name}`,
@@ -6961,11 +7407,11 @@ function compileLand(request, context) {
6961
7407
  function classFilter2(field2, classes) {
6962
7408
  return ["match", ["get", field2], classes, true, false];
6963
7409
  }
6964
- function landcoverFilter(classField, subclassField, match2) {
6965
- const filter = classFilter2(classField, match2.class);
6966
- if (match2.subclass) return ["all", filter, classFilter2(subclassField, match2.subclass)];
6967
- if (match2.excludeSubclass) {
6968
- return ["all", filter, ["!", classFilter2(subclassField, match2.excludeSubclass)]];
7410
+ function landcoverFilter(classField, subclassField, match3) {
7411
+ const filter = classFilter2(classField, match3.class);
7412
+ if (match3.subclass) return ["all", filter, classFilter2(subclassField, match3.subclass)];
7413
+ if (match3.excludeSubclass) {
7414
+ return ["all", filter, ["!", classFilter2(subclassField, match3.excludeSubclass)]];
6969
7415
  }
6970
7416
  return filter;
6971
7417
  }
@@ -7642,184 +8088,595 @@ function lightLabel(fields) {
7642
8088
  ["case", ["has", fields.name], ["concat", " ", ["to-string", ["get", fields.name]]], ""]
7643
8089
  ]);
7644
8090
  }
7645
-
7646
- // src/types.ts
7647
- var tileflowPoiCategories = [
7648
- "arts-entertainment",
7649
- "education",
7650
- "food-drink",
7651
- "landmark",
7652
- "lodging",
7653
- "medical",
7654
- "park-nature",
7655
- "public-services",
7656
- "religion",
7657
- "retail",
7658
- "sport-leisure",
7659
- "transport",
7660
- "visitor-amenity"
7661
- ];
7662
-
7663
- // src/modules/poi/index.ts
7664
- var tileflowPoiImageRoles = Object.freeze({
7665
- "arts-entertainment": { fallback: "culture", token: "poi.arts-entertainment" },
7666
- education: { fallback: "education", token: "poi.education" },
7667
- "food-drink": { fallback: "food", token: "poi.food-drink" },
7668
- landmark: { fallback: "culture", token: "poi.landmark" },
7669
- lodging: { fallback: "lodging", token: "poi.lodging" },
7670
- medical: { fallback: "health", token: "poi.medical" },
7671
- "park-nature": { fallback: "services", token: "poi.park-nature" },
7672
- "public-services": { fallback: "services", token: "poi.public-services" },
7673
- religion: { fallback: "culture", token: "poi.religion" },
7674
- retail: { fallback: "shopping", token: "poi.retail" },
7675
- "sport-leisure": { fallback: "culture", token: "poi.sport-leisure" },
7676
- transport: { fallback: "major-transit", token: "poi.transport" },
7677
- "visitor-amenity": { fallback: "services", token: "poi.visitor-amenity" }
7678
- });
7679
- function poi(options = {}) {
7680
- return { type: "poi", ...cloneJson13(options) };
8091
+
8092
+ // src/types.ts
8093
+ var tileflowPoiCategories = [
8094
+ "arts-entertainment",
8095
+ "education",
8096
+ "food-drink",
8097
+ "landmark",
8098
+ "lodging",
8099
+ "medical",
8100
+ "park-nature",
8101
+ "public-services",
8102
+ "religion",
8103
+ "retail",
8104
+ "sport-leisure",
8105
+ "transport",
8106
+ "visitor-amenity"
8107
+ ];
8108
+
8109
+ // src/modules/poi/index.ts
8110
+ var tileflowPoiImageRoles = Object.freeze({
8111
+ "arts-entertainment": { fallback: "culture", token: "poi.arts-entertainment" },
8112
+ education: { fallback: "education", token: "poi.education" },
8113
+ "food-drink": { fallback: "food", token: "poi.food-drink" },
8114
+ landmark: { fallback: "culture", token: "poi.landmark" },
8115
+ lodging: { fallback: "lodging", token: "poi.lodging" },
8116
+ medical: { fallback: "health", token: "poi.medical" },
8117
+ "park-nature": { fallback: "services", token: "poi.park-nature" },
8118
+ "public-services": { fallback: "services", token: "poi.public-services" },
8119
+ religion: { fallback: "culture", token: "poi.religion" },
8120
+ retail: { fallback: "shopping", token: "poi.retail" },
8121
+ "sport-leisure": { fallback: "culture", token: "poi.sport-leisure" },
8122
+ transport: { fallback: "major-transit", token: "poi.transport" },
8123
+ "visitor-amenity": { fallback: "services", token: "poi.visitor-amenity" }
8124
+ });
8125
+ var tileflowPoiIconOnlyTypes = Object.freeze([
8126
+ "parking",
8127
+ "parking_garage",
8128
+ "parking_lot",
8129
+ "public_restroom"
8130
+ ]);
8131
+ function poi(options = {}) {
8132
+ return { type: "poi", ...cloneJson13(options) };
8133
+ }
8134
+ function resolvePoi(request) {
8135
+ return {
8136
+ categories: [...new Set(request?.categories ?? tileflowPoiCategories)],
8137
+ color: request?.color ?? "uniform",
8138
+ density: request?.density ?? 3,
8139
+ icons: request?.icons ?? true,
8140
+ labels: request?.labels ?? true,
8141
+ minZoom: request?.minZoom ?? 0,
8142
+ placement: {
8143
+ coupleIconAndLabel: request?.placement?.coupleIconAndLabel ?? false,
8144
+ iconOnlyTypes: [...request?.placement?.iconOnlyTypes ?? tileflowPoiIconOnlyTypes],
8145
+ iconPadding: request?.placement?.iconPadding ?? 2,
8146
+ order: request?.placement?.order ?? "importance",
8147
+ ...request?.placement?.prominentRank === void 0 ? {} : { prominentRank: request.placement.prominentRank },
8148
+ textPadding: request?.placement?.textPadding ?? 2
8149
+ }
8150
+ };
8151
+ }
8152
+ function cloneJson13(value) {
8153
+ return JSON.parse(JSON.stringify(value));
8154
+ }
8155
+
8156
+ // src/modules/poi/compiler.ts
8157
+ init_values();
8158
+
8159
+ // src/modules/poi/placement.ts
8160
+ init_expression_operators();
8161
+ var tileflowPoiFeatureVaryingProperties = Object.freeze({
8162
+ circle: Object.freeze({
8163
+ "circle-blur": 0,
8164
+ "circle-color": "#000000",
8165
+ "circle-opacity": 1,
8166
+ "circle-radius": 5,
8167
+ "circle-sort-key": void 0,
8168
+ "circle-stroke-color": "#000000",
8169
+ "circle-stroke-opacity": 1,
8170
+ "circle-stroke-width": 0
8171
+ }),
8172
+ symbol: Object.freeze({
8173
+ "icon-anchor": "center",
8174
+ "icon-color": "#000000",
8175
+ "icon-halo-blur": 0,
8176
+ "icon-halo-color": "rgba(0, 0, 0, 0)",
8177
+ "icon-halo-width": 0,
8178
+ // An empty image draws no icon, so a category without one stays text-only.
8179
+ "icon-image": "",
8180
+ "icon-offset": [0, 0],
8181
+ "icon-opacity": 1,
8182
+ "icon-padding": [2],
8183
+ "icon-rotate": 0,
8184
+ "icon-size": 1,
8185
+ "symbol-sort-key": void 0,
8186
+ "text-anchor": "center",
8187
+ "text-color": "#000000",
8188
+ "text-field": "",
8189
+ // MapLibre can vary `text-font` per feature, but Tileflow prepares glyphs for a static font
8190
+ // stack, so the font stays a layer-wide property.
8191
+ "text-halo-blur": 0,
8192
+ "text-halo-color": "rgba(0, 0, 0, 0)",
8193
+ "text-halo-width": 0,
8194
+ "text-justify": "center",
8195
+ "text-letter-spacing": 0,
8196
+ "text-max-width": 10,
8197
+ "text-offset": [0, 0],
8198
+ "text-opacity": 1,
8199
+ "text-radial-offset": 0,
8200
+ "text-rotate": 0,
8201
+ "text-size": 16,
8202
+ "text-transform": "none",
8203
+ "text-variable-anchor-offset": void 0
8204
+ })
8205
+ });
8206
+ var tileflowPoiLayerPropertyDefaults = Object.freeze({
8207
+ "circle-pitch-alignment": "viewport",
8208
+ "circle-pitch-scale": "map",
8209
+ "circle-translate": [0, 0],
8210
+ "circle-translate-anchor": "map",
8211
+ "icon-allow-overlap": false,
8212
+ "icon-ignore-placement": false,
8213
+ "icon-keep-upright": false,
8214
+ "icon-optional": false,
8215
+ "icon-pitch-alignment": "auto",
8216
+ "icon-rotation-alignment": "auto",
8217
+ "icon-text-fit": "none",
8218
+ "icon-text-fit-padding": [0, 0, 0, 0],
8219
+ "symbol-avoid-edges": false,
8220
+ "symbol-placement": "point",
8221
+ "symbol-spacing": 250,
8222
+ "symbol-z-order": "auto",
8223
+ "text-allow-overlap": false,
8224
+ "text-ignore-placement": false,
8225
+ "text-keep-upright": true,
8226
+ "text-line-height": 1.2,
8227
+ "text-max-angle": 45,
8228
+ "text-optional": false,
8229
+ "text-padding": 2,
8230
+ "text-pitch-alignment": "auto",
8231
+ "text-rotation-alignment": "auto",
8232
+ visibility: "visible"
8233
+ });
8234
+ var TileflowPoiPlacementError = class extends Error {
8235
+ code = "TILEFLOW_POI_PLACEMENT_CONFLICT";
8236
+ constructor(message) {
8237
+ super(message);
8238
+ this.name = "TileflowPoiPlacementError";
8239
+ }
8240
+ };
8241
+ function mergePoiCategoryLayers(entries, options) {
8242
+ const [first] = entries;
8243
+ if (!first) throw new TileflowPoiPlacementError("A POI placement layer needs a category.");
8244
+ const kind = first.layer.type === "circle" ? "circle" : "symbol";
8245
+ const varying = tileflowPoiFeatureVaryingProperties[kind];
8246
+ const categories = entries.map(({ category }) => category);
8247
+ for (const property of ["type", "source", "source-layer", "minzoom", "maxzoom"]) {
8248
+ requireShared(entries, property, (layer) => layer[property]);
8249
+ }
8250
+ const result = {
8251
+ ...first.layer,
8252
+ id: options.id,
8253
+ filter: options.filter
8254
+ };
8255
+ for (const part of ["layout", "paint"]) {
8256
+ const records = entries.map(({ layer }) => asRecord3(layer[part]));
8257
+ const properties = [...new Set(records.flatMap((record2) => Object.keys(record2)))].sort();
8258
+ const merged = {};
8259
+ for (const property of properties) {
8260
+ const fallback = Object.hasOwn(varying, property) ? varying[property] : tileflowPoiLayerPropertyDefaults[property];
8261
+ const values = records.map(
8262
+ (record2) => Object.hasOwn(record2, property) ? record2[property] : fallback
8263
+ );
8264
+ if (values.every((value) => sameJson(value, values[0]))) {
8265
+ if (values[0] !== void 0) merged[property] = values[0];
8266
+ continue;
8267
+ }
8268
+ if (!Object.hasOwn(varying, property)) {
8269
+ throw conflict(entries, property, (layer) => asRecord3(layer[part])[property]);
8270
+ }
8271
+ if (values.some((value) => value === void 0)) {
8272
+ throw new TileflowPoiPlacementError(
8273
+ `POI categories ${categories.join(", ")} set ${property} for only some categories, and MapLibre has no default to fill in for the rest. Set it for every category.`
8274
+ );
8275
+ }
8276
+ merged[property] = matchByCategory(
8277
+ property,
8278
+ categories.map((category, index) => [category, values[index]]),
8279
+ ["get", options.categoryField]
8280
+ );
8281
+ }
8282
+ if (Object.keys(merged).length) result[part] = merged;
8283
+ else delete result[part];
8284
+ }
8285
+ return result;
8286
+ }
8287
+ function requireShared(entries, property, read) {
8288
+ const value = read(entries[0].layer);
8289
+ if (entries.every(({ layer }) => sameJson(read(layer), value))) return;
8290
+ throw conflict(entries, property, read);
8291
+ }
8292
+ function conflict(entries, property, read) {
8293
+ const described = entries.map(({ category, layer }) => `${category}: ${JSON.stringify(read(layer)) ?? "unset"}`).join("; ");
8294
+ return new TileflowPoiPlacementError(
8295
+ `POI categories need different ${property} values (${described}), but MapLibre keeps ${property} constant within one layer. Give them the same ${property}, or set placement.order to 'categories' to place each category in its own layer.`
8296
+ );
8297
+ }
8298
+ function matchByCategory(property, values, input) {
8299
+ const curves = values.map(([, value]) => zoomCurve(value));
8300
+ const present = curves.filter((curve) => curve !== void 0);
8301
+ if (present.length === 0) return match(input, values);
8302
+ const reference = present[0];
8303
+ for (const curve of present) {
8304
+ if (curve.kind !== reference.kind || curve.kind === "interpolate" && reference.kind === "interpolate" && (curve.operator !== reference.operator || !sameJson(curve.interpolation, reference.interpolation))) {
8305
+ throw new TileflowPoiPlacementError(
8306
+ `POI categories use different kinds of zoom curve for ${property}. Use one kind of curve (linear, the same exponential base, or step) for every category, or set placement.order to 'categories'.`
8307
+ );
8308
+ }
8309
+ }
8310
+ const stops = [...new Set(present.flatMap((curve) => curve.stops.map(([zoom3]) => zoom3)))].sort(
8311
+ (left, right) => left - right
8312
+ );
8313
+ const at = (zoom3) => match(
8314
+ input,
8315
+ values.map(([category, value], index) => [
8316
+ category,
8317
+ curves[index] ? evaluateCurve(property, curves[index], zoom3) : value
8318
+ ])
8319
+ );
8320
+ if (reference.kind === "step") {
8321
+ const base = match(
8322
+ input,
8323
+ values.map(([category, value], index) => {
8324
+ const curve = curves[index];
8325
+ return [category, curve?.kind === "step" ? curve.base : value];
8326
+ })
8327
+ );
8328
+ return ["step", ["zoom"], base, ...stops.flatMap((zoom3) => [zoom3, at(zoom3)])];
8329
+ }
8330
+ return [
8331
+ reference.operator,
8332
+ reference.interpolation,
8333
+ ["zoom"],
8334
+ ...stops.flatMap((zoom3) => [zoom3, at(zoom3)])
8335
+ ];
8336
+ }
8337
+ function match(input, values) {
8338
+ const groups = [];
8339
+ for (const [category, value] of values) {
8340
+ const group = groups.find((candidate) => sameJson(candidate.value, value));
8341
+ if (group) group.categories.push(category);
8342
+ else groups.push({ categories: [category], value });
8343
+ }
8344
+ if (groups.length === 1) return groups[0].value;
8345
+ const fallback = groups.reduce(
8346
+ (largest, group) => group.categories.length > largest.categories.length ? group : largest
8347
+ );
8348
+ return [
8349
+ "match",
8350
+ input,
8351
+ ...groups.filter((group) => group !== fallback).flatMap((group) => [
8352
+ group.categories.length === 1 ? group.categories[0] : group.categories,
8353
+ expressionValue(group.value)
8354
+ ]),
8355
+ expressionValue(fallback.value)
8356
+ ];
8357
+ }
8358
+ function zoomCurve(value) {
8359
+ if (!Array.isArray(value)) return void 0;
8360
+ const [operator] = value;
8361
+ if ((operator === "interpolate" || operator === "interpolate-hcl" || operator === "interpolate-lab") && isZoomInput3(value[2])) {
8362
+ return {
8363
+ kind: "interpolate",
8364
+ operator,
8365
+ interpolation: value[1],
8366
+ stops: pairs(value.slice(3))
8367
+ };
8368
+ }
8369
+ if (operator === "step" && isZoomInput3(value[1])) {
8370
+ return { kind: "step", base: value[2], stops: pairs(value.slice(3)) };
8371
+ }
8372
+ return void 0;
8373
+ }
8374
+ function evaluateCurve(property, curve, zoom3) {
8375
+ const { stops } = curve;
8376
+ if (curve.kind === "step") {
8377
+ let value2 = curve.base;
8378
+ for (const [stop, output] of stops) if (stop <= zoom3) value2 = output;
8379
+ return value2;
8380
+ }
8381
+ const exact = stops.find(([stop]) => stop === zoom3);
8382
+ if (exact) return exact[1];
8383
+ if (zoom3 < stops[0][0]) return stops[0][1];
8384
+ if (zoom3 > stops.at(-1)[0]) return stops.at(-1)[1];
8385
+ const upperIndex = stops.findIndex(([stop]) => stop > zoom3);
8386
+ const [lowerZoom, lower] = stops[upperIndex - 1];
8387
+ const [upperZoom, upper] = stops[upperIndex];
8388
+ const t = interpolationFactor(curve.interpolation, zoom3, lowerZoom, upperZoom);
8389
+ const value = interpolateOutput(lower, upper, t);
8390
+ if (value === void 0) {
8391
+ throw new TileflowPoiPlacementError(
8392
+ `POI categories interpolate ${property} between values Tileflow cannot evaluate at zoom ${zoom3}. Give every category the same zoom stops for ${property}, or set placement.order to 'categories'.`
8393
+ );
8394
+ }
8395
+ return value;
8396
+ }
8397
+ function interpolationFactor(interpolation, zoom3, lower, upper) {
8398
+ const progress = zoom3 - lower;
8399
+ const range2 = upper - lower;
8400
+ if (Array.isArray(interpolation) && interpolation[0] === "exponential") {
8401
+ const base = Number(interpolation[1]);
8402
+ if (base !== 1) return (base ** progress - 1) / (base ** range2 - 1);
8403
+ }
8404
+ return progress / range2;
8405
+ }
8406
+ function interpolateOutput(lower, upper, t) {
8407
+ if (typeof lower === "number" && typeof upper === "number") {
8408
+ return roundOutput(lower + (upper - lower) * t);
8409
+ }
8410
+ const lowerArray = numericArray(lower);
8411
+ const upperArray = numericArray(upper);
8412
+ if (lowerArray && upperArray && lowerArray.length === upperArray.length) {
8413
+ return [
8414
+ "literal",
8415
+ lowerArray.map((value, index) => roundOutput(value + (upperArray[index] - value) * t))
8416
+ ];
8417
+ }
8418
+ if (isNumericOutput(lower) && isNumericOutput(upper)) {
8419
+ return ["+", lower, ["*", roundOutput(t), ["-", upper, lower]]];
8420
+ }
8421
+ return void 0;
8422
+ }
8423
+ function isNumericOutput(value) {
8424
+ if (typeof value === "number") return true;
8425
+ if (!Array.isArray(value) || typeof value[0] !== "string") return false;
8426
+ return isMapLibreExpressionOperator(value[0]) && !["literal", "array"].includes(value[0]);
8427
+ }
8428
+ function numericArray(value) {
8429
+ const array = Array.isArray(value) && value[0] === "literal" && Array.isArray(value[1]) ? value[1] : value;
8430
+ return Array.isArray(array) && array.every((entry) => typeof entry === "number") ? array : void 0;
8431
+ }
8432
+ function roundOutput(value) {
8433
+ return Math.round(value * 1e6) / 1e6;
8434
+ }
8435
+ function expressionValue(value) {
8436
+ if (!Array.isArray(value)) return value;
8437
+ if (typeof value[0] === "string" && isMapLibreExpressionOperator(value[0])) return value;
8438
+ return ["literal", value];
8439
+ }
8440
+ function pairs(values) {
8441
+ const result = [];
8442
+ for (let index = 0; index + 1 < values.length; index += 2) {
8443
+ result.push([values[index], values[index + 1]]);
8444
+ }
8445
+ return result;
8446
+ }
8447
+ function isZoomInput3(value) {
8448
+ return Array.isArray(value) && value.length === 1 && value[0] === "zoom";
7681
8449
  }
7682
- function resolvePoi(request) {
7683
- return {
7684
- categories: [...new Set(request?.categories ?? tileflowPoiCategories)],
7685
- color: request?.color ?? "uniform",
7686
- density: request?.density ?? 3,
7687
- icons: request?.icons ?? true,
7688
- labels: request?.labels ?? true,
7689
- minZoom: request?.minZoom ?? 0,
7690
- placement: {
7691
- coupleIconAndLabel: request?.placement?.coupleIconAndLabel ?? false,
7692
- iconPadding: request?.placement?.iconPadding ?? 2,
7693
- textPadding: request?.placement?.textPadding ?? 2
7694
- }
7695
- };
8450
+ function sameJson(left, right) {
8451
+ return JSON.stringify(left) === JSON.stringify(right);
7696
8452
  }
7697
- function cloneJson13(value) {
7698
- return JSON.parse(JSON.stringify(value));
8453
+ function asRecord3(value) {
8454
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
7699
8455
  }
7700
8456
 
7701
8457
  // src/modules/poi/compiler.ts
7702
- init_values();
8458
+ var representationOrder = {
8459
+ marker: 0,
8460
+ combined: 1,
8461
+ icon: 1,
8462
+ label: 2
8463
+ };
7703
8464
  function compilePoi(request, context, language = "auto") {
7704
8465
  if (request?.enabled === false) return [];
7705
8466
  const semantics = resolvePoi(request);
7706
- const result = [];
8467
+ const selection2 = createPoiSelection(semantics, context, language);
8468
+ const parts = semantics.categories.flatMap(
8469
+ (category) => compileCategory(category, request, semantics, context, language, selection2)
8470
+ );
8471
+ if (semantics.placement.order === "categories") {
8472
+ return parts.map((part) => {
8473
+ const rank = semantics.categories.length - 1 - semantics.categories.indexOf(part.category);
8474
+ const suffix = part.representation === "combined" ? "" : `.${part.representation}`;
8475
+ return poiContribution(
8476
+ `${part.category}${suffix}`,
8477
+ rank * 4 + representationOrder[part.representation],
8478
+ {
8479
+ ...part.layer,
8480
+ id: `tileflow-poi-${part.category}${suffix.replace(".", "-")}`,
8481
+ filter: selection2.filter([part.category], part.representation)
8482
+ }
8483
+ );
8484
+ });
8485
+ }
8486
+ const { prominentRank } = semantics.placement;
8487
+ const filterRank = numericPoiField(context.data.schema.fields.poiFilterRank, 6);
8488
+ return ["marker", "combined", "icon", "label"].flatMap((representation) => {
8489
+ const entries = parts.filter((part) => part.representation === representation);
8490
+ if (entries.length === 0) return [];
8491
+ const suffix = representation === "combined" ? "" : `.${representation}`;
8492
+ const filter = selection2.filter(
8493
+ entries.map(({ category }) => category),
8494
+ representation
8495
+ );
8496
+ const layer = mergePoiCategoryLayers(entries, {
8497
+ categoryField: context.data.schema.fields.poiCategory,
8498
+ filter,
8499
+ id: `tileflow-poi${suffix.replace(".", "-")}`
8500
+ });
8501
+ if (prominentRank === void 0 || representation === "marker") {
8502
+ return [poiContribution(suffix.slice(1), representationOrder[representation], layer)];
8503
+ }
8504
+ return [
8505
+ poiContribution(suffix.slice(1), representationOrder[representation], {
8506
+ ...layer,
8507
+ filter: [...filter, [">", filterRank, prominentRank]]
8508
+ }),
8509
+ poiContribution(`prominent${suffix}`, 400 + representationOrder[representation], {
8510
+ ...layer,
8511
+ id: `tileflow-poi-prominent${suffix.replace(".", "-")}`,
8512
+ filter: [...filter, ["<=", filterRank, prominentRank]]
8513
+ })
8514
+ ];
8515
+ });
8516
+ }
8517
+ function compileCategory(category, request, semantics, context, language, selection2) {
7707
8518
  const { sourceId: source, schema } = context.data;
7708
- for (const [index, category] of semantics.categories.entries()) {
7709
- const requestedCategoryStyle = request?.styles?.[category];
7710
- const categoryDensity = requestedCategoryStyle?.density ?? semantics.density;
7711
- const { density: _density, ...categoryStyle } = requestedCategoryStyle ?? {};
7712
- const categoryColor = semantics.color === "category" ? context.colors.poi[category] ?? context.colors.poi.label : context.colors.poi.label;
7713
- const defaults4 = {
8519
+ const coupled = semantics.placement.coupleIconAndLabel;
8520
+ const categoryColor = semantics.color === "category" ? context.colors.poi[category] ?? context.colors.poi.label : context.colors.poi.label;
8521
+ const defaults4 = {
8522
+ icon: {
8523
+ optional: !coupled,
8524
+ padding: semantics.placement.iconPadding,
8525
+ size: semantics.minZoom < 17 ? zoom.linear([
8526
+ [semantics.minZoom, 0.85],
8527
+ [17, 1]
8528
+ ]) : 1
8529
+ },
8530
+ text: poiTextStyle(context, {
8531
+ color: categoryColor,
8532
+ field: labelField(language, context),
8533
+ // A coupled POI is its pictogram and its name: it is placed only when both fit.
8534
+ optional: !coupled,
8535
+ padding: semantics.placement.textPadding,
8536
+ size: semantics.minZoom < 17 ? zoom.linear([
8537
+ [semantics.minZoom, 10],
8538
+ [17, 12]
8539
+ ]) : 12
8540
+ })
8541
+ };
8542
+ let style = mergeTileflowDesign(defaults4, request?.styles?.[category] ?? {});
8543
+ const markerStyle = style.marker ? resolveMarkerStyle(style) : void 0;
8544
+ const hidden = style.visible === false;
8545
+ const showText = !hidden && semantics.labels && style.text.visible !== false;
8546
+ const showIcon = !hidden && semantics.icons && style.icon.visible !== false;
8547
+ style = {
8548
+ ...withoutVisibility(style),
8549
+ icon: withoutVisibility(style.icon),
8550
+ text: withoutVisibility(style.text)
8551
+ };
8552
+ if (showIcon && style.icon.image === void 0) {
8553
+ style = {
8554
+ ...style,
7714
8555
  icon: {
7715
- optional: !semantics.placement.coupleIconAndLabel,
7716
- padding: semantics.placement.iconPadding,
7717
- size: semantics.minZoom < 17 ? zoom.linear([
7718
- [semantics.minZoom, 0.85],
7719
- [17, 1]
7720
- ]) : 1
7721
- },
7722
- text: poiTextStyle(context, {
7723
- color: categoryColor,
7724
- field: labelField(language, context),
7725
- padding: semantics.placement.textPadding,
7726
- size: semantics.minZoom < 17 ? zoom.linear([
7727
- [semantics.minZoom, 10],
7728
- [17, 12]
7729
- ]) : 12
7730
- })
8556
+ ...style.icon,
8557
+ image: resolvePoiImage(category, context, schema.fields.poiIcon)
8558
+ }
7731
8559
  };
7732
- let style = mergeTileflowDesign(defaults4, categoryStyle);
7733
- const markerStyle = style.marker ? resolveMarkerStyle(style) : void 0;
7734
- const showText = semantics.labels && style.text.visible !== false;
7735
- const showIcon = semantics.icons && style.icon.visible !== false;
7736
- if (showIcon && style.icon.image === void 0) {
7737
- style = {
7738
- ...style,
7739
- icon: {
7740
- ...style.icon,
7741
- image: resolvePoiImage(category, context, schema.fields.poiIcon)
7742
- }
7743
- };
7744
- }
7745
- style = withPoiTextClearance(style, showText && showIcon);
7746
- const symbolStyle2 = withoutMarker2(style);
7747
- if (markerStyle && markerStyle.visible !== false) {
7748
- const base = createPoiLayer({
7749
- category,
7750
- categoryField: schema.fields.poiCategory,
7751
- density: categoryDensity,
7752
- filterRankField: schema.fields.poiFilterRank,
7753
- id: `tileflow-poi-${category}-marker`,
7754
- minZoom: semantics.minZoom,
7755
- sizeRankField: schema.fields.poiSizeRank,
7756
- source,
7757
- sourceLayer: schema.layers.poi
7758
- });
7759
- const markerLayer = applyCircleStyle(
8560
+ }
8561
+ style = withPoiTextClearance(style, showText && showIcon);
8562
+ const symbolStyle2 = withoutMarker2(style);
8563
+ const base = () => ({
8564
+ id: `tileflow-poi-${category}`,
8565
+ type: "symbol",
8566
+ source,
8567
+ "source-layer": schema.layers.poi,
8568
+ minzoom: semantics.minZoom,
8569
+ layout: { "symbol-sort-key": poiSortKey(schema.fields.poiFilterRank, schema.fields.poiSizeRank) }
8570
+ });
8571
+ const parts = [];
8572
+ selection2.register(category, { icon: showIcon, text: showText });
8573
+ if (!hidden && markerStyle && markerStyle.visible !== false) {
8574
+ const markerBase = base();
8575
+ parts.push({
8576
+ category,
8577
+ representation: "marker",
8578
+ layer: applyCircleStyle(
7760
8579
  {
7761
- ...base,
8580
+ ...markerBase,
7762
8581
  type: "circle",
7763
8582
  layout: {
7764
8583
  "circle-sort-key": poiSortKey(schema.fields.poiFilterRank, schema.fields.poiSizeRank)
7765
8584
  }
7766
8585
  },
7767
8586
  markerStyle
7768
- );
7769
- result.push(poiContribution(`${category}.marker`, index * 4, markerLayer));
7770
- }
7771
- if (semantics.placement.coupleIconAndLabel && showText && showIcon) {
7772
- let layer = createPoiLayer({
7773
- category,
7774
- categoryField: schema.fields.poiCategory,
7775
- density: categoryDensity,
7776
- filterRankField: schema.fields.poiFilterRank,
7777
- id: `tileflow-poi-${category}`,
7778
- minZoom: semantics.minZoom,
7779
- sizeRankField: schema.fields.poiSizeRank,
7780
- source,
7781
- sourceLayer: schema.layers.poi
7782
- });
7783
- layer = applySymbolStyle(layer, symbolStyle2);
7784
- result.push(poiContribution(category, index * 4 + 1, layer));
7785
- continue;
7786
- }
7787
- if (showIcon) {
7788
- const layer = applySymbolStyle(
7789
- createPoiLayer({
7790
- category,
7791
- categoryField: schema.fields.poiCategory,
7792
- density: categoryDensity,
7793
- filterRankField: schema.fields.poiFilterRank,
7794
- id: `tileflow-poi-${category}-icon`,
7795
- minZoom: semantics.minZoom,
7796
- sizeRankField: schema.fields.poiSizeRank,
7797
- source,
7798
- sourceLayer: schema.layers.poi
7799
- }),
7800
- { ...symbolStyle2, text: void 0 }
7801
- );
7802
- result.push(poiContribution(`${category}.icon`, index * 4 + 1, layer));
7803
- }
7804
- if (showText) {
7805
- const layer = applySymbolStyle(
7806
- createPoiLayer({
7807
- category,
7808
- categoryField: schema.fields.poiCategory,
7809
- density: categoryDensity,
7810
- filterRankField: schema.fields.poiFilterRank,
7811
- id: `tileflow-poi-${category}-label`,
7812
- minZoom: semantics.minZoom,
7813
- sizeRankField: schema.fields.poiSizeRank,
7814
- source,
7815
- sourceLayer: schema.layers.poi
7816
- }),
7817
- { ...symbolStyle2, icon: void 0 }
7818
- );
7819
- result.push(poiContribution(`${category}.label`, index * 4 + 2, layer));
7820
- }
8587
+ )
8588
+ });
7821
8589
  }
7822
- return result;
8590
+ const combined = coupled && (semantics.placement.order === "importance" ? semantics.icons && semantics.labels && (showIcon || showText) : showIcon && showText);
8591
+ if (combined) {
8592
+ const combinedStyle = {
8593
+ ...symbolStyle2,
8594
+ icon: showIcon ? symbolStyle2.icon : { image: "" },
8595
+ text: showText ? { ...symbolStyle2.text, field: selection2.textField(symbolStyle2.text.field) } : { field: "" }
8596
+ };
8597
+ parts.push({
8598
+ category,
8599
+ representation: "combined",
8600
+ layer: applySymbolStyle(base(), combinedStyle)
8601
+ });
8602
+ return parts;
8603
+ }
8604
+ if (showIcon) {
8605
+ parts.push({
8606
+ category,
8607
+ representation: "icon",
8608
+ layer: applySymbolStyle(base(), { ...symbolStyle2, text: void 0 })
8609
+ });
8610
+ }
8611
+ if (showText) {
8612
+ parts.push({
8613
+ category,
8614
+ representation: "label",
8615
+ layer: applySymbolStyle(base(), { ...symbolStyle2, icon: void 0 })
8616
+ });
8617
+ }
8618
+ return parts;
8619
+ }
8620
+ function createPoiSelection(semantics, context, language) {
8621
+ const { fields } = context.data.schema;
8622
+ const shown = /* @__PURE__ */ new Map();
8623
+ const iconOnlyTypes = [...new Set(semantics.placement.iconOnlyTypes)];
8624
+ const iconOnly = () => iconOnlyTypes.length ? ["match", ["get", fields.poiType], iconOnlyTypes, true, false] : ["literal", false];
8625
+ const inCategories = (categories) => categories.length === 1 ? ["==", ["get", fields.poiCategory], categories[0]] : ["match", ["get", fields.poiCategory], [...categories], true, false];
8626
+ const named = () => [
8627
+ "any",
8628
+ ...labelNameFields(language, context).map((field2) => ["has", field2])
8629
+ ];
8630
+ return {
8631
+ register(category, parts) {
8632
+ shown.set(category, parts);
8633
+ },
8634
+ textField(field2) {
8635
+ if (!iconOnlyTypes.length || field2 === void 0) return field2;
8636
+ return expression([
8637
+ "match",
8638
+ ["get", fields.poiType],
8639
+ iconOnlyTypes,
8640
+ "",
8641
+ fieldValue(field2)
8642
+ ]);
8643
+ },
8644
+ filter(categories, representation) {
8645
+ const filterRank = numericPoiField(fields.poiFilterRank, 6);
8646
+ const sizeRank = numericPoiField(fields.poiSizeRank, 17);
8647
+ const result = [
8648
+ "all",
8649
+ inCategories(categories),
8650
+ ["has", fields.poiFilterRank],
8651
+ [">=", filterRank, 0],
8652
+ ["<=", filterRank, poiRankThreshold(semantics.density)],
8653
+ ["has", fields.poiSizeRank],
8654
+ [">=", sizeRank, 0],
8655
+ ["<=", sizeRank, 16]
8656
+ ];
8657
+ if (!semantics.icons || !semantics.labels) return result;
8658
+ const textless = categories.filter((category) => !shown.get(category)?.text);
8659
+ const iconless = categories.filter((category) => !shown.get(category)?.icon);
8660
+ if (representation === "label") {
8661
+ if (iconless.length === categories.length || !iconOnlyTypes.length) return result;
8662
+ const keep = ["!", iconOnly()];
8663
+ return [...result, iconless.length ? ["any", inCategories(iconless), keep] : keep];
8664
+ }
8665
+ if (textless.length === categories.length) return result;
8666
+ return [
8667
+ ...result,
8668
+ [
8669
+ "any",
8670
+ named(),
8671
+ ...iconOnlyTypes.length ? [iconOnly()] : [],
8672
+ ...textless.length ? [inCategories(textless)] : []
8673
+ ]
8674
+ ];
8675
+ }
8676
+ };
8677
+ }
8678
+ function fieldValue(field2) {
8679
+ return typeof field2 === "object" && field2 !== null && "kind" in field2 && field2.kind === "expression" ? field2.value : field2;
7823
8680
  }
7824
8681
  function resolvePoiImage(category, context, iconField) {
7825
8682
  const role = `poi.${category}`;
@@ -7842,28 +8699,6 @@ function resolveMarkerStyle(style) {
7842
8699
  style.marker
7843
8700
  );
7844
8701
  }
7845
- function createPoiLayer(options) {
7846
- const filterRank = numericPoiField(options.filterRankField, 6);
7847
- const sizeRank = numericPoiField(options.sizeRankField, 17);
7848
- return {
7849
- id: options.id,
7850
- type: "symbol",
7851
- source: options.source,
7852
- "source-layer": options.sourceLayer,
7853
- minzoom: options.minZoom,
7854
- filter: [
7855
- "all",
7856
- ["==", ["get", options.categoryField], options.category],
7857
- ["has", options.filterRankField],
7858
- [">=", filterRank, 0],
7859
- ["<=", filterRank, poiRankThreshold(options.density)],
7860
- ["has", options.sizeRankField],
7861
- [">=", sizeRank, 0],
7862
- ["<=", sizeRank, 16]
7863
- ],
7864
- layout: { "symbol-sort-key": poiSortKey(options.filterRankField, options.sizeRankField) }
7865
- };
7866
- }
7867
8702
  function poiRankThreshold(density) {
7868
8703
  return ["+", ["step", ["zoom"], 0, 16, 1, 17, 2], density];
7869
8704
  }
@@ -7880,7 +8715,7 @@ function poiContribution(target, localOrder, layer) {
7880
8715
  localOrder: 1e3 + localOrder,
7881
8716
  owner: "poi",
7882
8717
  slot: "symbols",
7883
- target: `poi.${target}`
8718
+ target: target ? `poi.${target}` : "poi"
7884
8719
  };
7885
8720
  }
7886
8721
  function poiTextStyle(context, overrides) {
@@ -7890,8 +8725,7 @@ function poiTextStyle(context, overrides) {
7890
8725
  color: context.colors.poi.label,
7891
8726
  ...typographyTextStyle(context.typography.poi),
7892
8727
  haloColor: context.colors.poi.halo,
7893
- haloWidth: 1,
7894
- optional: true
8728
+ haloWidth: 1
7895
8729
  },
7896
8730
  overrides
7897
8731
  );
@@ -7914,6 +8748,10 @@ function withoutMarker2(style) {
7914
8748
  delete result.marker;
7915
8749
  return result;
7916
8750
  }
8751
+ function withoutVisibility(value) {
8752
+ const { visible: _visible, ...rest } = value;
8753
+ return rest;
8754
+ }
7917
8755
 
7918
8756
  // src/modules/roads/compiler.ts
7919
8757
  init_values();
@@ -8867,9 +9705,10 @@ function compileRoundabouts(request, context, contributions) {
8867
9705
  contributions.push({
8868
9706
  kind: "layer",
8869
9707
  layer: applyCircleStyle({ ...base, id: "tileflow-road-circular-casing" }, config.casing),
8870
- localOrder: 10,
9708
+ localOrder: 900,
8871
9709
  owner: "roads",
8872
- slot: "transport-symbols",
9710
+ // Approach fills must cover the circular casing where the roads meet.
9711
+ slot: "transport-surface-casing",
8873
9712
  target: "roads.roundabouts.casing"
8874
9713
  });
8875
9714
  }
@@ -8877,9 +9716,9 @@ function compileRoundabouts(request, context, contributions) {
8877
9716
  contributions.push({
8878
9717
  kind: "layer",
8879
9718
  layer: applyCircleStyle({ ...base, id: "tileflow-road-circular-fill" }, config.fill),
8880
- localOrder: 20,
9719
+ localOrder: 900,
8881
9720
  owner: "roads",
8882
- slot: "transport-symbols",
9721
+ slot: "transport-surface-fill",
8883
9722
  target: "roads.roundabouts.fill"
8884
9723
  });
8885
9724
  }
@@ -8944,7 +9783,7 @@ var circularRoadBorderTotalWidth = 1;
8944
9783
  function circularRoadInnerRadius(fields, casing) {
8945
9784
  const values = circularRoadValues(fields);
8946
9785
  const stops = [];
8947
- for (let level = 15; level <= 22; level += 1) {
9786
+ for (let level = 15; level <= 24; level += 1) {
8948
9787
  const centerlineRadius = level === 15 ? values.radiusAtZoom15 : ["*", values.radiusAtZoom15, 2 ** (level - 15)];
8949
9788
  const physicalInnerRadius = [
8950
9789
  "*",
@@ -8961,13 +9800,13 @@ function circularRoadInnerRadius(fields, casing) {
8961
9800
  casing ? ["-", innerRadius, circularRoadBorderTotalWidth / 2] : innerRadius
8962
9801
  ]);
8963
9802
  }
8964
- return ["interpolate", ["linear"], ["zoom"], ...stops];
9803
+ return ["interpolate", ["exponential", 2], ["zoom"], ...stops];
8965
9804
  }
8966
9805
  function circularRoadStrokeWidth(fields, casing) {
8967
9806
  const values = circularRoadValues(fields);
8968
9807
  const baseWidth = circularRoadBaseWidth(fields.class);
8969
9808
  const stops = [];
8970
- for (let level = 15; level <= 22; level += 1) {
9809
+ for (let level = 15; level <= 24; level += 1) {
8971
9810
  const centerlineRadius = level === 15 ? values.radiusAtZoom15 : ["*", values.radiusAtZoom15, 2 ** (level - 15)];
8972
9811
  const physicalWidth = [
8973
9812
  "*",
@@ -8982,7 +9821,7 @@ function circularRoadStrokeWidth(fields, casing) {
8982
9821
  casing ? ["+", fallbackWidth, circularRoadBorderTotalWidth] : fallbackWidth
8983
9822
  ]);
8984
9823
  }
8985
- return ["interpolate", ["linear"], ["zoom"], ...stops];
9824
+ return ["interpolate", ["exponential", 2], ["zoom"], ...stops];
8986
9825
  }
8987
9826
  function circularRoadBaseWidth(classField) {
8988
9827
  return [
@@ -9146,6 +9985,10 @@ function applyRoadTreatments(base, treatments, structure, phase, fallbackColor)
9146
9985
  return value === void 0 ? [] : [{ condition, resolve: () => expressionOutput(value) }];
9147
9986
  });
9148
9987
  if (branches.length > 0) {
9988
+ if (property === "dash" && isSolidRoadDash(result[property] ?? treatmentPaintDefaults.dash) && branches.every(({ resolve }) => isSolidRoadDash(resolve()))) {
9989
+ delete result[property];
9990
+ continue;
9991
+ }
9149
9992
  result[property] = conditionalStyleValue(
9150
9993
  result[property],
9151
9994
  branches,
@@ -9162,9 +10005,21 @@ function applyRoadTreatments(base, treatments, structure, phase, fallbackColor)
9162
10005
  widthScales,
9163
10006
  treatmentPaintDefaults.width
9164
10007
  );
10008
+ if (result.gapWidth !== void 0 && result.gapWidth !== 0) {
10009
+ result.gapWidth = conditionalWidthScaleValue(
10010
+ result.gapWidth,
10011
+ widthScales,
10012
+ treatmentPaintDefaults.gapWidth
10013
+ );
10014
+ }
9165
10015
  }
9166
10016
  return result;
9167
10017
  }
10018
+ function isSolidRoadDash(value) {
10019
+ const output = expressionOutput(value);
10020
+ const dash = Array.isArray(output) && output[0] === "literal" ? output[1] : output;
10021
+ return Array.isArray(dash) && dash.length === 2 && dash[0] === 1 && dash[1] === 0;
10022
+ }
9168
10023
  function roadTreatmentPhaseConditions(treatments, structure, phase) {
9169
10024
  return treatments.flatMap(
9170
10025
  ({ condition, style }) => style[structure]?.[phase] === void 0 ? [] : [condition]
@@ -9249,10 +10104,10 @@ function isExpressionOutput(value) {
9249
10104
  }
9250
10105
  function rewriteZoomOutputs(value, rewrite) {
9251
10106
  if (!Array.isArray(value)) return rewrite(value);
9252
- if (value[0] === "interpolate" && isZoomInput3(value[2])) {
10107
+ if (value[0] === "interpolate" && isZoomInput4(value[2])) {
9253
10108
  return value.map((entry, index) => index >= 4 && index % 2 === 0 ? rewrite(entry) : entry);
9254
10109
  }
9255
- if (value[0] === "step" && isZoomInput3(value[1])) {
10110
+ if (value[0] === "step" && isZoomInput4(value[1])) {
9256
10111
  return value.map(
9257
10112
  (entry, index) => index === 2 || index >= 4 && index % 2 === 0 ? rewrite(entry) : entry
9258
10113
  );
@@ -9262,7 +10117,7 @@ function rewriteZoomOutputs(value, rewrite) {
9262
10117
  function expressionOutput(value) {
9263
10118
  return Array.isArray(value) && typeof value[0] !== "string" ? ["literal", value] : value;
9264
10119
  }
9265
- function isZoomInput3(value) {
10120
+ function isZoomInput4(value) {
9266
10121
  return Array.isArray(value) && value.length === 1 && value[0] === "zoom";
9267
10122
  }
9268
10123
  function restrictedAccessFilter(field2) {
@@ -9643,7 +10498,7 @@ var waterwayClasses = {
9643
10498
  river: ["river"],
9644
10499
  stream: ["stream"]
9645
10500
  };
9646
- function compileWater(request, context) {
10501
+ function compileWater(request, context, language = "auto") {
9647
10502
  const config = mergeTileflowDesign(
9648
10503
  {
9649
10504
  type: "water",
@@ -9795,8 +10650,11 @@ function compileWater(request, context) {
9795
10650
  appendBathymetryRelief(contributions, bathymetryProduct.relief, context);
9796
10651
  }
9797
10652
  const productContours = bathymetryProduct?.contours;
10653
+ const nativeContours = sidecarBathymetry && bathymetryProduct?.vectorLayers?.contours === true;
10654
+ const contourLayer = nativeContours ? tileflowBathymetryV1Schema.layers.contours : bathymetryLayer;
10655
+ const contourDepthField = nativeContours ? tileflowBathymetryV1Schema.fields.depth : bathymetryDepthField;
9798
10656
  const contourRequest = productContours === false ? void 0 : productContours === void 0 ? request?.bathymetryContours : mergeTileflowDesign(productContours, request?.bathymetryContours);
9799
- if (contourRequest !== void 0 && bathymetryLayer && bathymetryDepthField) {
10657
+ if (contourRequest !== void 0 && contourLayer && contourDepthField) {
9800
10658
  const bathymetryContours = mergeTileflowDesign(
9801
10659
  {
9802
10660
  color: context.colors.hydro.label,
@@ -9819,12 +10677,12 @@ function compileWater(request, context) {
9819
10677
  id: "tileflow-bathymetry-contours",
9820
10678
  type: "line",
9821
10679
  source: bathymetrySource,
9822
- "source-layer": bathymetryLayer,
10680
+ "source-layer": contourLayer,
9823
10681
  filter: [
9824
10682
  "all",
9825
- ["==", ["geometry-type"], "Polygon"],
9826
- ["has", bathymetryDepthField],
9827
- ["<", ["to-number", ["get", bathymetryDepthField], 0], 0]
10683
+ ["==", ["geometry-type"], nativeContours ? "LineString" : "Polygon"],
10684
+ ["has", contourDepthField],
10685
+ ["<", ["to-number", ["get", contourDepthField], 0], 0]
9828
10686
  ]
9829
10687
  },
9830
10688
  bathymetryContours
@@ -9838,19 +10696,19 @@ function compileWater(request, context) {
9838
10696
  }
9839
10697
  const productLabels = bathymetryProduct?.labels;
9840
10698
  const labelRequest = productLabels === false ? void 0 : productLabels === void 0 ? request?.bathymetryLabels : mergeTileflowDesign(productLabels, request?.bathymetryLabels);
9841
- if (labelRequest !== void 0 && bathymetryLayer && bathymetryDepthField) {
10699
+ if (labelRequest !== void 0 && contourLayer && contourDepthField) {
9842
10700
  const bathymetryLabels = mergeTileflowDesign(
9843
10701
  {
9844
10702
  maxZoom: 10,
9845
10703
  minZoom: 3,
9846
- placement: "point",
10704
+ placement: nativeContours ? "line" : "point",
9847
10705
  priority: 5,
9848
10706
  text: {
9849
10707
  allowOverlap: false,
9850
10708
  color: context.colors.hydro.label,
9851
10709
  field: expression([
9852
10710
  "to-string",
9853
- ["abs", ["to-number", ["get", bathymetryDepthField], 0]]
10711
+ ["abs", ["to-number", ["get", contourDepthField], 0]]
9854
10712
  ]),
9855
10713
  ...typographyTextStyle(context.typography.water),
9856
10714
  haloColor: context.colors.hydro.water,
@@ -9871,8 +10729,13 @@ function compileWater(request, context) {
9871
10729
  id: "tileflow-bathymetry-labels",
9872
10730
  type: "symbol",
9873
10731
  source: bathymetrySource,
9874
- "source-layer": bathymetryLayer,
9875
- filter: ["all", ["==", ["geometry-type"], "Polygon"], ["has", bathymetryDepthField]]
10732
+ "source-layer": contourLayer,
10733
+ filter: [
10734
+ "all",
10735
+ ["==", ["geometry-type"], nativeContours ? "LineString" : "Polygon"],
10736
+ ["has", contourDepthField],
10737
+ ...nativeContours ? [["<", ["to-number", ["get", contourDepthField], 0], 0]] : []
10738
+ ]
9876
10739
  },
9877
10740
  bathymetryLabels
9878
10741
  ),
@@ -9883,6 +10746,37 @@ function compileWater(request, context) {
9883
10746
  });
9884
10747
  }
9885
10748
  }
10749
+ if (sidecarBathymetry) {
10750
+ const { layers: marineLayers } = tileflowBathymetryV1Schema;
10751
+ const landforms2 = bathymetryProduct?.vectorLayers?.landforms;
10752
+ const waterNames = bathymetryProduct?.vectorLayers?.waterNames;
10753
+ if (landforms2) {
10754
+ appendBathymetryNames(contributions, {
10755
+ availability: landforms2,
10756
+ context,
10757
+ language,
10758
+ localOrder: -300,
10759
+ source: sidecarBathymetry.sourceId,
10760
+ sourceLayer: marineLayers.landforms,
10761
+ style: config.bathymetryLandforms,
10762
+ target: "water.bathymetryLandforms",
10763
+ id: "tileflow-bathymetry-landforms"
10764
+ });
10765
+ }
10766
+ if (waterNames) {
10767
+ appendBathymetryNames(contributions, {
10768
+ availability: waterNames,
10769
+ context,
10770
+ language,
10771
+ localOrder: -150,
10772
+ source: sidecarBathymetry.sourceId,
10773
+ sourceLayer: marineLayers.waterNames,
10774
+ style: config.bathymetryWaterNames,
10775
+ target: "water.bathymetryWaterNames",
10776
+ id: "tileflow-bathymetry-water-names"
10777
+ });
10778
+ }
10779
+ }
9886
10780
  let localOrder = 10;
9887
10781
  for (const [name, classes] of Object.entries(waterwayClasses)) {
9888
10782
  const style = config.waterways?.[name];
@@ -9946,6 +10840,99 @@ function compileWater(request, context) {
9946
10840
  }
9947
10841
  return contributions;
9948
10842
  }
10843
+ function appendBathymetryNames(contributions, options) {
10844
+ const { context, language } = options;
10845
+ const { fields } = tileflowBathymetryV1Schema;
10846
+ const localName = ["to-string", ["coalesce", ["get", fields.name], ""]];
10847
+ const name = language === "auto" || language === "local" ? localName : [
10848
+ "case",
10849
+ ["!=", ["to-string", ["coalesce", ["get", `name:${language}`], ""]], ""],
10850
+ ["to-string", ["get", `name:${language}`]],
10851
+ localName
10852
+ ];
10853
+ const style = mergeTileflowDesign(
10854
+ {
10855
+ minZoom: 0,
10856
+ placement: "point",
10857
+ priority: expression(["to-number", ["get", fields.sortKey], 0]),
10858
+ priorityOrder: "lower-first",
10859
+ text: {
10860
+ ...typographyTextStyle(context.typography.water),
10861
+ allowOverlap: false,
10862
+ ignorePlacement: false,
10863
+ color: context.colors.hydro.label,
10864
+ field: expression(name),
10865
+ haloColor: context.colors.hydro.water,
10866
+ haloWidth: 1,
10867
+ optional: false,
10868
+ padding: 12,
10869
+ size: 11
10870
+ }
10871
+ },
10872
+ options.style
10873
+ );
10874
+ if (style.visible === false || style.text?.visible === false) return;
10875
+ const layer = applySymbolStyle(
10876
+ {
10877
+ id: options.id,
10878
+ type: "symbol",
10879
+ source: options.source,
10880
+ "source-layer": options.sourceLayer,
10881
+ filter: [
10882
+ "all",
10883
+ ["match", ["geometry-type"], ["Point", "LineString", "Polygon"], true, false],
10884
+ ["!=", name, ""]
10885
+ ]
10886
+ },
10887
+ style
10888
+ );
10889
+ const sourceMinimum = ["to-number", ["coalesce", ["get", fields.minZoom], 0], 0];
10890
+ const sourceMaximum = ["to-number", ["coalesce", ["get", fields.maxZoom], 24], 24];
10891
+ const baseFilter = layer.filter;
10892
+ const append = (result, target, order = 0) => {
10893
+ contributions.push({
10894
+ kind: "layer",
10895
+ layer: result,
10896
+ localOrder: options.localOrder + order,
10897
+ owner: "water",
10898
+ slot: "symbols",
10899
+ target
10900
+ });
10901
+ };
10902
+ if (options.availability === true) {
10903
+ append(
10904
+ {
10905
+ ...layer,
10906
+ filter: [...baseFilter, [">=", ["zoom"], sourceMinimum], ["<", ["zoom"], sourceMaximum]]
10907
+ },
10908
+ options.target
10909
+ );
10910
+ return;
10911
+ }
10912
+ const ranges = [...options.availability.zoomRanges].sort(
10913
+ (left, right) => left.minZoom - right.minZoom || left.maxZoom - right.maxZoom
10914
+ );
10915
+ for (const [index, range2] of ranges.entries()) {
10916
+ const minzoom = Math.max(Number(layer.minzoom ?? 0), range2.minZoom);
10917
+ const maxzoom = Math.min(Number(layer.maxzoom ?? 24), range2.maxZoom);
10918
+ if (minzoom >= maxzoom) continue;
10919
+ append(
10920
+ {
10921
+ ...layer,
10922
+ id: `${options.id}-cohort-${index}`,
10923
+ minzoom,
10924
+ maxzoom,
10925
+ filter: [
10926
+ ...baseFilter,
10927
+ ["==", sourceMinimum, range2.minZoom],
10928
+ ["==", sourceMaximum, range2.maxZoom]
10929
+ ]
10930
+ },
10931
+ `${options.target}.cohort${index}`,
10932
+ index
10933
+ );
10934
+ }
10935
+ }
9949
10936
  function appendBathymetryRelief(contributions, relief, context) {
9950
10937
  const { sourceId, style } = relief;
9951
10938
  const opacity = resolvedNumber(style.opacity, 0.22, "bathymetry relief opacity");
@@ -10154,12 +11141,6 @@ var tileflowSemanticDomainRegistry = Object.freeze([
10154
11141
  dependencies: {},
10155
11142
  name: "land"
10156
11143
  }),
10157
- defineDomain({
10158
- compile: ({ context, module }) => compileWater(module, context),
10159
- defaultModule: water(),
10160
- dependencies: {},
10161
- name: "water"
10162
- }),
10163
11144
  defineDomain({
10164
11145
  compile: ({ context, module }) => compileNautical(module, context),
10165
11146
  defaultModule: nautical(),
@@ -10248,6 +11229,12 @@ var tileflowSemanticDomainRegistry = Object.freeze([
10248
11229
  provides: ["language"],
10249
11230
  resolveServices: ({ module }) => ({ language: resolveLabels(module).language })
10250
11231
  }),
11232
+ defineDomain({
11233
+ compile: ({ context, dependencies, module }) => compileWater(module, context, dependencies.service("language")),
11234
+ defaultModule: water(),
11235
+ dependencies: { services: ["language"] },
11236
+ name: "water"
11237
+ }),
10251
11238
  defineDomain({
10252
11239
  compile: ({ context, dependencies, module }) => compileLandforms(module, dependencies.service("language"), context),
10253
11240
  defaultModule: landforms(),
@@ -10366,7 +11353,7 @@ function createTileflowCompilerProvenance(owner, slot, target) {
10366
11353
  return [{ operations: [], owner, slot, target }];
10367
11354
  }
10368
11355
  function readTileflowCompilerProvenance(layer) {
10369
- const metadata = asRecord3(layer.metadata);
11356
+ const metadata = asRecord4(layer.metadata);
10370
11357
  const raw = metadata[tileflowCompilerProvenanceMetadataKey];
10371
11358
  if (Array.isArray(raw)) {
10372
11359
  const parsed = raw.flatMap((value) => {
@@ -10394,7 +11381,7 @@ function createTileflowStyleInspection(map, theme, layers) {
10394
11381
  };
10395
11382
  }
10396
11383
  function parseContribution(value) {
10397
- const input = asRecord3(value);
11384
+ const input = asRecord4(value);
10398
11385
  const owner = requireLayerDomain(input.owner);
10399
11386
  const slot = requireLayerSlot(input.slot);
10400
11387
  const target = input.target;
@@ -10408,7 +11395,7 @@ function parseContribution(value) {
10408
11395
  return { operations: operations2, owner, slot, target };
10409
11396
  }
10410
11397
  function parseRenderOperation(value) {
10411
- const input = asRecord3(value);
11398
+ const input = asRecord4(value);
10412
11399
  const owner = requireLayerDomain(input.owner);
10413
11400
  const target = input.target;
10414
11401
  if (input.kind !== "pass" && input.kind !== "refinement" || !owner || typeof target !== "string" || !tileflowSemanticTargetPattern.test(target)) {
@@ -10422,7 +11409,7 @@ function requireLayerDomain(value) {
10422
11409
  function requireLayerSlot(value) {
10423
11410
  return typeof value === "string" && tileflowLayerSlots.includes(value) ? value : void 0;
10424
11411
  }
10425
- function asRecord3(value) {
11412
+ function asRecord4(value) {
10426
11413
  return value && typeof value === "object" && !Array.isArray(value) ? value : {};
10427
11414
  }
10428
11415
 
@@ -10779,7 +11766,7 @@ function not(value) {
10779
11766
  function has(reference) {
10780
11767
  return make(["has", reference]);
10781
11768
  }
10782
- function match(input, branches, fallback) {
11769
+ function match2(input, branches, fallback) {
10783
11770
  validateBranchCount(branches.length, "expr.match");
10784
11771
  validateMatchLabels(branches);
10785
11772
  return make([
@@ -10877,7 +11864,7 @@ function limitError(message) {
10877
11864
  return new Error(site ? `${message} Called at ${site}.` : message);
10878
11865
  }
10879
11866
  function authoringCallSite(stack) {
10880
- const locations = (stack ?? "").split("\n").slice(1).map((line) => /\(?([^()\s]+?):(\d+):(\d+)\)?$/.exec(line.trim())).filter((match2) => match2 !== null).map(([, file, line, column]) => ({ file: file.replace(/^file:\/\//, ""), line, column }));
11867
+ const locations = (stack ?? "").split("\n").slice(1).map((line) => /\(?([^()\s]+?):(\d+):(\d+)\)?$/.exec(line.trim())).filter((match3) => match3 !== null).map(([, file, line, column]) => ({ file: file.replace(/^file:\/\//, ""), line, column }));
10881
11868
  const own = locations[0]?.file;
10882
11869
  const site = locations.find(({ file }) => file !== own && !file.startsWith("node:"));
10883
11870
  return site ? `${site.file}:${site.line}:${site.column}` : void 0;
@@ -11262,7 +12249,7 @@ var expr = Object.freeze({
11262
12249
  literal,
11263
12250
  lt: (left, right) => compare("<", left, right),
11264
12251
  lte: (left, right) => compare("<=", left, right),
11265
- match,
12252
+ match: match2,
11266
12253
  max: maximum,
11267
12254
  min: minimum,
11268
12255
  modulo,
@@ -11286,6 +12273,12 @@ var tileflowSemanticFieldNames = Object.freeze(
11286
12273
  var tileflowSemanticLayerNames = Object.freeze(
11287
12274
  Object.keys(completeSemanticDataContract.layers).sort(compareCodeUnits5)
11288
12275
  );
12276
+ var auxiliaryFieldBindings = Object.freeze({
12277
+ bathymetryContourDepth: tileflowBathymetryV1Schema.fields.depth
12278
+ });
12279
+ var tileflowSemanticExpressionFieldNames = Object.freeze(
12280
+ [...tileflowSemanticFieldNames, ...Object.keys(auxiliaryFieldBindings)].sort(compareCodeUnits5)
12281
+ );
11289
12282
  function field(name) {
11290
12283
  return Object.freeze({ kind: "tileflow-data-field", name });
11291
12284
  }
@@ -11317,6 +12310,9 @@ function bindSemanticReferences(value, data) {
11317
12310
  }
11318
12311
  function bindSemanticValue(value, schema, sourceId) {
11319
12312
  if (isDataFieldReference2(value)) {
12313
+ if (Object.hasOwn(auxiliaryFieldBindings, value.name)) {
12314
+ return auxiliaryFieldBindings[value.name];
12315
+ }
11320
12316
  const binding = schema.fields[value.name];
11321
12317
  if (!binding) throw new Error(`Tileflow data schema does not provide field ${value.name}.`);
11322
12318
  return binding;
@@ -11328,21 +12324,21 @@ function bindSemanticValue(value, schema, sourceId) {
11328
12324
  }
11329
12325
  if (isDataSourceReference(value)) return sourceId;
11330
12326
  if (Array.isArray(value)) return value.map((item) => bindSemanticValue(item, schema, sourceId));
11331
- if (!isRecord8(value)) return value;
12327
+ if (!isRecord7(value)) return value;
11332
12328
  return Object.fromEntries(
11333
12329
  Object.entries(value).map(([key, item]) => [key, bindSemanticValue(item, schema, sourceId)])
11334
12330
  );
11335
12331
  }
11336
12332
  function isDataFieldReference2(value) {
11337
- return isRecord8(value) && value.kind === "tileflow-data-field" && typeof value.name === "string";
12333
+ return isRecord7(value) && value.kind === "tileflow-data-field" && typeof value.name === "string";
11338
12334
  }
11339
12335
  function isDataLayerReference(value) {
11340
- return isRecord8(value) && value.kind === "tileflow-data-layer" && typeof value.name === "string";
12336
+ return isRecord7(value) && value.kind === "tileflow-data-layer" && typeof value.name === "string";
11341
12337
  }
11342
12338
  function isDataSourceReference(value) {
11343
- return isRecord8(value) && value.kind === "tileflow-data-source" && value.name === "primary";
12339
+ return isRecord7(value) && value.kind === "tileflow-data-source" && value.name === "primary";
11344
12340
  }
11345
- function isRecord8(value) {
12341
+ function isRecord7(value) {
11346
12342
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
11347
12343
  }
11348
12344
  function compareCodeUnits5(left, right) {
@@ -11446,8 +12442,8 @@ function createTileflowLayerTemplateIR(layer, semanticKey) {
11446
12442
  renderer: type,
11447
12443
  ...filter === void 0 ? {} : { selector: cloneJson20(filter) },
11448
12444
  style: Object.freeze({
11449
- ...isRecord9(layout) ? { placement: Object.freeze(cloneJson20(layout)) } : {},
11450
- ...isRecord9(paint) ? { appearance: Object.freeze(cloneJson20(paint)) } : {}
12445
+ ...isRecord8(layout) ? { placement: Object.freeze(cloneJson20(layout)) } : {},
12446
+ ...isRecord8(paint) ? { appearance: Object.freeze(cloneJson20(paint)) } : {}
11451
12447
  })
11452
12448
  });
11453
12449
  }
@@ -11521,72 +12517,77 @@ function emitLayer(family, resolvePhysicalId) {
11521
12517
  function physicalLayerIdForSemanticKey(semanticKey) {
11522
12518
  const exact = exactPhysicalLayerIds[semanticKey];
11523
12519
  if (exact) return exact;
11524
- let match2 = /^([A-Za-z0-9_-]+)\.render\.([A-Za-z0-9_-]+(?:\.[A-Za-z0-9_-]+)*)$/u.exec(
12520
+ let match3 = /^([A-Za-z0-9_-]+)\.render\.([A-Za-z0-9_-]+(?:\.[A-Za-z0-9_-]+)*)$/u.exec(
11525
12521
  semanticKey
11526
12522
  );
11527
- if (match2) return `tileflow-${match2[1]}-render-${match2[2].replaceAll(".", "-")}`;
11528
- match2 = /^roads\.classes\.([^.]+)\.(tunnel|surface|bridge)\.(shadow|casing|fill|hatch)$/u.exec(
12523
+ if (match3) return `tileflow-${match3[1]}-render-${match3[2].replaceAll(".", "-")}`;
12524
+ match3 = /^roads\.classes\.([^.]+)\.(tunnel|surface|bridge)\.(shadow|casing|fill|hatch)$/u.exec(
11529
12525
  semanticKey
11530
12526
  );
11531
- if (match2) return `tileflow-road-${match2[2]}-${match2[1]}-${match2[3]}`;
11532
- match2 = /^roads\.cohorts\.(tunnel|surface|bridge)\.([^.]+)\.(shadow|casing|fill)$/u.exec(
12527
+ if (match3) return `tileflow-road-${match3[2]}-${match3[1]}-${match3[3]}`;
12528
+ match3 = /^roads\.cohorts\.(tunnel|surface|bridge)\.([^.]+)\.(shadow|casing|fill)$/u.exec(
11533
12529
  semanticKey
11534
12530
  );
11535
- if (match2) return `tileflow-road-${match2[1]}-highzoom-${match2[2]}-${match2[3]}`;
11536
- match2 = /^roads\.cohorts\.(tunnel|surface|bridge)\.hatch$/u.exec(semanticKey);
11537
- if (match2) return `tileflow-road-${match2[1]}-hatch`;
11538
- match2 = /^roads\.areas\.(road|pedestrian|pier)\.(fill|outline)$/u.exec(semanticKey);
11539
- if (match2) {
11540
- const base = match2[1] === "road" ? "tileflow-road-area" : `tileflow-road-${match2[1]}-area`;
11541
- return match2[2] === "fill" ? base : `${base}-outline`;
11542
- }
11543
- match2 = /^land\.(landcover|landuse)\.([^.]+)\.(fill|outline)$/u.exec(semanticKey);
11544
- if (match2) {
11545
- const base = `tileflow-${match2[1]}-${match2[2]}`;
11546
- return match2[3] === "fill" ? base : `${base}-outline`;
11547
- }
11548
- match2 = /^land\.compatibility\.legacyPark\.(fill|outline)$/u.exec(semanticKey);
11549
- if (match2) {
11550
- return match2[1] === "fill" ? "tileflow-landcover-legacy-park" : "tileflow-landcover-legacy-park-outline";
11551
- }
11552
- match2 = /^land\.cohorts\.(landcover|landuse)(?:\.cohort(\d+))?$/u.exec(semanticKey);
11553
- if (match2) return `tileflow-${match2[1]}${match2[2] === void 0 ? "" : `-${match2[2]}`}`;
11554
- match2 = /^water\.(intermittent\.)?bodies\.(fill|outline)$/u.exec(semanticKey);
11555
- if (match2) {
11556
- const base = `tileflow-water${match2[1] ? "-intermittent" : ""}`;
11557
- return match2[2] === "fill" ? base : `${base}-outline`;
11558
- }
11559
- match2 = /^water\.(intermittent\.)?waterways\.([^.]+)$/u.exec(semanticKey);
11560
- if (match2) return `tileflow-waterway-${match2[2]}${match2[1] ? "-intermittent" : ""}`;
11561
- match2 = /^buildings\.(businessCorridor|flat)\.(fill|outline)$/u.exec(semanticKey);
11562
- if (match2) {
11563
- const base = match2[1] === "businessCorridor" ? "tileflow-business-corridor" : "tileflow-buildings-fill";
11564
- return match2[2] === "fill" ? base : `${base}-outline`;
11565
- }
11566
- match2 = /^aeroways\.area\.(fill|outline)$/u.exec(semanticKey);
11567
- if (match2) return match2[1] === "fill" ? "tileflow-aeroway-area" : "tileflow-aeroway-area-outline";
11568
- match2 = /^aeroways\.(taxiway|runway)\.(shadow|casing|fill)$/u.exec(semanticKey);
11569
- if (match2) return `tileflow-aeroway-${match2[1]}-${match2[2]}`;
11570
- match2 = /^transit\.([A-Za-z0-9_-]+)(?:\.(tunnel|surface|bridge))?$/u.exec(semanticKey);
11571
- if (match2) return `tileflow-transit-${match2[1]}${match2[2] ? `-${match2[2]}` : ""}`;
11572
- match2 = /^boundaries\.([A-Za-z0-9_-]+(?:\.[A-Za-z0-9_-]+)*)$/u.exec(semanticKey);
11573
- if (match2) return `tileflow-boundary-${match2[1].replaceAll(".", "-")}`;
11574
- match2 = /^labels\.places\.([^.]+)$/u.exec(semanticKey);
11575
- if (match2) return `tileflow-label-place-${match2[1]}`;
11576
- match2 = /^labels\.roads\.([^.]+)$/u.exec(semanticKey);
11577
- if (match2) return `tileflow-label-road-${match2[1]}`;
11578
- match2 = /^labels\.shields\.([^.]+)$/u.exec(semanticKey);
11579
- if (match2) return `tileflow-label-road-shield-${match2[1]}`;
11580
- match2 = /^labels\.water\.([^.]+)$/u.exec(semanticKey);
11581
- if (match2) return `tileflow-label-water-${match2[1]}`;
11582
- match2 = /^labels\.cohorts\.roads\.(major|local)$/u.exec(semanticKey);
11583
- if (match2) return `tileflow-label-road-${match2[1]}`;
11584
- match2 = /^labels\.cohorts\.roads\.cohort(\d+)$/u.exec(semanticKey);
11585
- if (match2) return `tileflow-label-road-cohort-${match2[1]}`;
11586
- match2 = /^landforms\.classes\.([^.]+)$/u.exec(semanticKey);
11587
- if (match2) return `tileflow-landform-${match2[1]}`;
11588
- match2 = /^poi\.([A-Za-z0-9_-]+(?:\.[A-Za-z0-9_-]+)*)$/u.exec(semanticKey);
11589
- if (match2) return `tileflow-poi-${match2[1].replaceAll(".", "-")}`;
12531
+ if (match3) return `tileflow-road-${match3[1]}-highzoom-${match3[2]}-${match3[3]}`;
12532
+ match3 = /^roads\.cohorts\.(tunnel|surface|bridge)\.hatch$/u.exec(semanticKey);
12533
+ if (match3) return `tileflow-road-${match3[1]}-hatch`;
12534
+ match3 = /^roads\.areas\.(road|pedestrian|pier)\.(fill|outline)$/u.exec(semanticKey);
12535
+ if (match3) {
12536
+ const base = match3[1] === "road" ? "tileflow-road-area" : `tileflow-road-${match3[1]}-area`;
12537
+ return match3[2] === "fill" ? base : `${base}-outline`;
12538
+ }
12539
+ match3 = /^land\.(landcover|landuse)\.([^.]+)\.(fill|outline)$/u.exec(semanticKey);
12540
+ if (match3) {
12541
+ const base = `tileflow-${match3[1]}-${match3[2]}`;
12542
+ return match3[3] === "fill" ? base : `${base}-outline`;
12543
+ }
12544
+ match3 = /^land\.compatibility\.legacyPark\.(fill|outline)$/u.exec(semanticKey);
12545
+ if (match3) {
12546
+ return match3[1] === "fill" ? "tileflow-landcover-legacy-park" : "tileflow-landcover-legacy-park-outline";
12547
+ }
12548
+ match3 = /^land\.cohorts\.(landcover|landuse)(?:\.cohort(\d+))?$/u.exec(semanticKey);
12549
+ if (match3) return `tileflow-${match3[1]}${match3[2] === void 0 ? "" : `-${match3[2]}`}`;
12550
+ match3 = /^water\.(intermittent\.)?bodies\.(fill|outline)$/u.exec(semanticKey);
12551
+ if (match3) {
12552
+ const base = `tileflow-water${match3[1] ? "-intermittent" : ""}`;
12553
+ return match3[2] === "fill" ? base : `${base}-outline`;
12554
+ }
12555
+ match3 = /^water\.(intermittent\.)?waterways\.([^.]+)$/u.exec(semanticKey);
12556
+ if (match3) return `tileflow-waterway-${match3[2]}${match3[1] ? "-intermittent" : ""}`;
12557
+ match3 = /^buildings\.(businessCorridor|flat)\.(fill|outline)$/u.exec(semanticKey);
12558
+ if (match3) {
12559
+ const base = match3[1] === "businessCorridor" ? "tileflow-business-corridor" : "tileflow-buildings-fill";
12560
+ return match3[2] === "fill" ? base : `${base}-outline`;
12561
+ }
12562
+ match3 = /^aeroways\.area\.(fill|outline)$/u.exec(semanticKey);
12563
+ if (match3) return match3[1] === "fill" ? "tileflow-aeroway-area" : "tileflow-aeroway-area-outline";
12564
+ match3 = /^aeroways\.(taxiway|runway)\.(shadow|casing|fill)$/u.exec(semanticKey);
12565
+ if (match3) return `tileflow-aeroway-${match3[1]}-${match3[2]}`;
12566
+ match3 = /^transit\.([A-Za-z0-9_-]+)(?:\.(tunnel|surface|bridge))?$/u.exec(semanticKey);
12567
+ if (match3) return `tileflow-transit-${match3[1]}${match3[2] ? `-${match3[2]}` : ""}`;
12568
+ match3 = /^boundaries\.([A-Za-z0-9_-]+(?:\.[A-Za-z0-9_-]+)*)$/u.exec(semanticKey);
12569
+ if (match3) return `tileflow-boundary-${match3[1].replaceAll(".", "-")}`;
12570
+ match3 = /^labels\.places\.([^.]+)$/u.exec(semanticKey);
12571
+ if (match3) return `tileflow-label-place-${match3[1]}`;
12572
+ match3 = /^labels\.roads\.([^.]+)$/u.exec(semanticKey);
12573
+ if (match3) return `tileflow-label-road-${match3[1]}`;
12574
+ match3 = /^labels\.shields\.([^.]+)$/u.exec(semanticKey);
12575
+ if (match3) return `tileflow-label-road-shield-${match3[1]}`;
12576
+ match3 = /^labels\.water\.([^.]+)$/u.exec(semanticKey);
12577
+ if (match3) return `tileflow-label-water-${match3[1]}`;
12578
+ match3 = /^labels\.cohorts\.roads\.(major|local)$/u.exec(semanticKey);
12579
+ if (match3) return `tileflow-label-road-${match3[1]}`;
12580
+ match3 = /^labels\.cohorts\.roads\.cohort(\d+)$/u.exec(semanticKey);
12581
+ if (match3) return `tileflow-label-road-cohort-${match3[1]}`;
12582
+ match3 = /^landforms\.classes\.([^.]+)$/u.exec(semanticKey);
12583
+ if (match3) return `tileflow-landform-${match3[1]}`;
12584
+ match3 = /^water\.(bathymetryLandforms|bathymetryWaterNames)\.cohort(\d+)$/u.exec(semanticKey);
12585
+ if (match3) {
12586
+ const base = match3[1] === "bathymetryLandforms" ? "landforms" : "water-names";
12587
+ return `tileflow-bathymetry-${base}-cohort-${match3[2]}`;
12588
+ }
12589
+ match3 = /^poi\.([A-Za-z0-9_-]+(?:\.[A-Za-z0-9_-]+)*)$/u.exec(semanticKey);
12590
+ if (match3) return `tileflow-poi-${match3[1].replaceAll(".", "-")}`;
11590
12591
  const nautical2 = nauticalPhysicalLayerId(semanticKey);
11591
12592
  if (nautical2) return nautical2;
11592
12593
  throw new TileflowDomainIRError(
@@ -11603,6 +12604,7 @@ var exactPhysicalLayerIds = Object.freeze({
11603
12604
  "labels.junctions": "tileflow-label-road-junction",
11604
12605
  "land.background": "tileflow-background",
11605
12606
  "land.globalLandcover": "tileflow-global-landcover",
12607
+ poi: "tileflow-poi",
11606
12608
  "landforms.classes": "tileflow-landforms",
11607
12609
  "roads.crossings": "tileflow-road-crossing",
11608
12610
  "roads.oneWayMarkers": "tileflow-road-oneway",
@@ -11619,6 +12621,8 @@ var exactPhysicalLayerIds = Object.freeze({
11619
12621
  "water.bathymetry": "tileflow-bathymetry",
11620
12622
  "water.bathymetryContours": "tileflow-bathymetry-contours",
11621
12623
  "water.bathymetryLabels": "tileflow-bathymetry-labels",
12624
+ "water.bathymetryLandforms": "tileflow-bathymetry-landforms",
12625
+ "water.bathymetryWaterNames": "tileflow-bathymetry-water-names",
11622
12626
  "water.bathymetryRelief.color": "tileflow-bathymetry-color-relief",
11623
12627
  "water.bathymetryRelief.hillshade": "tileflow-bathymetry-relief"
11624
12628
  });
@@ -11643,15 +12647,15 @@ var nauticalPhysicalBases = Object.freeze({
11643
12647
  function nauticalPhysicalLayerId(semanticKey) {
11644
12648
  const direct = nauticalPhysicalBases[semanticKey];
11645
12649
  if (direct) return direct;
11646
- const match2 = /^(nautical\.[A-Za-z0-9_.-]+)\.(fill|outline|marker|symbol)$/u.exec(semanticKey);
11647
- if (!match2) return void 0;
11648
- const base = nauticalPhysicalBases[match2[1]];
12650
+ const match3 = /^(nautical\.[A-Za-z0-9_.-]+)\.(fill|outline|marker|symbol)$/u.exec(semanticKey);
12651
+ if (!match3) return void 0;
12652
+ const base = nauticalPhysicalBases[match3[1]];
11649
12653
  if (!base) return void 0;
11650
- if (match2[2] === "fill" || match2[2] === "symbol") return base;
11651
- return `${base}-${match2[2]}`;
12654
+ if (match3[2] === "fill" || match3[2] === "symbol") return base;
12655
+ return `${base}-${match3[2]}`;
11652
12656
  }
11653
12657
  function publicMetadata(value) {
11654
- const metadata = { ...asRecord4(value) };
12658
+ const metadata = { ...asRecord5(value) };
11655
12659
  delete metadata[tileflowCompilerProvenanceMetadataKey];
11656
12660
  for (const key of Object.values(tileflowCompilerMetadataKeys)) delete metadata[key];
11657
12661
  return Object.keys(metadata).length > 0 ? cloneJson20(metadata) : void 0;
@@ -11687,21 +12691,21 @@ function visitReferences(value, counts, visited = /* @__PURE__ */ new WeakSet())
11687
12691
  }
11688
12692
  }
11689
12693
  function isSemanticFieldReference(value) {
11690
- return isRecord9(value) && value.kind === "tileflow-data-field";
12694
+ return isRecord8(value) && value.kind === "tileflow-data-field";
11691
12695
  }
11692
12696
  function isSemanticLayerReference(value) {
11693
- return isRecord9(value) && value.kind === "tileflow-data-layer";
12697
+ return isRecord8(value) && value.kind === "tileflow-data-layer";
11694
12698
  }
11695
12699
  function isSemanticSourceReference(value) {
11696
- return isRecord9(value) && value.kind === "tileflow-data-source";
12700
+ return isRecord8(value) && value.kind === "tileflow-data-source";
11697
12701
  }
11698
12702
  function cloneJson20(value) {
11699
12703
  return JSON.parse(JSON.stringify(value));
11700
12704
  }
11701
- function asRecord4(value) {
11702
- return isRecord9(value) ? value : {};
12705
+ function asRecord5(value) {
12706
+ return isRecord8(value) ? value : {};
11703
12707
  }
11704
- function isRecord9(value) {
12708
+ function isRecord8(value) {
11705
12709
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
11706
12710
  }
11707
12711
 
@@ -11765,7 +12769,7 @@ function validateTileflowRenderSelectorConstraints(input) {
11765
12769
  };
11766
12770
  while (pending.length > 0) {
11767
12771
  const current = pending.pop();
11768
- if (!isRecord10(current.selector) || typeof current.selector.kind !== "string") {
12772
+ if (!isRecord9(current.selector) || typeof current.selector.kind !== "string") {
11769
12773
  addIssue(
11770
12774
  "invalid-selector",
11771
12775
  "a render selector must be a semantic selector node",
@@ -11826,7 +12830,7 @@ function validateTileflowRenderSelectorConstraints(input) {
11826
12830
  }
11827
12831
  for (const [index, branch] of current.selector.branches.entries()) {
11828
12832
  const branchPath = [...branchesPath, index];
11829
- if (!isRecord10(branch)) {
12833
+ if (!isRecord9(branch)) {
11830
12834
  addIssue("invalid-selector", "match selector branch must be an object", branchPath);
11831
12835
  continue;
11832
12836
  }
@@ -11857,14 +12861,14 @@ function validateTileflowRenderSelectorConstraints(input) {
11857
12861
  for (let index = current.selector.stops.length - 1; index >= 0; index -= 1) {
11858
12862
  const stop = current.selector.stops[index];
11859
12863
  const stopPath = [...stopsPath, index];
11860
- if (!isRecord10(stop)) {
12864
+ if (!isRecord9(stop)) {
11861
12865
  addIssue("invalid-selector", "step selector stop must be an object", stopPath);
11862
12866
  continue;
11863
12867
  }
11864
12868
  pushChild(stop.selector, current.depth + 1, [...stopPath, "selector"]);
11865
12869
  }
11866
12870
  for (const [index, stop] of current.selector.stops.entries()) {
11867
- if (!isRecord10(stop)) continue;
12871
+ if (!isRecord9(stop)) continue;
11868
12872
  const zoom3 = stop.zoom;
11869
12873
  const zoomPath = [...stopsPath, index, "zoom"];
11870
12874
  if (typeof zoom3 !== "number" || !Number.isFinite(zoom3) || zoom3 < 0 || zoom3 > 24) {
@@ -12075,8 +13079,8 @@ function applyCompiledRenderStacks(input, operations2) {
12075
13079
  const index2 = findTargetIndex(layers, operation.target);
12076
13080
  moved.set(operation.target, requireRefinementOwner(layers[index2], operation));
12077
13081
  layers = [...layers.slice(0, index2), ...layers.slice(index2 + 1)];
12078
- for (const [placed, target] of lastPlaced) {
12079
- if (target === operation.target) lastPlaced.delete(placed);
13082
+ for (const [placed2, target] of lastPlaced) {
13083
+ if (target === operation.target) lastPlaced.delete(placed2);
12080
13084
  }
12081
13085
  }
12082
13086
  const placement = first.placement;
@@ -12242,12 +13246,12 @@ function applyRendererStyle(layer, renderer, style) {
12242
13246
  if (!visibilityGroup) return result;
12243
13247
  return {
12244
13248
  ...result,
12245
- layout: { ...asRecord5(result.layout), visibility: "none" },
12246
- metadata: { ...asRecord5(result.metadata), "tileflow:3d-toggle": visibilityGroup }
13249
+ layout: { ...asRecord6(result.layout), visibility: "none" },
13250
+ metadata: { ...asRecord6(result.metadata), "tileflow:3d-toggle": visibilityGroup }
12247
13251
  };
12248
13252
  }
12249
13253
  function lowerSelector(selector, data) {
12250
- if (!isRecord10(selector) || typeof selector.kind !== "string") {
13254
+ if (!isRecord9(selector) || typeof selector.kind !== "string") {
12251
13255
  throw renderStackError(
12252
13256
  "invalid-selector",
12253
13257
  "A render selector must be a semantic selector node."
@@ -12450,7 +13454,7 @@ function requireRenderer(value) {
12450
13454
  function requirePlacement(value) {
12451
13455
  if (typeof value === "string") {
12452
13456
  if (tileflowBandPlacements.includes(value)) return;
12453
- } else if (isRecord10(value)) {
13457
+ } else if (isRecord9(value)) {
12454
13458
  const keys = Object.keys(value);
12455
13459
  if (keys.length === 1 && (keys[0] === "above" || keys[0] === "below")) {
12456
13460
  requirePortableTarget(value[keys[0]], "render placement target");
@@ -12477,7 +13481,7 @@ function validateRefinementShape(operation) {
12477
13481
  validateStyle(operation.renderer, operation.style);
12478
13482
  }
12479
13483
  function validateStyle(renderer, style) {
12480
- if (!isRecord10(style)) {
13484
+ if (!isRecord9(style)) {
12481
13485
  throw renderStackError(
12482
13486
  "invalid-style",
12483
13487
  `A ${renderer} render operation requires a style object.`
@@ -12579,7 +13583,7 @@ function normalizeRequirements(requirements) {
12579
13583
  return [...requirements];
12580
13584
  }
12581
13585
  function requireRenderStackEntries(stack) {
12582
- if (!isRecord10(stack)) {
13586
+ if (!isRecord9(stack)) {
12583
13587
  throw renderStackError("invalid-stack", "A render stack must be a named operation record.");
12584
13588
  }
12585
13589
  const entries = Object.entries(stack);
@@ -12725,10 +13729,10 @@ function compareCodeUnits6(left, right) {
12725
13729
  function cloneJson21(value) {
12726
13730
  return JSON.parse(JSON.stringify(value));
12727
13731
  }
12728
- function asRecord5(value) {
12729
- return isRecord10(value) ? value : {};
13732
+ function asRecord6(value) {
13733
+ return isRecord9(value) ? value : {};
12730
13734
  }
12731
- function isRecord10(value) {
13735
+ function isRecord9(value) {
12732
13736
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
12733
13737
  }
12734
13738
 
@@ -12795,6 +13799,9 @@ function collectTileflowIconSetReferences(sources) {
12795
13799
  return references;
12796
13800
  }
12797
13801
 
13802
+ // src/resolved-map-schema.ts
13803
+ init_manifest_schema_classic();
13804
+
12798
13805
  // src/maps/assets.ts
12799
13806
  var tileflowLocalDirectoryMaximumLength = 512;
12800
13807
  var tileflowLocalDirectoryMessage = "Expected a canonical relative directory beginning with ./ or ../; only leading .. segments are allowed and segments must be non-empty, without backslashes or controls";
@@ -12939,6 +13946,8 @@ function isLoopbackHostname(hostname) {
12939
13946
  }
12940
13947
 
12941
13948
  // src/resolved-map-schema.ts
13949
+ init_time_of_day();
13950
+ init_time_of_day_schema();
12942
13951
  var TileflowResolvedMapValidationError = class extends Error {
12943
13952
  code = "CONFIG_INVALID";
12944
13953
  messages;
@@ -13085,7 +14094,7 @@ function validateExpressionFieldNames(value, context, path) {
13085
14094
  }
13086
14095
  if (!value || typeof value !== "object") return;
13087
14096
  const candidate = value;
13088
- if (candidate.kind === "tileflow-data-field" && (typeof candidate.name !== "string" || !Object.hasOwn(fieldBindingsSchema.shape, candidate.name))) {
14097
+ if (candidate.kind === "tileflow-data-field" && (typeof candidate.name !== "string" || !tileflowSemanticExpressionFieldNames.some((name) => name === candidate.name))) {
13089
14098
  context.addIssue({
13090
14099
  code: "custom",
13091
14100
  message: "Expected a registered semantic field name.",
@@ -13239,12 +14248,12 @@ var hexColorSchema = z7.string().regex(/^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a
13239
14248
  message: "Expected a hex color like #F6F7F3 or #F6F7F3FF"
13240
14249
  });
13241
14250
  var rgbColorSchema = z7.string().refine((value) => {
13242
- const match2 = value.match(
14251
+ const match3 = value.match(
13243
14252
  /^rgba?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)(?:\s*,\s*(\d+(?:\.\d+)?))?\s*\)$/iu
13244
14253
  );
13245
- if (!match2) return false;
13246
- const channels = match2.slice(1, 4).map(Number);
13247
- const alpha2 = Number(match2[4] ?? 1);
14254
+ if (!match3) return false;
14255
+ const channels = match3.slice(1, 4).map(Number);
14256
+ const alpha2 = Number(match3[4] ?? 1);
13248
14257
  return channels.every((channel) => channel >= 0 && channel <= 255) && alpha2 >= 0 && alpha2 <= 1;
13249
14258
  }, "Expected a Tileflow hex, rgb(), or rgba() color");
13250
14259
  var terrainColorLiteralSchema = z7.union([hexColorSchema, rgbColorSchema]);
@@ -13521,9 +14530,7 @@ var symbolStyleSchema = z7.object({
13521
14530
  text: textStyleSchema.optional()
13522
14531
  }).strict();
13523
14532
  var markerSymbolStyleSchema = symbolStyleSchema.extend({ marker: circleStyleSchema.optional() }).strict();
13524
- var poiCategoryStyleSchema = markerSymbolStyleSchema.omit({ priority: true, priorityOrder: true }).extend({
13525
- density: z7.union([z7.literal(1), z7.literal(2), z7.literal(3), z7.literal(4), z7.literal(5)]).optional()
13526
- }).strict();
14533
+ var poiCategoryStyleSchema = markerSymbolStyleSchema.omit({ priority: true, priorityOrder: true }).strict();
13527
14534
  var renderScalarSchema = z7.union([z7.boolean(), z7.number().finite(), z7.string()]);
13528
14535
  var renderTargetSchema = z7.string().regex(tileflowSemanticTargetPattern, "Expected a semantic target");
13529
14536
  var renderStackOperationNameSchema = z7.string().regex(
@@ -13756,6 +14763,8 @@ var waterModuleSchema = z7.object({
13756
14763
  bathymetry: fillStyleSchema.optional(),
13757
14764
  bathymetryContours: lineStyleSchema.optional(),
13758
14765
  bathymetryLabels: symbolStyleSchema.optional(),
14766
+ bathymetryLandforms: symbolStyleSchema.optional(),
14767
+ bathymetryWaterNames: symbolStyleSchema.optional(),
13759
14768
  bodies: areaStyleSchema.optional(),
13760
14769
  enabled: z7.boolean().optional(),
13761
14770
  intermittent: z7.object({ bodies: areaStyleSchema.optional(), waterways: lineStyleSchema.optional() }).strict().optional(),
@@ -13787,12 +14796,43 @@ var buildingsModuleSchema = z7.object({
13787
14796
  mode: z7.enum(["3d", "flat"]).optional(),
13788
14797
  renderStack: renderStackSchema.optional(),
13789
14798
  threeDimensional: z7.object({
14799
+ lighting: z7.enum(["style", "sun"]).optional(),
14800
+ colorVariation: boundedThemeNumberSchema(0, 1).optional(),
13790
14801
  edges: boundedThemeNumberSchema(0, 1).optional(),
13791
14802
  edgeColor: themeColorValueSchema.optional(),
13792
14803
  nightLight: boundedThemeNumberSchema(0, 2).optional(),
13793
14804
  occlusion: z7.boolean().optional(),
13794
14805
  shadows: z7.boolean().optional(),
13795
- windows: z7.boolean().optional()
14806
+ windows: z7.boolean().optional(),
14807
+ models: z7.array(
14808
+ z7.object({
14809
+ model: z7.string().max(64).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/u),
14810
+ at: z7.tuple([z7.number().min(-180).max(180), z7.number().min(-85).max(85)]),
14811
+ heading: z7.number().finite().optional(),
14812
+ url: z7.url().max(2048).refine((value) => new URL(value).protocol === "https:", {
14813
+ message: "A model served elsewhere has an HTTPS address."
14814
+ }).optional()
14815
+ }).strict()
14816
+ ).max(256).optional(),
14817
+ modelColors: z7.object({
14818
+ surface: themeColorValueSchema.optional(),
14819
+ secondary: themeColorValueSchema.optional(),
14820
+ glass: themeColorValueSchema.optional(),
14821
+ accent: themeColorValueSchema.optional(),
14822
+ roof: themeColorValueSchema.optional()
14823
+ }).strict().optional(),
14824
+ landmarks: z7.union([
14825
+ z7.boolean(),
14826
+ z7.object({
14827
+ url: z7.url().max(2048).refine(
14828
+ (value) => {
14829
+ const url = new URL(value);
14830
+ return url.protocol === "https:" || url.protocol === "http:" && ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname);
14831
+ },
14832
+ { message: "A landmarks tileset has an HTTPS address, or a local one." }
14833
+ )
14834
+ }).strict()
14835
+ ]).optional()
13796
14836
  }).strict().optional()
13797
14837
  }).strict();
13798
14838
  var addressesModuleSchema = z7.object({
@@ -13971,7 +15011,10 @@ var poiModuleSchema = z7.object({
13971
15011
  minZoom: zoomNumberSchema.optional(),
13972
15012
  placement: z7.object({
13973
15013
  coupleIconAndLabel: z7.boolean().optional(),
15014
+ iconOnlyTypes: z7.array(z7.string().regex(/^[a-z0-9]+(?:_[a-z0-9]+)*$/u, "Expected a World POI type")).max(64).optional(),
13974
15015
  iconPadding: z7.number().finite().min(0).optional(),
15016
+ order: z7.enum(["categories", "importance"]).optional(),
15017
+ prominentRank: z7.number().int().min(0).max(5).optional(),
13975
15018
  textPadding: z7.number().finite().min(0).optional()
13976
15019
  }).strict().optional(),
13977
15020
  renderStack: renderStackSchema.optional(),
@@ -14026,7 +15069,9 @@ var modulesSchema = z7.object({
14026
15069
  type: z7.literal("vegetation"),
14027
15070
  enabled: z7.boolean().optional(),
14028
15071
  flat: circleStyleSchema.optional(),
14029
- mode: z7.enum(["3d", "flat"]).optional(),
15072
+ mode: z7.enum(["3d", "flat", "auto"]).optional(),
15073
+ fallback: z7.enum(["flat", "none"]).optional(),
15074
+ visible: z7.boolean().optional(),
14030
15075
  renderStack: renderStackSchema.optional(),
14031
15076
  threeDimensional: z7.object({
14032
15077
  barkColor: themeColorValueSchema.optional(),
@@ -14163,6 +15208,7 @@ var fieldBindingsSchema = z7.object({
14163
15208
  markings: z7.string().trim().min(1),
14164
15209
  minHeight: z7.string().trim().min(1),
14165
15210
  minZoom: z7.string().trim().min(1),
15211
+ mode: z7.string().trim().min(1),
14166
15212
  mtbScale: z7.string().trim().min(1),
14167
15213
  name: z7.string().trim().min(1),
14168
15214
  nameEnglish: z7.string().trim().min(1),
@@ -14266,6 +15312,32 @@ var bathymetryReliefSchema = z7.object({
14266
15312
  });
14267
15313
  }
14268
15314
  });
15315
+ var bathymetryNameLayerSchema = z7.union([
15316
+ z7.boolean(),
15317
+ z7.object({
15318
+ zoomRanges: z7.array(z7.object({ minZoom: zoomNumberSchema, maxZoom: zoomNumberSchema }).strict()).min(1).max(tileflowBathymetryNameLayerLimits.maxZoomRanges).superRefine((ranges, context) => {
15319
+ const seen = /* @__PURE__ */ new Set();
15320
+ for (const [index, range2] of ranges.entries()) {
15321
+ if (range2.minZoom >= range2.maxZoom) {
15322
+ context.addIssue({
15323
+ code: "custom",
15324
+ message: "Expected minZoom < maxZoom",
15325
+ path: [index, "maxZoom"]
15326
+ });
15327
+ }
15328
+ const key = `${range2.minZoom}/${range2.maxZoom}`;
15329
+ if (seen.has(key)) {
15330
+ context.addIssue({
15331
+ code: "custom",
15332
+ message: "Expected unique nominal zoom ranges",
15333
+ path: [index]
15334
+ });
15335
+ }
15336
+ seen.add(key);
15337
+ }
15338
+ })
15339
+ }).strict()
15340
+ ]);
14269
15341
  var bathymetryConfigSchema = z7.object({
14270
15342
  ...marineSourceSchema.shape,
14271
15343
  bands: z7.union([z7.literal(false), fillStyleSchema]).optional(),
@@ -14273,7 +15345,12 @@ var bathymetryConfigSchema = z7.object({
14273
15345
  display: z7.enum(["bands", "relief", "hybrid"]).optional(),
14274
15346
  labels: z7.union([z7.literal(false), symbolStyleSchema]).optional(),
14275
15347
  relief: z7.union([z7.literal(false), bathymetryReliefSchema]).optional(),
14276
- type: z7.literal("bathymetry")
15348
+ type: z7.literal("bathymetry"),
15349
+ vectorLayers: z7.object({
15350
+ contours: z7.boolean().optional(),
15351
+ landforms: bathymetryNameLayerSchema.optional(),
15352
+ waterNames: bathymetryNameLayerSchema.optional()
15353
+ }).strict().optional()
14277
15354
  }).strict();
14278
15355
  var marineSchema = z7.union([
14279
15356
  z7.enum(["none", "bathymetry", "nautical", "chart"]),
@@ -14628,6 +15705,10 @@ var resolvedTileflowMapSchema = z7.object({
14628
15705
  systemThemes: systemThemesSchema.optional(),
14629
15706
  terrain: terrainSchema.optional(),
14630
15707
  themes: themesSchema,
15708
+ timeOfDay: createTileflowTimeOfDaySchema(
15709
+ classicManifestSchemaOperations,
15710
+ tileflowThemeNameSchema
15711
+ ).optional(),
14631
15712
  version: z7.number().int().positive(),
14632
15713
  view: viewSchema.optional()
14633
15714
  }).strict().superRefine((map, context) => {
@@ -14652,6 +15733,15 @@ var resolvedTileflowMapSchema = z7.object({
14652
15733
  path: ["defaultTheme"]
14653
15734
  });
14654
15735
  }
15736
+ if (map.timeOfDay) {
15737
+ for (const issue of validateTileflowTimeOfDayVariants(map.timeOfDay, map.themes)) {
15738
+ context.addIssue({
15739
+ code: "custom",
15740
+ message: issue.message,
15741
+ path: ["timeOfDay", ...issue.path]
15742
+ });
15743
+ }
15744
+ }
14655
15745
  const themeEntries = Object.entries(map.themes).sort(
14656
15746
  ([left], [right]) => left < right ? -1 : left > right ? 1 : 0
14657
15747
  );
@@ -14874,6 +15964,46 @@ function tileflowRouteMetadata(inks) {
14874
15964
  return Object.freeze({ version: 1, ...inks });
14875
15965
  }
14876
15966
 
15967
+ // src/street-lights.ts
15968
+ init_theme_blend();
15969
+ var tileflowStreetLightsMetadataKey = "tileflow:street-lights";
15970
+ var tileflowDefaultStreetLightsDesign = Object.freeze({
15971
+ source: "tileflow",
15972
+ layers: Object.freeze({
15973
+ streetFurniture: "street_furniture",
15974
+ transportation: "transportation",
15975
+ sidewalk: "sidewalk"
15976
+ }),
15977
+ estimate: "lit",
15978
+ color: "#ffcf8f",
15979
+ intensity: 1
15980
+ });
15981
+ function tileflowStreetLightsMetadata(design) {
15982
+ return { version: 1, ...design };
15983
+ }
15984
+ function readTileflowStreetLights(metadata) {
15985
+ if (typeof metadata !== "object" || metadata === null || Array.isArray(metadata))
15986
+ return void 0;
15987
+ const value = metadata[tileflowStreetLightsMetadataKey];
15988
+ if (typeof value !== "object" || value === null || value.version !== 1) return void 0;
15989
+ const layers = value.layers;
15990
+ if (typeof value.source !== "string" || typeof layers?.streetFurniture !== "string" || typeof layers.transportation !== "string")
15991
+ return void 0;
15992
+ const estimate = ["lit", "streets", "none"].find((name) => name === value.estimate);
15993
+ const intensity = typeof value.intensity === "number" && value.intensity >= 0 && value.intensity <= 2 ? value.intensity : 1;
15994
+ return {
15995
+ source: value.source,
15996
+ layers: {
15997
+ streetFurniture: layers.streetFurniture,
15998
+ transportation: layers.transportation,
15999
+ ...typeof layers.sidewalk === "string" ? { sidewalk: layers.sidewalk } : {}
16000
+ },
16001
+ estimate: estimate ?? "lit",
16002
+ color: typeof value.color === "string" && tileflowColourChannels(value.color) ? value.color : tileflowDefaultStreetLightsDesign.color,
16003
+ intensity
16004
+ };
16005
+ }
16006
+
14877
16007
  // src/cartography/streets.ts
14878
16008
  init_sun();
14879
16009
 
@@ -15055,7 +16185,7 @@ function terrainContribution(target, localOrder, layer) {
15055
16185
  };
15056
16186
  }
15057
16187
  function applyLayerRange2(layer, range2) {
15058
- const layout = { ...asRecord6(layer.layout) };
16188
+ const layout = { ...asRecord7(layer.layout) };
15059
16189
  if (range2.visible !== void 0) layout.visibility = range2.visible ? "visible" : "none";
15060
16190
  return {
15061
16191
  ...layer,
@@ -15064,10 +16194,39 @@ function applyLayerRange2(layer, range2) {
15064
16194
  ...Object.keys(layout).length === 0 ? {} : { layout }
15065
16195
  };
15066
16196
  }
15067
- function asRecord6(value) {
16197
+ function asRecord7(value) {
15068
16198
  return value && typeof value === "object" && !Array.isArray(value) ? value : {};
15069
16199
  }
15070
16200
 
16201
+ // src/vegetation-display.ts
16202
+ var tileflowVegetationDisplayMetadataKey = "tileflow:vegetation-display";
16203
+ function readTileflowVegetationDisplay(metadata) {
16204
+ if (!metadata || typeof metadata !== "object") return void 0;
16205
+ const value = metadata[tileflowVegetationDisplayMetadataKey];
16206
+ if (value && typeof value === "object") {
16207
+ const policy = value;
16208
+ if (policy.version !== 1 || !["3d", "flat", "auto"].includes(policy.mode ?? "") || !["flat", "none"].includes(policy.fallback ?? "") || typeof policy.visible !== "boolean" || !Array.isArray(policy.flatLayers) || !policy.flatLayers.every(
16209
+ (layer) => layer && typeof layer.id === "string" && typeof layer.visible === "boolean"
16210
+ ))
16211
+ return void 0;
16212
+ return policy;
16213
+ }
16214
+ const legacy = readTileflowVegetation3D(metadata);
16215
+ return legacy ? {
16216
+ version: 1,
16217
+ mode: "3d",
16218
+ fallback: "flat",
16219
+ visible: true,
16220
+ flatLayers: legacy.flatLayers.map((id2) => ({ id: id2, visible: true }))
16221
+ } : void 0;
16222
+ }
16223
+ function resolveTileflowVegetationRepresentation(policy, options) {
16224
+ if (!policy || !(options.visible ?? policy.visible)) return "none";
16225
+ if (policy.mode === "flat" || policy.mode === "auto" && options.viewMode !== "3d")
16226
+ return "flat";
16227
+ return options.supports3D ? "3d" : policy.fallback;
16228
+ }
16229
+
15071
16230
  // src/cartography/graph.ts
15072
16231
  function assembleTileflowLayerFamilies(families, extraConstraints = []) {
15073
16232
  const slotOrder = resolveSlotOrder(extraConstraints);
@@ -15470,14 +16629,16 @@ function defaultPaint(image, key, names, appearances, ids) {
15470
16629
 
15471
16630
  // src/cartography/interaction-manifest.ts
15472
16631
  var tileflowInteractionManifestMetadataKey = "tileflow:interaction-manifest";
15473
- var tileflowInteractionManifestVersion = 2;
16632
+ var tileflowInteractionManifestVersion = 3;
15474
16633
  function createTileflowInteractionManifest(layers, fields) {
15475
16634
  const poiLayers = layers.flatMap((layer, priority) => {
15476
16635
  const id2 = typeof layer.id === "string" ? layer.id : void 0;
15477
16636
  const source = typeof layer.source === "string" ? layer.source : void 0;
15478
16637
  const sourceLayer = typeof layer["source-layer"] === "string" ? layer["source-layer"] : void 0;
15479
16638
  const target = semanticTarget(layer);
15480
- if (!id2 || !source || !sourceLayer || !target?.startsWith("poi.")) return [];
16639
+ if (!id2 || !source || !sourceLayer || target !== "poi" && !target?.startsWith("poi.")) {
16640
+ return [];
16641
+ }
15481
16642
  const parsed = parsePoiTarget(target);
15482
16643
  if (!parsed) return [];
15483
16644
  return [
@@ -15525,7 +16686,7 @@ function assertTileflowInteractionManifestLayers(manifest, layers) {
15525
16686
  );
15526
16687
  }
15527
16688
  for (const layer of poiLayers) {
15528
- if (!isTileflowPoiCategory(layer.category) || !isSafeArtifactName(layer.layerId) || !isSafeArtifactName(layer.source) || !isSafeArtifactName(layer.sourceLayer)) {
16689
+ if (!isSafeArtifactName(layer.layerId) || !isSafeArtifactName(layer.source) || !isSafeArtifactName(layer.sourceLayer)) {
15529
16690
  throw new Error("Tileflow interaction manifest contains an invalid physical POI lookup.");
15530
16691
  }
15531
16692
  const finalized = layersById.get(layer.layerId);
@@ -15548,25 +16709,26 @@ function assertTileflowInteractionManifestLayers(manifest, layers) {
15548
16709
  }
15549
16710
  function parsePoiTarget(target) {
15550
16711
  const segments = target.split(".");
15551
- if (segments[0] !== "poi" || segments.length < 2 || segments.length > 3) return void 0;
15552
- const category = segments[1];
15553
- if (!isTileflowPoiCategory(category)) return void 0;
15554
- const suffix = segments[2];
15555
- if (suffix === void 0) return { category, representation: "combined" };
15556
- if (suffix === "icon" || suffix === "label" || suffix === "marker") {
15557
- return { category, representation: suffix };
15558
- }
15559
- return void 0;
16712
+ if (segments[0] !== "poi" || segments.length > 3) return void 0;
16713
+ const [, first, second] = segments;
16714
+ if (first === void 0) return { representation: "combined" };
16715
+ if (segments.length === 2 && isRepresentationPart(first)) return { representation: first };
16716
+ if (first !== "prominent" && !isTileflowPoiCategory(first)) return void 0;
16717
+ if (second === void 0) return { representation: "combined" };
16718
+ return isRepresentationPart(second) ? { representation: second } : void 0;
16719
+ }
16720
+ function isRepresentationPart(value) {
16721
+ return value === "icon" || value === "label" || value === "marker";
15560
16722
  }
15561
16723
  function isTileflowPoiCategory(value) {
15562
16724
  return typeof value === "string" && tileflowPoiCategories.includes(value);
15563
16725
  }
15564
16726
  function semanticTarget(layer) {
15565
- if (!isRecord11(layer.metadata)) return void 0;
16727
+ if (!isRecord10(layer.metadata)) return void 0;
15566
16728
  const value = layer.metadata[tileflowCompilerMetadataKeys.target];
15567
16729
  return typeof value === "string" ? value : void 0;
15568
16730
  }
15569
- function isRecord11(value) {
16731
+ function isRecord10(value) {
15570
16732
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
15571
16733
  }
15572
16734
  function isSafeArtifactName(value) {
@@ -16228,12 +17390,12 @@ function combinePatternValues(entries, minimumRelevantZoom) {
16228
17390
  if (entries.some(({ value }) => containsZoom(value) && !isZoomStep(value))) {
16229
17391
  return { ok: false };
16230
17392
  }
16231
- const steps = entries.flatMap(({ value }) => isZoomStep(value) ? [value] : []);
16232
- if (steps.length === 0) {
17393
+ const steps2 = entries.flatMap(({ value }) => isZoomStep(value) ? [value] : []);
17394
+ if (steps2.length === 0) {
16233
17395
  return { ok: true, value: conditionalExpression(entries, entries[0]?.value) };
16234
17396
  }
16235
17397
  const stops = /* @__PURE__ */ new Set([minimumRelevantZoom]);
16236
- for (const step2 of steps) {
17398
+ for (const step2 of steps2) {
16237
17399
  for (let index = 3; index < step2.length; index += 2) {
16238
17400
  const stop = step2[index];
16239
17401
  if (typeof stop === "number" && stop >= minimumRelevantZoom) stops.add(stop);
@@ -16291,7 +17453,7 @@ function conditionalExpression(entries, fallback) {
16291
17453
  ];
16292
17454
  }
16293
17455
  const classMatches = entries.map(({ condition }) => splitClassMatch(condition));
16294
- if (classMatches.every((match2) => match2 !== void 0) && allEqual(classMatches.map((match2) => match2?.field)) && allEqual(classMatches.map((match2) => match2?.remainder)) && classMatchLabelsAreDisjoint(classMatches.map((match2) => match2.labels))) {
17456
+ if (classMatches.every((match3) => match3 !== void 0) && allEqual(classMatches.map((match3) => match3?.field)) && allEqual(classMatches.map((match3) => match3?.remainder)) && classMatchLabelsAreDisjoint(classMatches.map((match3) => match3.labels))) {
16295
17457
  return [
16296
17458
  "match",
16297
17459
  ["get", classMatches[0].field],
@@ -16455,6 +17617,115 @@ function stableSerialize(value) {
16455
17617
  return `{${Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, entry]) => `${JSON.stringify(key)}:${stableSerialize(entry)}`).join(",")}}`;
16456
17618
  }
16457
17619
 
17620
+ // src/cartography/scene-3d-metadata.ts
17621
+ init_values();
17622
+ var colourSources = [
17623
+ ["tileflow-buildings-render-extrusion", "fill-extrusion-color"],
17624
+ ["tileflow-buildings-3d", "fill-extrusion-color"],
17625
+ ["tileflow-buildings-fill", "fill-color"]
17626
+ ];
17627
+ function tileflowBuildings3DDesignOf(module, context, layers, buildingModels, tileflowLandmarks) {
17628
+ const config = isRecord11(module) ? module : {};
17629
+ if (config.enabled === false) return void 0;
17630
+ const style = config.threeDimensional ?? {};
17631
+ let color3;
17632
+ let verticalGradient = true;
17633
+ for (const [id2, property] of colourSources) {
17634
+ const value = layers.find((layer) => layer.id === id2)?.paint?.[property];
17635
+ if (typeof value === "string" || Array.isArray(value)) {
17636
+ color3 = value;
17637
+ verticalGradient = layers.find((layer) => layer.id === id2)?.paint?.["fill-extrusion-vertical-gradient"] !== false;
17638
+ break;
17639
+ }
17640
+ }
17641
+ const number = (value, fallback) => {
17642
+ const resolved = value === void 0 ? void 0 : toMapLibreStyleValue(value);
17643
+ return typeof resolved === "number" ? resolved : fallback;
17644
+ };
17645
+ const edgeColor = style.edgeColor === void 0 ? void 0 : toMapLibreStyleValue(style.edgeColor);
17646
+ return {
17647
+ source: context.data.sourceId,
17648
+ layers: {
17649
+ building: context.data.schema.layers.building,
17650
+ ...context.data.schema.layers.poi ? { places: context.data.schema.layers.poi } : {}
17651
+ },
17652
+ color: color3 ?? context.colors.buildings.generic,
17653
+ lighting: style.lighting === "sun" ? "sun" : "style",
17654
+ colorVariation: number(style.colorVariation, 0),
17655
+ verticalGradient,
17656
+ edges: number(style.edges, 0),
17657
+ ...typeof edgeColor === "string" ? { edgeColor } : {},
17658
+ nightLight: number(style.nightLight, 0),
17659
+ windows: style.windows === true,
17660
+ shadows: style.shadows === true,
17661
+ occlusion: style.occlusion === true,
17662
+ ...placedModels(style.models, buildingModels),
17663
+ ...modelColours(style.modelColors),
17664
+ ...landmarksOf2(style.landmarks, tileflowLandmarks)
17665
+ };
17666
+ }
17667
+ function landmarksOf2(value, tileflowLandmarks) {
17668
+ if (value === false) return {};
17669
+ if (isRecord11(value) && typeof value.url === "string") return { landmarks: { url: value.url } };
17670
+ return tileflowLandmarks ? { landmarks: { url: tileflowLandmarks } } : {};
17671
+ }
17672
+ function placedModels(value, served) {
17673
+ if (!Array.isArray(value) || value.length === 0) return {};
17674
+ const placements = value;
17675
+ const missing = [
17676
+ ...new Set(
17677
+ placements.filter((entry) => !entry.url).map((entry) => entry.model).filter((id2) => !served?.[id2])
17678
+ )
17679
+ ].sort();
17680
+ if (missing.length > 0)
17681
+ throw new Error(
17682
+ `The buildings module places missing 3D models: ${missing.join(", ")}. Add ${missing.map((id2) => `${id2}.glb`).join(
17683
+ ", "
17684
+ )} to a map.models directory, with materials named surface, secondary, glass, accent or roof, and run the Node build so the directories are prepared.`
17685
+ );
17686
+ return {
17687
+ models: placements.map((entry) => ({
17688
+ model: entry.model,
17689
+ url: entry.url ?? served[entry.model],
17690
+ at: [entry.at[0], entry.at[1]],
17691
+ heading: ((entry.heading ?? 0) % 360 + 360) % 360
17692
+ }))
17693
+ };
17694
+ }
17695
+ function modelColours(value) {
17696
+ if (!isRecord11(value)) return {};
17697
+ const colours = {};
17698
+ for (const [part, colour] of Object.entries(value)) {
17699
+ const resolved = colour === void 0 ? void 0 : toMapLibreStyleValue(colour);
17700
+ if (typeof resolved === "string") colours[part] = resolved;
17701
+ }
17702
+ return Object.keys(colours).length > 0 ? { modelColors: colours } : {};
17703
+ }
17704
+ function tileflowStreetLightsDesignOf(module, context) {
17705
+ const config = isRecord11(module) ? module : {};
17706
+ const layers = context.data.schema.layers;
17707
+ const style = config.streetLights ?? {};
17708
+ if (config.enabled === false || style.enabled === false || !layers.streetFurniture)
17709
+ return void 0;
17710
+ const color3 = style.color === void 0 ? void 0 : toMapLibreStyleValue(style.color);
17711
+ const intensity = style.intensity === void 0 ? void 0 : toMapLibreStyleValue(style.intensity);
17712
+ const estimate = style.estimate;
17713
+ return {
17714
+ source: context.data.sourceId,
17715
+ layers: {
17716
+ streetFurniture: layers.streetFurniture,
17717
+ transportation: layers.road,
17718
+ ...layers.sidewalk ? { sidewalk: layers.sidewalk } : {}
17719
+ },
17720
+ estimate: estimate === "streets" || estimate === "none" || estimate === "lit" ? estimate : "lit",
17721
+ color: typeof color3 === "string" ? color3 : tileflowDefaultStreetLightsDesign.color,
17722
+ intensity: typeof intensity === "number" ? intensity : 1
17723
+ };
17724
+ }
17725
+ function isRecord11(value) {
17726
+ return typeof value === "object" && value !== null && !Array.isArray(value);
17727
+ }
17728
+
16458
17729
  // src/cartography/semantic-compiler.ts
16459
17730
  var tileflowSemanticCompilerIdentity = Object.freeze({
16460
17731
  name: "tileflow-semantic",
@@ -16504,7 +17775,10 @@ function compileSemanticStyleInternal(input, options, inspect, onReport) {
16504
17775
  suggestion,
16505
17776
  ...target ? { target } : {}
16506
17777
  }));
16507
- const selected = runCompilationPhase("theme", () => resolveThemeSelection(input, options.theme));
17778
+ const selected = runCompilationPhase(
17779
+ "theme",
17780
+ () => resolveThemeSelection(input, options.theme, options.timeOfDay)
17781
+ );
16508
17782
  const resolvedTheme = runCompilationPhase("theme", () => resolveTileflowTheme(selected.theme));
16509
17783
  const { overlays, themes: _themes, ...themeableConfig } = input;
16510
17784
  const resolvedThemeConfig = runCompilationPhase(
@@ -16785,7 +18059,9 @@ function compileSemanticStyleInternal(input, options, inspect, onReport) {
16785
18059
  const buildings3D = tileflowBuildings3DDesignOf(
16786
18060
  modules.buildings,
16787
18061
  context,
16788
- layers
18062
+ layers,
18063
+ options.preparedAssets?.buildingModels,
18064
+ data.kind === "tileflow-world" ? `${apiBaseUrl}/landmarks/tiles.json` : void 0
16789
18065
  );
16790
18066
  const streetLights = tileflowStreetLightsDesignOf(
16791
18067
  modules.roads,
@@ -16838,6 +18114,24 @@ function compileSemanticStyleInternal(input, options, inspect, onReport) {
16838
18114
  layers
16839
18115
  })
16840
18116
  );
18117
+ const flatVegetationLayers = layers.filter((layer) => {
18118
+ const metadata = layer.metadata;
18119
+ return metadata?.["tileflow:vegetation-mode"] !== void 0 || metadata?.["tileflow:domain"] === "vegetation";
18120
+ });
18121
+ const vegetationDisplay = flatVegetationLayers.length || vegetation3D ? {
18122
+ version: 1,
18123
+ mode: modules.vegetation?.mode ?? "3d",
18124
+ fallback: modules.vegetation?.fallback ?? "flat",
18125
+ visible: modules.vegetation?.visible ?? true,
18126
+ flatLayers: flatVegetationLayers.map((layer) => ({
18127
+ id: String(layer.id),
18128
+ visible: layer.layout?.visibility !== "none"
18129
+ }))
18130
+ } : void 0;
18131
+ if (vegetationDisplay && (!vegetationDisplay.visible || vegetationDisplay.mode === "3d" && vegetationDisplay.fallback === "none")) {
18132
+ for (const layer of flatVegetationLayers)
18133
+ layer.layout = { ...layer.layout, visibility: "none" };
18134
+ }
16841
18135
  const atmosphere = resolveTileflowAtmosphere(config.atmosphere);
16842
18136
  const style = {
16843
18137
  ...atmosphere ? { sky: compileTileflowSky(atmosphere) } : {},
@@ -16877,12 +18171,10 @@ function compileSemanticStyleInternal(input, options, inspect, onReport) {
16877
18171
  [tileflowVegetationMetadataKey]: tileflowVegetationMetadata({
16878
18172
  ...bindSemanticReferences(vegetation3D, semanticData),
16879
18173
  // The layers that draw the trees flat: the module's own and its render passes.
16880
- flatLayers: layers.filter((layer) => {
16881
- const metadata = layer.metadata;
16882
- return metadata?.["tileflow:vegetation-mode"] !== void 0 || metadata?.["tileflow:domain"] === "vegetation";
16883
- }).map((layer) => String(layer.id))
18174
+ flatLayers: flatVegetationLayers.map((layer) => String(layer.id))
16884
18175
  })
16885
18176
  } : {},
18177
+ ...vegetationDisplay ? { [tileflowVegetationDisplayMetadataKey]: vegetationDisplay } : {},
16886
18178
  "tileflow:data": data.identity,
16887
18179
  "tileflow:sources": sourceIdentities,
16888
18180
  ...Object.keys(loweredOverlays.identities).length > 0 ? { "tileflow:overlays": loweredOverlays.identities } : {},
@@ -17268,6 +18560,7 @@ var tileflowMapMergeStrategies = {
17268
18560
  systemThemes: "atomic",
17269
18561
  terrain: "atomic",
17270
18562
  themes: "atomic",
18563
+ timeOfDay: "atomic",
17271
18564
  version: "identity",
17272
18565
  view: "deep"
17273
18566
  };
@@ -17282,7 +18575,10 @@ function resolveMap(map, options = {}) {
17282
18575
  for (let index = lineage.length - 1; index >= 0; index -= 1) {
17283
18576
  const current = lineage[index];
17284
18577
  const currentId = current.id;
17285
- if (current.themes !== void 0) delete design.systemThemes;
18578
+ if (current.themes !== void 0) {
18579
+ delete design.systemThemes;
18580
+ delete design.timeOfDay;
18581
+ }
17286
18582
  for (const key of Object.keys(current)) {
17287
18583
  const value = current[key];
17288
18584
  const strategy = tileflowMapMergeStrategies[key];
@@ -18472,7 +19768,7 @@ function analyzeTileflowStylePerformance(style, zooms = defaultZoomSamples(style
18472
19768
  function isLayerActive(layer, zoom3) {
18473
19769
  const minimum2 = typeof layer.minzoom === "number" ? layer.minzoom : 0;
18474
19770
  const maximum2 = typeof layer.maxzoom === "number" ? layer.maxzoom : Infinity;
18475
- const layout = asRecord7(layer.layout);
19771
+ const layout = asRecord8(layer.layout);
18476
19772
  return minimum2 <= zoom3 && zoom3 < maximum2 && layout.visibility !== "none";
18477
19773
  }
18478
19774
  function bucketSignature(layer) {
@@ -18513,7 +19809,7 @@ function stableStringify(value) {
18513
19809
  function compareCodeUnits10(left, right) {
18514
19810
  return left < right ? -1 : left > right ? 1 : 0;
18515
19811
  }
18516
- function asRecord7(value) {
19812
+ function asRecord8(value) {
18517
19813
  return value && typeof value === "object" && !Array.isArray(value) ? value : {};
18518
19814
  }
18519
19815
 
@@ -18667,7 +19963,7 @@ async function sha256Hex(input) {
18667
19963
  const digestInput = new Uint8Array(bytes.byteLength);
18668
19964
  digestInput.set(bytes);
18669
19965
  const digest = await crypto.subtle.digest("SHA-256", digestInput.buffer);
18670
- return Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("");
19966
+ return Array.from(new Uint8Array(digest), (byte2) => byte2.toString(16).padStart(2, "0")).join("");
18671
19967
  }
18672
19968
  async function hashTileflowIconPackageManifest(input) {
18673
19969
  return sha256Hex(serializeTileflowIconPackageManifest(input));
@@ -18916,6 +20212,7 @@ function packageBytes(manifest) {
18916
20212
 
18917
20213
  // src/runtime.ts
18918
20214
  init_portable_identity_rules();
20215
+ init_time_of_day();
18919
20216
  var defaultTileflowManifestUrl = "/tileflow/manifest.json";
18920
20217
  var defaultTileflowRuntimeView = Object.freeze({
18921
20218
  bearing: 0,
@@ -18997,7 +20294,8 @@ function resolveTileflowRuntimeStyle(options) {
18997
20294
  const theme = resolveTileflowRuntimeTheme(
18998
20295
  options.manifestMap,
18999
20296
  options.theme,
19000
- options.colorScheme
20297
+ options.colorScheme,
20298
+ options.timeOfDay
19001
20299
  );
19002
20300
  return {
19003
20301
  analytics: {
@@ -19014,7 +20312,7 @@ function resolveTileflowRuntimeStyle(options) {
19014
20312
  }
19015
20313
  return null;
19016
20314
  }
19017
- function resolveTileflowRuntimeTheme(map, selection2, colorScheme) {
20315
+ function resolveTileflowRuntimeTheme(map, selection2, colorScheme, timeOfDay) {
19018
20316
  let name;
19019
20317
  if (selection2 === void 0) {
19020
20318
  name = map.defaultTheme;
@@ -19036,6 +20334,8 @@ function resolveTileflowRuntimeTheme(map, selection2, colorScheme) {
19036
20334
  `Tileflow resolved invalid theme ${JSON.stringify(name)} for map "${map.name}"; expected a concrete portable theme name.`
19037
20335
  );
19038
20336
  }
20337
+ if (Object.hasOwn(map.themes, name))
20338
+ name = resolveTileflowTimeOfDayTheme(map.timeOfDay, name, timeOfDay);
19039
20339
  const theme = Object.hasOwn(map.themes, name) ? map.themes[name] : void 0;
19040
20340
  if (!theme) {
19041
20341
  const available = Object.keys(map.themes).sort().join(", ");
@@ -19571,6 +20871,7 @@ function resolveTileflowManifestMap(manifest, mapName) {
19571
20871
  defaultTheme: entry.defaultTheme,
19572
20872
  ...entry.environment ? { environment: entry.environment } : {},
19573
20873
  ...entry.systemThemes ? { systemThemes: { ...entry.systemThemes } } : {},
20874
+ ...entry.timeOfDay ? { timeOfDay: entry.timeOfDay } : {},
19574
20875
  themes: entry.themes,
19575
20876
  usageMode: entry.usageMode,
19576
20877
  view: entry.view,
@@ -19588,7 +20889,12 @@ function resolveTileflowStaticImageUrl(input) {
19588
20889
  const apiUrl = normalizeTileflowUrl(input.manifestMap.apiUrl ?? "https://api.tileflow.dev");
19589
20890
  const mapId = encodeURIComponent(input.manifestMap.mapId);
19590
20891
  const url = new URL(`/maps/${mapId}/static.png`, apiUrl);
19591
- const theme = resolveTileflowRuntimeTheme(input.manifestMap, input.theme, input.colorScheme);
20892
+ const theme = resolveTileflowRuntimeTheme(
20893
+ input.manifestMap,
20894
+ input.theme,
20895
+ input.colorScheme,
20896
+ input.timeOfDay
20897
+ );
19592
20898
  url.searchParams.set("center", input.center.join(","));
19593
20899
  url.searchParams.set("theme", theme.name);
19594
20900
  url.searchParams.set("zoom", String(input.zoom));
@@ -19704,13 +21010,13 @@ function assertSafeManifestRequestUrl(value) {
19704
21010
  function inferTileflowAnalyticsFromStyleUrl(styleUrl) {
19705
21011
  try {
19706
21012
  const url = new URL(styleUrl, getTileflowLocationOrigin());
19707
- const match2 = url.pathname.match(/^\/maps\/([^/]+)\/style\.json$/);
19708
- if (!match2?.[1]) {
21013
+ const match3 = url.pathname.match(/^\/maps\/([^/]+)\/style\.json$/);
21014
+ if (!match3?.[1]) {
19709
21015
  return void 0;
19710
21016
  }
19711
21017
  return {
19712
21018
  apiUrl: url.origin,
19713
- mapId: match2[1],
21019
+ mapId: match3[1],
19714
21020
  styleId: url.toString()
19715
21021
  };
19716
21022
  } catch {
@@ -20220,7 +21526,7 @@ function decodeTileflowTreeModel(text, level) {
20220
21526
  } catch {
20221
21527
  return void 0;
20222
21528
  }
20223
- if (bytes.length < headerBytes || magic.some((byte, index) => bytes[index] !== byte))
21529
+ if (bytes.length < headerBytes || magic.some((byte2, index) => bytes[index] !== byte2))
20224
21530
  return void 0;
20225
21531
  const view = new DataView(bytes.buffer);
20226
21532
  const count = view.getUint16(6, true);
@@ -20257,6 +21563,653 @@ function decodeTileflowTreeModel(text, level) {
20257
21563
  function clamp(value, low, high) {
20258
21564
  return Number.isFinite(value) ? Math.min(high, Math.max(low, value)) : 0;
20259
21565
  }
21566
+
21567
+ // src/models-3d-file.ts
21568
+ var tileflowModelContentType = "model/gltf-binary";
21569
+ var levelNames = ["near", "mid", "far"];
21570
+ var meshopt = "EXT_meshopt_compression";
21571
+ var quantisation = "KHR_mesh_quantization";
21572
+ var steps = 32767;
21573
+ var partCount2 = Object.keys(tileflowModelParts).length;
21574
+ var modelId2 = /^[a-z0-9]+(?:-[a-z0-9]+)*$/u;
21575
+ var [glbMagic, jsonChunk, binChunk] = [1179937895, 1313821514, 5130562];
21576
+ var [short, byte, unsignedByte, unsignedShort, unsignedInt] = [5122, 5120, 5121, 5123, 5125];
21577
+ function encodeTileflowModels(models, compressor) {
21578
+ if (models.length < 1 || models.length > tileflowModelLimits.models)
21579
+ throw new RangeError(`A model file holds 1 to ${tileflowModelLimits.models} models.`);
21580
+ if (new Set(models.map((model) => model.id)).size !== models.length)
21581
+ throw new RangeError("The models of a file have different ids.");
21582
+ const extensions = compressor ? [meshopt, quantisation] : [quantisation];
21583
+ const nodes = [];
21584
+ const meshes = [];
21585
+ const accessors = [];
21586
+ const bufferViews = [];
21587
+ const roots = [];
21588
+ const blobs = [];
21589
+ let binLength = 0;
21590
+ let fallbackLength = 0;
21591
+ const addBlob = (bytes) => {
21592
+ const padding = (4 - binLength % 4) % 4;
21593
+ if (padding) blobs.push(new Uint8Array(padding));
21594
+ const offset = binLength + padding;
21595
+ blobs.push(bytes);
21596
+ binLength = offset + bytes.byteLength;
21597
+ return offset;
21598
+ };
21599
+ const addView = (bytes, count, stride, vertices) => {
21600
+ const target = vertices ? 34962 : 34963;
21601
+ if (!compressor) {
21602
+ const byteOffset2 = addBlob(bytes);
21603
+ bufferViews.push({
21604
+ buffer: 0,
21605
+ byteOffset: byteOffset2,
21606
+ byteLength: bytes.byteLength,
21607
+ ...vertices ? { byteStride: stride } : {},
21608
+ target
21609
+ });
21610
+ return bufferViews.length - 1;
21611
+ }
21612
+ const mode = vertices ? "ATTRIBUTES" : "TRIANGLES";
21613
+ const packed = compressor.encodeGltfBuffer(bytes, count, stride, mode);
21614
+ const byteOffset = addBlob(packed);
21615
+ const fallbackOffset = fallbackLength;
21616
+ fallbackLength += bytes.byteLength + (4 - bytes.byteLength % 4) % 4;
21617
+ bufferViews.push({
21618
+ buffer: 1,
21619
+ byteOffset: fallbackOffset,
21620
+ byteLength: bytes.byteLength,
21621
+ ...vertices ? { byteStride: stride } : {},
21622
+ target,
21623
+ extensions: {
21624
+ [meshopt]: {
21625
+ buffer: 0,
21626
+ byteOffset,
21627
+ byteLength: packed.byteLength,
21628
+ byteStride: stride,
21629
+ count,
21630
+ mode
21631
+ }
21632
+ }
21633
+ });
21634
+ return bufferViews.length - 1;
21635
+ };
21636
+ for (const model of models) {
21637
+ checkModel(model);
21638
+ const children = [];
21639
+ for (const [index, mesh] of model.levels.entries()) {
21640
+ const level = quantise(mesh, compressor);
21641
+ const vertexView = addView(level.vertices, level.count, tileflowModelVertexBytes, true);
21642
+ const width = level.indices instanceof Uint32Array ? 4 : 2;
21643
+ const indexView = addView(
21644
+ new Uint8Array(level.indices.buffer, level.indices.byteOffset, level.indices.byteLength),
21645
+ level.indices.length,
21646
+ width,
21647
+ false
21648
+ );
21649
+ const first = accessors.length;
21650
+ accessors.push(
21651
+ {
21652
+ bufferView: vertexView,
21653
+ byteOffset: 0,
21654
+ componentType: short,
21655
+ count: level.count,
21656
+ type: "VEC3",
21657
+ min: level.min,
21658
+ max: level.max
21659
+ },
21660
+ {
21661
+ bufferView: vertexView,
21662
+ byteOffset: 8,
21663
+ componentType: byte,
21664
+ normalized: true,
21665
+ count: level.count,
21666
+ type: "VEC3"
21667
+ },
21668
+ {
21669
+ bufferView: vertexView,
21670
+ byteOffset: 12,
21671
+ componentType: unsignedByte,
21672
+ count: level.count,
21673
+ type: "VEC3"
21674
+ },
21675
+ {
21676
+ bufferView: indexView,
21677
+ componentType: width === 4 ? unsignedInt : unsignedShort,
21678
+ count: level.indices.length,
21679
+ type: "SCALAR"
21680
+ }
21681
+ );
21682
+ meshes.push({
21683
+ primitives: [
21684
+ {
21685
+ attributes: { POSITION: first, NORMAL: first + 1, _PAINT: first + 2 },
21686
+ indices: first + 3,
21687
+ mode: 4
21688
+ }
21689
+ ]
21690
+ });
21691
+ children.push(nodes.length);
21692
+ nodes.push({
21693
+ name: levelNames[index],
21694
+ mesh: meshes.length - 1,
21695
+ translation: [...level.centre],
21696
+ scale: [level.step, level.step, level.step]
21697
+ });
21698
+ }
21699
+ roots.push(nodes.length);
21700
+ nodes.push({
21701
+ name: model.id,
21702
+ children,
21703
+ extras: {
21704
+ tileflow: {
21705
+ model: model.id,
21706
+ footprint: model.footprint.map((ring) => ring.map((value) => round2(value, 100))),
21707
+ ...model.at ? { at: [model.at[0], model.at[1]] } : {},
21708
+ ...model.heading !== void 0 ? { heading: model.heading } : {}
21709
+ }
21710
+ }
21711
+ });
21712
+ }
21713
+ const json = {
21714
+ asset: { version: "2.0", generator: "Tileflow" },
21715
+ extensionsUsed: extensions,
21716
+ extensionsRequired: extensions,
21717
+ scene: 0,
21718
+ scenes: [{ nodes: roots }],
21719
+ nodes,
21720
+ meshes,
21721
+ accessors,
21722
+ bufferViews,
21723
+ buffers: [
21724
+ { byteLength: binLength },
21725
+ ...compressor ? [{ byteLength: fallbackLength, extensions: { [meshopt]: { fallback: true } } }] : []
21726
+ ]
21727
+ };
21728
+ const file = glb(new TextEncoder().encode(JSON.stringify(json)), blobs, binLength);
21729
+ if (file.byteLength > tileflowModelLimits.bytes)
21730
+ throw new RangeError(`A prepared model file is at most ${tileflowModelLimits.bytes} bytes.`);
21731
+ return file;
21732
+ }
21733
+ async function decodeTileflowModels(buffer, decompressor) {
21734
+ try {
21735
+ const bytes = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);
21736
+ const { json, bin } = readGlb(bytes);
21737
+ const required = Array.isArray(json.extensionsRequired) ? json.extensionsRequired : [];
21738
+ if (json.asset?.version !== "2.0" || required.some((name) => name !== meshopt && name !== quantisation))
21739
+ return void 0;
21740
+ const views = json.bufferViews ?? [];
21741
+ const compressed = views.some((view) => view?.extensions?.[meshopt]);
21742
+ const decoder = compressed ? decompressor ?? await meshoptDecoder() : void 0;
21743
+ const decoded = /* @__PURE__ */ new Map();
21744
+ const viewBytes = (index, stride, length) => {
21745
+ const view = views[index];
21746
+ if (!Number.isInteger(index) || !view || view.byteLength !== length) throw new Error();
21747
+ if ((view.byteStride ?? stride) !== stride) throw new Error();
21748
+ const cached = decoded.get(index);
21749
+ if (cached) return cached;
21750
+ const packed = view.extensions?.[meshopt];
21751
+ let out;
21752
+ if (packed) {
21753
+ const {
21754
+ buffer: source,
21755
+ byteOffset = 0,
21756
+ byteLength,
21757
+ byteStride,
21758
+ count,
21759
+ mode,
21760
+ filter
21761
+ } = packed;
21762
+ if (source !== 0 || byteStride !== stride || count * byteStride !== length)
21763
+ throw new Error();
21764
+ if (filter !== void 0 && filter !== "NONE") throw new Error();
21765
+ if (mode !== (stride === tileflowModelVertexBytes ? "ATTRIBUTES" : "TRIANGLES"))
21766
+ throw new Error();
21767
+ out = new Uint8Array(length);
21768
+ decoder.decodeGltfBuffer(out, count, byteStride, slice(bin, byteOffset, byteLength), mode);
21769
+ } else {
21770
+ if (view.buffer !== 0) throw new Error();
21771
+ out = slice(bin, view.byteOffset ?? 0, length).slice();
21772
+ }
21773
+ decoded.set(index, out);
21774
+ return out;
21775
+ };
21776
+ const roots = json.scenes?.[json.scene ?? 0]?.nodes ?? [];
21777
+ if (roots.length < 1 || roots.length > tileflowModelLimits.models) return void 0;
21778
+ const models = [];
21779
+ for (const root of roots) {
21780
+ const node2 = json.nodes?.[root];
21781
+ const model = readModelNode(node2);
21782
+ const children = Array.isArray(node2.children) ? node2.children : [];
21783
+ if (children.length < 1 || children.length > tileflowModelLimits.levels) return void 0;
21784
+ const levels = [];
21785
+ const bounds = [Infinity, Infinity, Infinity, -Infinity, -Infinity, -Infinity];
21786
+ for (const [at, child] of children.entries()) {
21787
+ const level = readLevelNode(
21788
+ json,
21789
+ json.nodes?.[child],
21790
+ levelNames[at],
21791
+ viewBytes
21792
+ );
21793
+ const low = level.min.map((value, axis) => level.centre[axis] + value * level.step);
21794
+ const high = level.max.map((value, axis) => level.centre[axis] + value * level.step);
21795
+ const box = [low[0], -high[2], low[1], high[0], -low[2], high[1]];
21796
+ for (let axis = 0; axis < 3; axis += 1) {
21797
+ bounds[axis] = Math.min(bounds[axis], box[axis]);
21798
+ bounds[axis + 3] = Math.max(bounds[axis + 3], box[axis + 3]);
21799
+ }
21800
+ levels.push({
21801
+ vertices: level.vertices,
21802
+ indices: level.indices,
21803
+ centre: level.centre,
21804
+ step: level.step
21805
+ });
21806
+ }
21807
+ models.push({
21808
+ ...model,
21809
+ bounds,
21810
+ levels
21811
+ });
21812
+ }
21813
+ return models;
21814
+ } catch {
21815
+ return void 0;
21816
+ }
21817
+ }
21818
+ var decoderLoad;
21819
+ function meshoptDecoder() {
21820
+ decoderLoad ??= Promise.resolve().then(() => (init_meshopt_decoder(), meshopt_decoder_exports)).then(
21821
+ async ({ MeshoptDecoder: MeshoptDecoder2 }) => {
21822
+ await MeshoptDecoder2.ready;
21823
+ return MeshoptDecoder2;
21824
+ },
21825
+ (error) => {
21826
+ decoderLoad = void 0;
21827
+ throw error;
21828
+ }
21829
+ );
21830
+ return decoderLoad;
21831
+ }
21832
+ function quantise(mesh, compressor) {
21833
+ const count = mesh.positions.length / 3;
21834
+ const axes = (index) => [
21835
+ mesh.positions[index * 3],
21836
+ mesh.positions[index * 3 + 2],
21837
+ -mesh.positions[index * 3 + 1]
21838
+ ];
21839
+ const low = [Infinity, Infinity, Infinity];
21840
+ const high = [-Infinity, -Infinity, -Infinity];
21841
+ for (let vertex = 0; vertex < count; vertex += 1) {
21842
+ const point = axes(vertex);
21843
+ for (let axis = 0; axis < 3; axis += 1) {
21844
+ low[axis] = Math.min(low[axis], point[axis]);
21845
+ high[axis] = Math.max(high[axis], point[axis]);
21846
+ }
21847
+ }
21848
+ const centre = low.map((value, axis) => round2((value + high[axis]) / 2, 1e3));
21849
+ const reach = Math.max(
21850
+ ...low.map((value, axis) => Math.max(centre[axis] - value, high[axis] - centre[axis]))
21851
+ );
21852
+ const step2 = Math.max(reach, 1e-3) / steps;
21853
+ const raw = new Uint8Array(count * tileflowModelVertexBytes);
21854
+ const view = new DataView(raw.buffer);
21855
+ for (let vertex = 0; vertex < count; vertex += 1) {
21856
+ const at = vertex * tileflowModelVertexBytes;
21857
+ const point = axes(vertex);
21858
+ for (let axis = 0; axis < 3; axis += 1)
21859
+ view.setInt16(
21860
+ at + axis * 2,
21861
+ clamp2(Math.round((point[axis] - centre[axis]) / step2), -steps, steps),
21862
+ true
21863
+ );
21864
+ const [nx, ny, nz] = [
21865
+ mesh.normals[vertex * 3],
21866
+ mesh.normals[vertex * 3 + 1],
21867
+ mesh.normals[vertex * 3 + 2]
21868
+ ];
21869
+ const length = Math.hypot(nx, ny, nz) || 1;
21870
+ const normal = [nx / length, nz / length, -ny / length];
21871
+ for (let axis = 0; axis < 3; axis += 1)
21872
+ view.setInt8(at + 8 + axis, clamp2(Math.round(normal[axis] * 127), -127, 127));
21873
+ const part = mesh.parts[vertex];
21874
+ if (!Number.isInteger(part) || part < 0 || part >= partCount2)
21875
+ throw new RangeError(`Vertex ${vertex} has no part.`);
21876
+ raw[at + 12] = part;
21877
+ raw[at + 13] = Math.round((clamp2(mesh.shades[vertex], -1, 1) + 1) / 2 * 255);
21878
+ raw[at + 14] = Math.round(clamp2(mesh.occlusion[vertex], 0, 1) * 255);
21879
+ }
21880
+ const words = new Uint32Array(raw.buffer);
21881
+ const seen = /* @__PURE__ */ new Map();
21882
+ const weld = new Uint32Array(count);
21883
+ const kept = [];
21884
+ for (let vertex = 0; vertex < count; vertex += 1) {
21885
+ const w = vertex * 4;
21886
+ const key = `${words[w]},${words[w + 1]},${words[w + 2]},${words[w + 3]}`;
21887
+ let index = seen.get(key);
21888
+ if (index === void 0) {
21889
+ index = kept.length;
21890
+ seen.set(key, index);
21891
+ kept.push(vertex);
21892
+ }
21893
+ weld[vertex] = index;
21894
+ }
21895
+ const indices = new Uint32Array(mesh.indices.length);
21896
+ for (const [position, vertex] of mesh.indices.entries()) {
21897
+ if (!Number.isInteger(vertex) || vertex < 0 || vertex >= count)
21898
+ throw new RangeError(`Index ${position} names no vertex.`);
21899
+ indices[position] = weld[vertex];
21900
+ }
21901
+ let order = kept;
21902
+ if (compressor) {
21903
+ const [remap, unique] = compressor.reorderMesh(indices, true, true);
21904
+ order = new Array(unique);
21905
+ for (const [index, vertex] of kept.entries())
21906
+ if (remap[index] !== 4294967295) order[remap[index]] = vertex;
21907
+ }
21908
+ const vertices = new Uint8Array(order.length * tileflowModelVertexBytes);
21909
+ const min = [Infinity, Infinity, Infinity];
21910
+ const max = [-Infinity, -Infinity, -Infinity];
21911
+ for (const [index, vertex] of order.entries()) {
21912
+ vertices.set(
21913
+ raw.subarray(vertex * tileflowModelVertexBytes, (vertex + 1) * tileflowModelVertexBytes),
21914
+ index * tileflowModelVertexBytes
21915
+ );
21916
+ for (let axis = 0; axis < 3; axis += 1) {
21917
+ const value = view.getInt16(vertex * tileflowModelVertexBytes + axis * 2, true);
21918
+ min[axis] = Math.min(min[axis], value);
21919
+ max[axis] = Math.max(max[axis], value);
21920
+ }
21921
+ }
21922
+ return {
21923
+ vertices,
21924
+ indices: order.length > 65535 ? indices : Uint16Array.from(indices),
21925
+ count: order.length,
21926
+ centre,
21927
+ step: step2,
21928
+ min,
21929
+ max
21930
+ };
21931
+ }
21932
+ function checkModel(model) {
21933
+ const { id: id2, levels, footprint } = model;
21934
+ if (!modelId2.test(id2) || id2.length > 64)
21935
+ throw new RangeError(`"${id2}" is not a model id: lower-case words joined by hyphens.`);
21936
+ if (levels.length < 1 || levels.length > tileflowModelLimits.levels)
21937
+ throw new RangeError(`A model has 1 to ${tileflowModelLimits.levels} levels of detail.`);
21938
+ const bounds = [Infinity, Infinity, Infinity, -Infinity, -Infinity, -Infinity];
21939
+ for (const [at, level] of levels.entries()) {
21940
+ const count = level.positions.length / 3;
21941
+ const triangles = level.indices.length / 3;
21942
+ if (!Number.isInteger(count) || count < 3 || count > tileflowModelLimits.vertices)
21943
+ throw new RangeError(`Level ${at} has 3 to ${tileflowModelLimits.vertices} vertices.`);
21944
+ if (!Number.isInteger(triangles) || triangles < 1 || triangles > tileflowModelLimits.triangles)
21945
+ throw new RangeError(`Level ${at} has 1 to ${tileflowModelLimits.triangles} triangles.`);
21946
+ if (level.normals.length !== count * 3)
21947
+ throw new RangeError(`Every vertex of level ${at} needs a position and a normal.`);
21948
+ for (const list of [level.parts, level.shades, level.occlusion])
21949
+ if (list.length !== count)
21950
+ throw new RangeError(`Every vertex of level ${at} needs a part, a shade and a light.`);
21951
+ for (let index = 0; index < count; index += 1)
21952
+ for (let axis = 0; axis < 3; axis += 1) {
21953
+ const value = level.positions[index * 3 + axis];
21954
+ if (!Number.isFinite(value)) throw new RangeError(`Level ${at} has a vertex at no place.`);
21955
+ bounds[axis] = Math.min(bounds[axis], value);
21956
+ bounds[axis + 3] = Math.max(bounds[axis + 3], value);
21957
+ }
21958
+ }
21959
+ const radius = Math.max(...[0, 1, 3, 4].map((axis) => Math.abs(bounds[axis])));
21960
+ if (radius > tileflowModelLimits.radius)
21961
+ throw new RangeError(
21962
+ `A model reaches at most ${tileflowModelLimits.radius} m from its origin.`
21963
+ );
21964
+ if (bounds[2] < -0.5)
21965
+ throw new RangeError("A model stands on the ground: no vertex lies more than 0.5 m below it.");
21966
+ if (bounds[5] > tileflowModelLimits.height)
21967
+ throw new RangeError(`A model is at most ${tileflowModelLimits.height} m tall.`);
21968
+ if (footprint.some((ring) => ring.length < 6 || ring.length % 2 !== 0))
21969
+ throw new RangeError("A footprint ring has at least three points.");
21970
+ if (footprint.some((ring) => ring.some((value) => !Number.isFinite(value))))
21971
+ throw new RangeError("A footprint point has no place.");
21972
+ if (footprint.reduce((sum, ring) => sum + ring.length / 2, 0) > tileflowModelLimits.footprintPoints)
21973
+ throw new RangeError(
21974
+ `A footprint has at most ${tileflowModelLimits.footprintPoints} points in all.`
21975
+ );
21976
+ if (model.at && !placed(model.at))
21977
+ throw new RangeError(`Model ${id2} stands at no place on the map.`);
21978
+ if (model.heading !== void 0 && !(model.heading >= 0 && model.heading < 360))
21979
+ throw new RangeError(`Model ${id2} is turned 0 to 360 degrees.`);
21980
+ }
21981
+ function readModelNode(node2) {
21982
+ const own = node2?.extras?.tileflow;
21983
+ if (!own || typeof own.model !== "string" || !modelId2.test(own.model)) throw new Error();
21984
+ const footprint = Array.isArray(own.footprint) ? own.footprint : [];
21985
+ let points = 0;
21986
+ for (const ring of footprint) {
21987
+ if (!Array.isArray(ring) || ring.length < 6 || ring.length % 2 !== 0) throw new Error();
21988
+ if (ring.some((value) => typeof value !== "number" || !Number.isFinite(value)))
21989
+ throw new Error();
21990
+ points += ring.length / 2;
21991
+ }
21992
+ if (points > tileflowModelLimits.footprintPoints) throw new Error();
21993
+ if (own.at !== void 0 && !placed(own.at)) throw new Error();
21994
+ if (own.heading !== void 0 && !(typeof own.heading === "number" && own.heading >= 0 && own.heading < 360))
21995
+ throw new Error();
21996
+ return {
21997
+ id: own.model,
21998
+ footprint,
21999
+ ...own.at ? { at: [own.at[0], own.at[1]] } : {},
22000
+ ...own.heading !== void 0 ? { heading: own.heading } : {}
22001
+ };
22002
+ }
22003
+ function readLevelNode(json, node2, name, viewBytes) {
22004
+ if (node2?.name !== name || node2.matrix !== void 0 || node2.rotation !== void 0)
22005
+ throw new Error();
22006
+ const centre = node2.translation;
22007
+ const scale = node2.scale;
22008
+ if (!Array.isArray(centre) || centre.length !== 3 || !centre.every(Number.isFinite))
22009
+ throw new Error();
22010
+ if (!Array.isArray(scale) || scale.length !== 3 || !(scale[0] > 0) || scale.some((value) => value !== scale[0]))
22011
+ throw new Error();
22012
+ const primitives = json.meshes?.[node2.mesh]?.primitives;
22013
+ if (!Array.isArray(primitives) || primitives.length !== 1) throw new Error();
22014
+ const primitive = primitives[0];
22015
+ const names = Object.keys(primitive.attributes ?? {}).sort();
22016
+ if ((primitive.mode ?? 4) !== 4 || names.join() !== "NORMAL,POSITION,_PAINT") throw new Error();
22017
+ const accessor = (index2) => json.accessors?.[index2];
22018
+ const position = accessor(primitive.attributes.POSITION);
22019
+ const normal = accessor(primitive.attributes.NORMAL);
22020
+ const paint = accessor(primitive.attributes._PAINT);
22021
+ const index = accessor(primitive.indices);
22022
+ const count = position?.count;
22023
+ if (!Number.isInteger(count) || count < 3 || count > tileflowModelLimits.vertices)
22024
+ throw new Error();
22025
+ const attribute = (value, offset, type, normalized) => value?.bufferView === position.bufferView && (value.byteOffset ?? 0) === offset && value.componentType === type && (value.normalized ?? false) === normalized && value.type === "VEC3" && value.count === count;
22026
+ if (!attribute(position, 0, short, false) || !attribute(normal, 8, byte, true) || !attribute(paint, 12, unsignedByte, false))
22027
+ throw new Error();
22028
+ const min = position.min;
22029
+ const max = position.max;
22030
+ if (![min, max].every(
22031
+ (list) => Array.isArray(list) && list.length === 3 && list.every(Number.isFinite)
22032
+ ))
22033
+ throw new Error();
22034
+ const width = index?.componentType === unsignedInt ? 4 : index?.componentType === unsignedShort ? 2 : 0;
22035
+ const indexCount = index?.count;
22036
+ if (!width || index.type !== "SCALAR" || (index.byteOffset ?? 0) !== 0 || !Number.isInteger(indexCount) || indexCount < 3 || indexCount % 3 !== 0 || indexCount / 3 > tileflowModelLimits.triangles)
22037
+ throw new Error();
22038
+ const vertices = viewBytes(
22039
+ position.bufferView,
22040
+ tileflowModelVertexBytes,
22041
+ count * tileflowModelVertexBytes
22042
+ );
22043
+ for (let vertex = 0; vertex < count; vertex += 1)
22044
+ if (vertices[vertex * tileflowModelVertexBytes + 12] >= partCount2) throw new Error();
22045
+ const indexBytes = viewBytes(index.bufferView, width, indexCount * width);
22046
+ const indices = width === 4 ? new Uint32Array(indexBytes.buffer, indexBytes.byteOffset, indexCount) : new Uint16Array(indexBytes.buffer, indexBytes.byteOffset, indexCount);
22047
+ for (const vertex of indices) if (vertex >= count) throw new Error();
22048
+ return {
22049
+ vertices,
22050
+ indices,
22051
+ centre: [centre[0], centre[1], centre[2]],
22052
+ step: scale[0],
22053
+ min,
22054
+ max
22055
+ };
22056
+ }
22057
+ function readGlb(bytes) {
22058
+ if (bytes.byteLength < 20 || bytes.byteLength > tileflowModelLimits.bytes) throw new Error();
22059
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
22060
+ if (view.getUint32(0, true) !== glbMagic || view.getUint32(4, true) !== 2) throw new Error();
22061
+ if (view.getUint32(8, true) !== bytes.byteLength) throw new Error();
22062
+ const jsonLength = view.getUint32(12, true);
22063
+ if (view.getUint32(16, true) !== jsonChunk || 20 + jsonLength > bytes.byteLength)
22064
+ throw new Error();
22065
+ const json = JSON.parse(new TextDecoder().decode(bytes.subarray(20, 20 + jsonLength)));
22066
+ let bin = new Uint8Array(0);
22067
+ const at = 20 + jsonLength;
22068
+ if (at + 8 <= bytes.byteLength) {
22069
+ const binLength = view.getUint32(at, true);
22070
+ if (view.getUint32(at + 4, true) !== binChunk || at + 8 + binLength > bytes.byteLength)
22071
+ throw new Error();
22072
+ bin = bytes.subarray(at + 8, at + 8 + binLength);
22073
+ }
22074
+ if (typeof json !== "object" || json === null) throw new Error();
22075
+ return { json, bin };
22076
+ }
22077
+ function glb(json, blobs, binLength) {
22078
+ const jsonLength = json.byteLength + (4 - json.byteLength % 4) % 4;
22079
+ const binPadded = binLength + (4 - binLength % 4) % 4;
22080
+ const total = 12 + 8 + jsonLength + (binLength > 0 ? 8 + binPadded : 0);
22081
+ const out = new Uint8Array(total);
22082
+ const view = new DataView(out.buffer);
22083
+ view.setUint32(0, glbMagic, true);
22084
+ view.setUint32(4, 2, true);
22085
+ view.setUint32(8, total, true);
22086
+ view.setUint32(12, jsonLength, true);
22087
+ view.setUint32(16, jsonChunk, true);
22088
+ out.set(json, 20);
22089
+ out.fill(32, 20 + json.byteLength, 20 + jsonLength);
22090
+ if (binLength > 0) {
22091
+ const at = 20 + jsonLength;
22092
+ view.setUint32(at, binPadded, true);
22093
+ view.setUint32(at + 4, binChunk, true);
22094
+ let offset = at + 8;
22095
+ for (const blob of blobs) {
22096
+ out.set(blob, offset);
22097
+ offset += blob.byteLength;
22098
+ }
22099
+ }
22100
+ return out;
22101
+ }
22102
+ function slice(bin, offset, length) {
22103
+ if (!Number.isInteger(offset) || !Number.isInteger(length)) throw new Error();
22104
+ const start = offset;
22105
+ const end = start + length;
22106
+ if (start < 0 || end > bin.byteLength) throw new Error();
22107
+ return bin.subarray(start, end);
22108
+ }
22109
+ function placed(at) {
22110
+ if (!Array.isArray(at) || at.length !== 2) return false;
22111
+ const [longitude, latitude] = at;
22112
+ return typeof longitude === "number" && typeof latitude === "number" && longitude >= -180 && longitude <= 180 && latitude >= -85 && latitude <= 85;
22113
+ }
22114
+ function round2(value, scale) {
22115
+ return Math.round(value * scale) / scale;
22116
+ }
22117
+ function clamp2(value, low, high) {
22118
+ return Number.isFinite(value) ? Math.min(high, Math.max(low, value)) : 0;
22119
+ }
22120
+
22121
+ // src/models-3d-landmarks.ts
22122
+ var tileflowLandmarkTileZoom = 14;
22123
+ var tileflowLandmarkRegionZoom = 6;
22124
+ var sha256 = /^[a-f0-9]{64}$/u;
22125
+ function tileflowLandmarkTileOf(at) {
22126
+ const [longitude, latitude] = at;
22127
+ if (!(longitude >= -180 && longitude <= 180 && latitude >= -85 && latitude <= 85))
22128
+ throw new RangeError("A landmark stands at a longitude and a latitude on the map.");
22129
+ const n = 2 ** tileflowLandmarkTileZoom;
22130
+ const phi = latitude * Math.PI / 180;
22131
+ return [
22132
+ Math.min(n - 1, Math.floor((longitude + 180) / 360 * n)),
22133
+ Math.floor((1 - Math.log(Math.tan(phi) + 1 / Math.cos(phi)) / Math.PI) / 2 * n)
22134
+ ];
22135
+ }
22136
+ function tileflowLandmarkRegionOf(tile) {
22137
+ const shift = 2 ** (tileflowLandmarkTileZoom - tileflowLandmarkRegionZoom);
22138
+ return [Math.floor(tile[0] / shift), Math.floor(tile[1] / shift)];
22139
+ }
22140
+ function serializeTileflowLandmarkRegion(region) {
22141
+ const [x, y] = region.region;
22142
+ const regions2 = 2 ** tileflowLandmarkRegionZoom;
22143
+ if (![x, y].every((value) => Number.isInteger(value) && value >= 0 && value < regions2))
22144
+ throw new RangeError(`A region is a zoom-${tileflowLandmarkRegionZoom} tile.`);
22145
+ const tiles = [...region.tiles].sort((a, b) => a[0] - b[0] || a[1] - b[1]);
22146
+ for (const [at, [tx, ty, hash]] of tiles.entries()) {
22147
+ const [rx, ry] = tileflowLandmarkRegionOf([tx, ty]);
22148
+ if (!Number.isInteger(tx) || !Number.isInteger(ty) || rx !== x || ry !== y)
22149
+ throw new RangeError(`Tile ${tx}/${ty} lies outside region ${x}/${y}.`);
22150
+ if (!sha256.test(hash)) throw new RangeError(`Tile ${tx}/${ty} has no SHA-256.`);
22151
+ const before = tiles[at - 1];
22152
+ if (before && before[0] === tx && before[1] === ty)
22153
+ throw new RangeError(`Tile ${tx}/${ty} appears twice.`);
22154
+ }
22155
+ if (tiles.length === 0) throw new RangeError("A region index names at least one tile.");
22156
+ return new TextEncoder().encode(
22157
+ JSON.stringify({
22158
+ format: "tileflow-landmark-region-v1",
22159
+ zoom: tileflowLandmarkTileZoom,
22160
+ region: [tileflowLandmarkRegionZoom, x, y],
22161
+ tiles: tiles.map(([tx, ty, hash]) => [tx, ty, hash])
22162
+ })
22163
+ );
22164
+ }
22165
+ function readTileflowLandmarkRegion(json) {
22166
+ if (!isRecord16(json) || json.format !== "tileflow-landmark-region-v1") return void 0;
22167
+ const region = json.region;
22168
+ if (json.zoom !== tileflowLandmarkTileZoom || !Array.isArray(region) || region.length !== 3 || region[0] !== tileflowLandmarkRegionZoom || !Array.isArray(json.tiles))
22169
+ return void 0;
22170
+ const [, x, y] = region;
22171
+ if (!Number.isInteger(x) || !Number.isInteger(y)) return void 0;
22172
+ const tiles = [];
22173
+ for (const tile of json.tiles) {
22174
+ if (!Array.isArray(tile) || tile.length !== 3) return void 0;
22175
+ const [tx, ty, hash] = tile;
22176
+ if (!Number.isInteger(tx) || !Number.isInteger(ty) || typeof hash !== "string")
22177
+ return void 0;
22178
+ if (!sha256.test(hash)) return void 0;
22179
+ const [rx, ry] = tileflowLandmarkRegionOf([tx, ty]);
22180
+ if (rx !== x || ry !== y) return void 0;
22181
+ tiles.push([tx, ty, hash]);
22182
+ }
22183
+ return { region: [x, y], tiles };
22184
+ }
22185
+ function readTileflowLandmarksTileJson(json, url) {
22186
+ if (!isRecord16(json) || json.format !== "tileflow-landmarks-v2") return void 0;
22187
+ const tile = Array.isArray(json.tiles) ? json.tiles[0] : void 0;
22188
+ const regions2 = json.regions;
22189
+ if (typeof tile !== "string" || !tile.includes("{sha256}") || json.minzoom !== tileflowLandmarkTileZoom || json.maxzoom !== tileflowLandmarkTileZoom || !isRecord16(regions2) || regions2.zoom !== tileflowLandmarkRegionZoom || typeof regions2.url !== "string" || !regions2.url.includes("{x}") || !regions2.url.includes("{y}") || !Array.isArray(regions2.available))
22190
+ return void 0;
22191
+ const available = /* @__PURE__ */ new Set();
22192
+ for (const region of regions2.available) {
22193
+ if (!Array.isArray(region) || region.length !== 2) return void 0;
22194
+ const [x, y] = region;
22195
+ if (!Number.isInteger(x) || !Number.isInteger(y)) return void 0;
22196
+ available.add(`${x}/${y}`);
22197
+ }
22198
+ return {
22199
+ url,
22200
+ tile,
22201
+ region: regions2.url,
22202
+ tileZoom: tileflowLandmarkTileZoom,
22203
+ regionZoom: tileflowLandmarkRegionZoom,
22204
+ regions: available
22205
+ };
22206
+ }
22207
+ function isRecord16(value) {
22208
+ return typeof value === "object" && value !== null && !Array.isArray(value);
22209
+ }
22210
+
22211
+ // src/index.ts
22212
+ init_time_of_day();
20260
22213
  export {
20261
22214
  TileflowIconSetError,
20262
22215
  TileflowMapResolutionError,
@@ -20285,6 +22238,7 @@ export {
20285
22238
  createTileflowLineBackgroundFontStack,
20286
22239
  createTileflowSessionController,
20287
22240
  createTileflowSessionId,
22241
+ decodeTileflowModels,
20288
22242
  decodeTileflowTreeModel,
20289
22243
  defaultTileflowManifestUrl,
20290
22244
  defaultTileflowRuntimeView,
@@ -20294,6 +22248,7 @@ export {
20294
22248
  diffTileflowIconPackageManifests,
20295
22249
  diffTileflowMaps,
20296
22250
  disable,
22251
+ encodeTileflowModels,
20297
22252
  encodeTileflowTreeModel,
20298
22253
  expr,
20299
22254
  field,
@@ -20316,6 +22271,7 @@ export {
20316
22271
  isTileflowLocalDirectory,
20317
22272
  isTileflowPortableId,
20318
22273
  isTileflowThemeName,
22274
+ isTileflowTimeOfDay,
20319
22275
  isTileflowWorldReleaseId,
20320
22276
  labels,
20321
22277
  land,
@@ -20345,9 +22301,12 @@ export {
20345
22301
  poi,
20346
22302
  readTileflowBuildings3D,
20347
22303
  readTileflowIconLayout,
22304
+ readTileflowLandmarkRegion,
22305
+ readTileflowLandmarksTileJson,
20348
22306
  readTileflowStreetLights,
20349
22307
  readTileflowSunPreset,
20350
22308
  readTileflowVegetation3D,
22309
+ readTileflowVegetationDisplay,
20351
22310
  refine,
20352
22311
  refineRenderTarget,
20353
22312
  remove,
@@ -20371,6 +22330,7 @@ export {
20371
22330
  resolveTileflowStaticImageUrl,
20372
22331
  resolveTileflowSun,
20373
22332
  resolveTileflowTheme,
22333
+ resolveTileflowVegetationRepresentation,
20374
22334
  roads,
20375
22335
  safeParseTileflowRuntimeManifest,
20376
22336
  scaleTileflowIconLayout,
@@ -20379,6 +22339,7 @@ export {
20379
22339
  serializeTileflowFontBundleManifest,
20380
22340
  serializeTileflowIconPackageManifest,
20381
22341
  serializeTileflowIconsLockfile,
22342
+ serializeTileflowLandmarkRegion,
20382
22343
  sha256Hex,
20383
22344
  shouldLoadTileflowManifest,
20384
22345
  startTileflowSession,
@@ -20386,8 +22347,10 @@ export {
20386
22347
  tileflowAuthoringManifestSchemaVersion,
20387
22348
  tileflowBandPlacements,
20388
22349
  tileflowBathymetryDemSourceId,
22350
+ tileflowBathymetryNameLayerLimits,
20389
22351
  tileflowBathymetrySourceId,
20390
22352
  tileflowBathymetryV1Schema,
22353
+ tileflowBuildingModelPlacementLimit,
20391
22354
  tileflowBuildingsMetadataKey,
20392
22355
  tileflowCaptureApplicationTargetSchema,
20393
22356
  tileflowCaptureBoundsCameraSchema,
@@ -20446,7 +22409,12 @@ export {
20446
22409
  tileflowIconsLockfileMaximumBytes,
20447
22410
  tileflowIconsLockfileName,
20448
22411
  tileflowIconsLockfileSchema,
22412
+ tileflowInsideRings,
20449
22413
  tileflowLandformClasses,
22414
+ tileflowLandmarkRegionOf,
22415
+ tileflowLandmarkRegionZoom,
22416
+ tileflowLandmarkTileOf,
22417
+ tileflowLandmarkTileZoom,
20450
22418
  tileflowLayerBands,
20451
22419
  tileflowLineBackgroundDefaults,
20452
22420
  tileflowLineBackgroundHaloRatio,
@@ -20455,10 +22423,15 @@ export {
20455
22423
  tileflowLocalDirectoryMessage,
20456
22424
  tileflowMapDefaultMaxDepth,
20457
22425
  tileflowMapIdSchema,
22426
+ tileflowModelContentType,
22427
+ tileflowModelLimits,
22428
+ tileflowModelParts,
22429
+ tileflowModelVertexBytes,
20458
22430
  tileflowNauticalSourceId,
20459
22431
  tileflowNauticalV1Schema,
20460
22432
  tileflowOverlayPlacements,
20461
22433
  tileflowPoiCategories,
22434
+ tileflowPoiIconOnlyTypes,
20462
22435
  tileflowPoiImageRoles,
20463
22436
  tileflowPortableIdMaximumLength,
20464
22437
  tileflowPortableIdSchema,
@@ -20470,6 +22443,7 @@ export {
20470
22443
  tileflowRenderStackRenderers,
20471
22444
  tileflowRenderedIconIdentitySchema,
20472
22445
  tileflowRenderedIconManifestEntrySchema,
22446
+ tileflowRingsOverlap,
20473
22447
  tileflowRoadClasses,
20474
22448
  tileflowRouteMetadataKey,
20475
22449
  tileflowRouteTokens,
@@ -20488,10 +22462,12 @@ export {
20488
22462
  tileflowThemeLimits,
20489
22463
  tileflowThemeNameSchema,
20490
22464
  tileflowThemeTokenCategories,
22465
+ tileflowTimesOfDay,
20491
22466
  tileflowTreeForms,
20492
22467
  tileflowTreeModelIdPattern,
20493
22468
  tileflowTreeModelLimits,
20494
22469
  tileflowTreeParts,
22470
+ tileflowVegetationDisplayMetadataKey,
20495
22471
  tileflowVegetationMetadataKey,
20496
22472
  tileflowWorld,
20497
22473
  tileflowWorldGeneration,