@tileflow/core 0.1.0-alpha.39 → 0.1.0-alpha.40

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/browser.js CHANGED
@@ -325,6 +325,9 @@ function assertSameStructure(styles, base) {
325
325
  throw new TileflowThemeBlendError("Blended themes must use the same sources.");
326
326
  if (!same(style.sprite, base.sprite) || !same(style.glyphs, base.glyphs))
327
327
  throw new TileflowThemeBlendError("Blended themes must use the same sprite and glyphs.");
328
+ for (const key of ["projection", "terrain"])
329
+ if (!same(style[key], base[key]))
330
+ throw new TileflowThemeBlendError(`Blended themes must use the same ${key}.`);
328
331
  for (const [index, layer] of style.layers.entries()) {
329
332
  const other = base.layers[index];
330
333
  for (const key of ["type", "source", "source-layer", "filter", "minzoom", "maxzoom"])
@@ -3707,6 +3710,74 @@ function getTileflowLocationOrigin() {
3707
3710
  return window.location.origin;
3708
3711
  }
3709
3712
 
3713
+ // src/sky.ts
3714
+ init_theme_blend();
3715
+ var tileflowSkyMetadataKey = "tileflow:sky";
3716
+ var hexColour = /^#[0-9a-f]{6}$/iu;
3717
+ var unit = (value) => typeof value === "number" && Number.isFinite(value) && value >= 0 && value <= 1;
3718
+ function readColours(value) {
3719
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
3720
+ const record3 = value;
3721
+ if (Object.keys(record3).length !== 4) return void 0;
3722
+ const { color, horizonColor, horizonBlend, glowColor } = record3;
3723
+ if (typeof color !== "string" || !hexColour.test(color) || typeof horizonColor !== "string" || !hexColour.test(horizonColor) || typeof glowColor !== "string" || !hexColour.test(glowColor) || !unit(horizonBlend))
3724
+ return void 0;
3725
+ return { color, horizonColor, horizonBlend, glowColor };
3726
+ }
3727
+ function readTileflowSky(value) {
3728
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
3729
+ const record3 = value;
3730
+ const keys = Object.keys(record3);
3731
+ if (record3.version !== 1 || keys.length !== (record3.timesOfDay === void 0 ? 3 : 4))
3732
+ return void 0;
3733
+ const { starIntensity, glowColor, timesOfDay } = record3;
3734
+ if (!unit(starIntensity) || typeof glowColor !== "string" || !hexColour.test(glowColor))
3735
+ return void 0;
3736
+ if (timesOfDay === void 0) return { version: 1, starIntensity, glowColor };
3737
+ if (!timesOfDay || typeof timesOfDay !== "object" || Array.isArray(timesOfDay)) return void 0;
3738
+ const times = timesOfDay;
3739
+ if (Object.keys(times).length !== 4) return void 0;
3740
+ const day = readColours(times.day);
3741
+ const dawn = readColours(times.dawn);
3742
+ const dusk = readColours(times.dusk);
3743
+ const night = readColours(times.night);
3744
+ if (!day || !dawn || !dusk || !night) return void 0;
3745
+ return { version: 1, starIntensity, glowColor, timesOfDay: { day, dawn, dusk, night } };
3746
+ }
3747
+ function tileflowSkyStarVisibility(channels) {
3748
+ const linear = channels.map(
3749
+ (channel) => channel <= 0.04045 ? channel / 12.92 : ((channel + 0.055) / 1.055) ** 2.4
3750
+ );
3751
+ const luminance2 = 0.2126 * linear[0] + 0.7152 * linear[1] + 0.0722 * linear[2];
3752
+ const progress = Math.min(1, Math.max(0, (0.06 - luminance2) / (0.06 - 0.015)));
3753
+ return progress * progress * (3 - 2 * progress);
3754
+ }
3755
+ var smooth = (from, to, value) => {
3756
+ const t = Math.min(1, Math.max(0, (value - from) / (to - from)));
3757
+ return t * t * (3 - 2 * t);
3758
+ };
3759
+ function tileflowSkyGlowStrength(altitude) {
3760
+ return smooth(-9, -1, altitude) * (1 - smooth(6, 24, altitude));
3761
+ }
3762
+ function mixColours(from, to, t) {
3763
+ if (t <= 0) return from;
3764
+ if (t >= 1) return to;
3765
+ return {
3766
+ color: mixTileflowColours(from.color, to.color, t) ?? to.color,
3767
+ horizonColor: mixTileflowColours(from.horizonColor, to.horizonColor, t) ?? to.horizonColor,
3768
+ horizonBlend: from.horizonBlend + (to.horizonBlend - from.horizonBlend) * t,
3769
+ glowColor: mixTileflowColours(from.glowColor, to.glowColor, t) ?? to.glowColor
3770
+ };
3771
+ }
3772
+ function tileflowSkyAtSun(times, sun) {
3773
+ const azimuth = (sun.azimuth % 360 + 360) % 360;
3774
+ const twilight = azimuth < 180 ? times.dawn : times.dusk;
3775
+ if (sun.altitude >= 2) return mixColours(twilight, times.day, smooth(2, 14, sun.altitude));
3776
+ if (sun.altitude >= -2) return twilight;
3777
+ return mixColours(times.night, twilight, smooth(-10, -2, sun.altitude));
3778
+ }
3779
+ var tileflowSkySunKey = /* @__PURE__ */ Symbol.for("tileflow.skySun");
3780
+
3710
3781
  // src/browser.ts
3711
3782
  init_sun();
3712
3783
  init_theme_blend();
@@ -3823,7 +3894,7 @@ function emphasizeTileflowValue(target, value, options) {
3823
3894
  if (amount <= 0) return value;
3824
3895
  if (target.kind === "fade") return scaleOpacity(value, 1 - amount);
3825
3896
  if (options.ground === void 0) return value;
3826
- return mixColours(value, options.ground, amount);
3897
+ return mixColours2(value, options.ground, amount);
3827
3898
  }
3828
3899
  function tileflowEmphasisGround(layers) {
3829
3900
  for (const layer of layers) {
@@ -3845,11 +3916,11 @@ function firstColour(value) {
3845
3916
  }
3846
3917
  return void 0;
3847
3918
  }
3848
- function mixColours(value, toward, amount) {
3919
+ function mixColours2(value, toward, amount) {
3849
3920
  if (typeof value === "string") return mixTileflowColours(value, toward, amount) ?? value;
3850
3921
  if (Array.isArray(value)) {
3851
3922
  if (value[0] === "literal") return value;
3852
- return value.map((item, index) => index === 0 ? item : mixColours(item, toward, amount));
3923
+ return value.map((item, index) => index === 0 ? item : mixColours2(item, toward, amount));
3853
3924
  }
3854
3925
  return value;
3855
3926
  }
@@ -3939,30 +4010,14 @@ function beginTileflowStyleCrossfade(input, duration) {
3939
4010
  snapshot.setAttribute("aria-hidden", "true");
3940
4011
  snapshot.dataset.tileflowThemeCrossfade = "";
3941
4012
  canvas.after(snapshot);
3942
- const corners = [
3943
- [width * 0.1, height * 0.45],
3944
- [width * 0.9, height * 0.45],
3945
- [width * 0.9, height * 0.9],
3946
- [width * 0.1, height * 0.9]
3947
- ];
3948
- const anchors = corners.map((corner) => map.unproject(corner));
3949
- const follow = () => {
3950
- const to = anchors.map((anchor) => map.project(anchor));
3951
- if (to.some((point) => !Number.isFinite(point.x) || !Number.isFinite(point.y))) return;
3952
- const matrix = homography(
3953
- corners,
3954
- to.map((point) => [point.x, point.y])
3955
- );
3956
- if (matrix) snapshot.style.transform = matrix3d(matrix);
3957
- };
3958
- map.on("move", follow);
3959
4013
  let removed = false;
3960
4014
  const remove = () => {
3961
4015
  if (removed) return;
3962
4016
  removed = true;
3963
- map.off("move", follow);
4017
+ map.off("move", remove);
3964
4018
  snapshot.remove();
3965
4019
  };
4020
+ map.on("move", remove);
3966
4021
  const frame = (callback) => {
3967
4022
  if (typeof view.requestAnimationFrame === "function") view.requestAnimationFrame(callback);
3968
4023
  else view.setTimeout(callback, 16);
@@ -4225,7 +4280,7 @@ function relayoutPositions(plan) {
4225
4280
  return positions;
4226
4281
  }
4227
4282
  function isCrossfadeMap(map) {
4228
- return typeof map.getCanvas === "function" && typeof map.redraw === "function" && typeof map.project === "function" && typeof map.unproject === "function" && typeof map.isStyleLoaded === "function" && typeof map.areTilesLoaded === "function";
4283
+ return typeof map.getCanvas === "function" && typeof map.redraw === "function" && typeof map.isStyleLoaded === "function" && typeof map.areTilesLoaded === "function";
4229
4284
  }
4230
4285
  function viewOf(map) {
4231
4286
  if (typeof map.getCanvas !== "function") return void 0;
@@ -4245,124 +4300,114 @@ function prefersReducedMotion(view) {
4245
4300
  function tileflowThemeMotionView(map) {
4246
4301
  return viewOf(map);
4247
4302
  }
4248
- function homography(from, to) {
4249
- const rows = [];
4250
- for (let index = 0; index < 4; index += 1) {
4251
- const [x3, y2] = from[index];
4252
- const [u, v2] = to[index];
4253
- rows.push([x3, y2, 1, 0, 0, 0, -u * x3, -u * y2, u]);
4254
- rows.push([0, 0, 0, x3, y2, 1, -v2 * x3, -v2 * y2, v2]);
4255
- }
4256
- for (let column = 0; column < 8; column += 1) {
4257
- let pivot = column;
4258
- for (let row = column + 1; row < 8; row += 1)
4259
- if (Math.abs(rows[row][column]) > Math.abs(rows[pivot][column])) pivot = row;
4260
- if (Math.abs(rows[pivot][column]) < 1e-12) return void 0;
4261
- [rows[column], rows[pivot]] = [rows[pivot], rows[column]];
4262
- for (let row = 0; row < 8; row += 1) {
4263
- if (row === column) continue;
4264
- const factor = rows[row][column] / rows[column][column];
4265
- for (let k = column; k <= 8; k += 1) rows[row][k] -= factor * rows[column][k];
4266
- }
4267
- }
4268
- return [...rows.map((row, index) => row[8] / row[index]), 1];
4269
- }
4270
- function matrix3d(matrix) {
4271
- const [a, b2, c, d2, e, f, g, h2, i2] = matrix.map(
4272
- (value) => Math.abs(value) < 1e-12 ? 0 : Number(value.toPrecision(10))
4273
- );
4274
- return `matrix3d(${a},${d2},0,${g},${b2},${e},0,${h2},0,0,1,0,${c},${f},0,${i2})`;
4275
- }
4276
4303
 
4277
- // src/sky.ts
4278
- init_theme_blend();
4279
- var tileflowSkyMetadataKey = "tileflow:sky";
4280
- var hexColour = /^#[0-9a-f]{6}$/iu;
4281
- var unit = (value) => typeof value === "number" && Number.isFinite(value) && value >= 0 && value <= 1;
4282
- function readColours(value) {
4283
- if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
4284
- const record2 = value;
4285
- if (Object.keys(record2).length !== 4) return void 0;
4286
- const { color, horizonColor, horizonBlend, glowColor } = record2;
4287
- if (typeof color !== "string" || !hexColour.test(color) || typeof horizonColor !== "string" || !hexColour.test(horizonColor) || typeof glowColor !== "string" || !hexColour.test(glowColor) || !unit(horizonBlend))
4288
- return void 0;
4289
- return { color, horizonColor, horizonBlend, glowColor };
4290
- }
4291
- function readTileflowSky(value) {
4292
- if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
4293
- const record2 = value;
4294
- const keys = Object.keys(record2);
4295
- if (record2.version !== 1 || keys.length !== (record2.timesOfDay === void 0 ? 3 : 4))
4296
- return void 0;
4297
- const { starIntensity, glowColor, timesOfDay } = record2;
4298
- if (!unit(starIntensity) || typeof glowColor !== "string" || !hexColour.test(glowColor))
4299
- return void 0;
4300
- if (timesOfDay === void 0) return { version: 1, starIntensity, glowColor };
4301
- if (!timesOfDay || typeof timesOfDay !== "object" || Array.isArray(timesOfDay)) return void 0;
4302
- const times = timesOfDay;
4303
- if (Object.keys(times).length !== 4) return void 0;
4304
- const day = readColours(times.day);
4305
- const dawn = readColours(times.dawn);
4306
- const dusk = readColours(times.dusk);
4307
- const night = readColours(times.night);
4308
- if (!day || !dawn || !dusk || !night) return void 0;
4309
- return { version: 1, starIntensity, glowColor, timesOfDay: { day, dawn, dusk, night } };
4310
- }
4311
- function tileflowSkyStarVisibility(channels) {
4312
- const linear = channels.map(
4313
- (channel) => channel <= 0.04045 ? channel / 12.92 : ((channel + 0.055) / 1.055) ** 2.4
4314
- );
4315
- const luminance2 = 0.2126 * linear[0] + 0.7152 * linear[1] + 0.0722 * linear[2];
4316
- const progress = Math.min(1, Math.max(0, (0.06 - luminance2) / (0.06 - 0.015)));
4317
- return progress * progress * (3 - 2 * progress);
4318
- }
4319
- var smooth = (from, to, value) => {
4320
- const t = Math.min(1, Math.max(0, (value - from) / (to - from)));
4321
- return t * t * (3 - 2 * t);
4304
+ // src/theme-preparation-browser.ts
4305
+ var opacities = {
4306
+ background: ["background-opacity"],
4307
+ circle: ["circle-opacity", "circle-stroke-opacity"],
4308
+ fill: ["fill-opacity"],
4309
+ "fill-extrusion": ["fill-extrusion-opacity"],
4310
+ heatmap: ["heatmap-opacity"],
4311
+ line: ["line-opacity"],
4312
+ raster: ["raster-opacity"],
4313
+ symbol: ["text-opacity", "icon-opacity"]
4322
4314
  };
4323
- function tileflowSkyGlowStrength(altitude) {
4324
- return smooth(-9, -1, altitude) * (1 - smooth(6, 24, altitude));
4325
- }
4326
- function mixColours2(from, to, t) {
4327
- if (t <= 0) return from;
4328
- if (t >= 1) return to;
4315
+ function prepareTileflowThemeGeometry(from, to) {
4316
+ const existing = new Set(from.layers.map((layer) => layer.id));
4317
+ const added = to.layers.filter((layer) => !existing.has(layer.id));
4318
+ if (!added.length || added.some((layer) => !opacities[String(layer.type)])) return void 0;
4319
+ const style = {
4320
+ ...from,
4321
+ layers: [
4322
+ ...from.layers,
4323
+ ...added.map((layer) => ({
4324
+ ...layer,
4325
+ paint: {
4326
+ ...layer.paint,
4327
+ ...Object.fromEntries(
4328
+ opacities[String(layer.type)].flatMap((property) => [
4329
+ [property, 0],
4330
+ [`${property}-transition`, { duration: 0, delay: 0 }]
4331
+ ])
4332
+ )
4333
+ }
4334
+ }))
4335
+ ]
4336
+ };
4329
4337
  return {
4330
- color: mixTileflowColours(from.color, to.color, t) ?? to.color,
4331
- horizonColor: mixTileflowColours(from.horizonColor, to.horizonColor, t) ?? to.horizonColor,
4332
- horizonBlend: from.horizonBlend + (to.horizonBlend - from.horizonBlend) * t,
4333
- glowColor: mixTileflowColours(from.glowColor, to.glowColor, t) ?? to.glowColor
4338
+ style,
4339
+ reveal(map) {
4340
+ const set = map.setPaintProperty;
4341
+ for (const layer of added)
4342
+ for (const property of opacities[String(layer.type)])
4343
+ set.call(
4344
+ map,
4345
+ String(layer.id),
4346
+ property,
4347
+ layer.paint?.[property] ?? 1
4348
+ );
4349
+ }
4334
4350
  };
4335
4351
  }
4336
- function tileflowSkyAtSun(times, sun) {
4337
- const azimuth = (sun.azimuth % 360 + 360) % 360;
4338
- const twilight = azimuth < 180 ? times.dawn : times.dusk;
4339
- if (sun.altitude >= 2) return mixColours2(twilight, times.day, smooth(2, 14, sun.altitude));
4340
- if (sun.altitude >= -2) return twilight;
4341
- return mixColours2(times.night, twilight, smooth(-10, -2, sun.altitude));
4352
+ function waitForTileflowThemeGeometry(map, timeoutMs, stop) {
4353
+ const view = tileflowThemeMotionView(map);
4354
+ if (!view || typeof map.isStyleLoaded !== "function" || typeof map.areTilesLoaded !== "function")
4355
+ return Promise.resolve(!stop());
4356
+ const loaded = map.isStyleLoaded;
4357
+ const tiles = map.areTilesLoaded;
4358
+ return new Promise((resolve, reject) => {
4359
+ const now = () => view.performance?.now?.() ?? Date.now();
4360
+ const started = now();
4361
+ let readyFrames = 0;
4362
+ const step = () => {
4363
+ if (stop()) return resolve(false);
4364
+ readyFrames = loaded.call(map) && tiles.call(map) ? readyFrames + 1 : 0;
4365
+ if (readyFrames >= 2) return resolve(true);
4366
+ if (now() - started >= timeoutMs)
4367
+ return reject(new Error("Tileflow theme geometry did not finish loading."));
4368
+ if (view.requestAnimationFrame) view.requestAnimationFrame(step);
4369
+ else view.setTimeout(step, 16);
4370
+ };
4371
+ if (view.requestAnimationFrame) view.requestAnimationFrame(step);
4372
+ else view.setTimeout(step, 16);
4373
+ });
4342
4374
  }
4343
- var tileflowSkySunKey = /* @__PURE__ */ Symbol.for("tileflow.skySun");
4344
4375
 
4345
4376
  // src/atmosphere.ts
4346
4377
  var tileflowAtmosphereMetadataKey = "tileflow:atmosphere";
4378
+ var tileflowAtmosphereMetadataVersion = 2;
4379
+ var defaultAtmosphereStars = {
4380
+ starColor: "#e0ebff",
4381
+ starCount: 1100,
4382
+ starSize: 1
4383
+ };
4347
4384
  function readTileflowAtmosphere(value) {
4348
4385
  if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
4349
- const record2 = value;
4350
- if (record2.version !== 1 || Object.keys(record2).length !== 7) return void 0;
4386
+ const record3 = value;
4387
+ const legacy = record3.version === 1;
4388
+ if (!legacy && record3.version !== tileflowAtmosphereMetadataVersion || Object.keys(record3).length !== (legacy ? 7 : 10))
4389
+ return void 0;
4351
4390
  for (const key of ["skyColor", "horizonColor", "fogColor", "spaceColor"]) {
4352
- if (typeof record2[key] !== "string" || !/^#[0-9a-f]{6}$/i.test(record2[key])) return void 0;
4391
+ if (typeof record3[key] !== "string" || !/^#[0-9a-f]{6}$/i.test(record3[key])) return void 0;
4353
4392
  }
4354
4393
  for (const key of ["starIntensity", "starParallax"]) {
4355
- const number = record2[key];
4394
+ const number = record3[key];
4356
4395
  if (typeof number !== "number" || !Number.isFinite(number) || number < 0 || number > 1)
4357
4396
  return void 0;
4358
4397
  }
4398
+ const stars = legacy ? defaultAtmosphereStars : record3;
4399
+ if (typeof stars.starColor !== "string" || !/^#[0-9a-f]{6}$/i.test(stars.starColor) || typeof stars.starCount !== "number" || !Number.isInteger(stars.starCount) || stars.starCount < 0 || stars.starCount > 4096 || typeof stars.starSize !== "number" || !Number.isFinite(stars.starSize) || stars.starSize < 0 || stars.starSize > 4)
4400
+ return void 0;
4359
4401
  return {
4360
- skyColor: record2.skyColor,
4361
- horizonColor: record2.horizonColor,
4362
- fogColor: record2.fogColor,
4363
- spaceColor: record2.spaceColor,
4364
- starIntensity: record2.starIntensity,
4365
- starParallax: record2.starParallax
4402
+ skyColor: record3.skyColor,
4403
+ horizonColor: record3.horizonColor,
4404
+ fogColor: record3.fogColor,
4405
+ spaceColor: record3.spaceColor,
4406
+ starColor: stars.starColor,
4407
+ starCount: stars.starCount,
4408
+ starSize: stars.starSize,
4409
+ starIntensity: record3.starIntensity,
4410
+ starParallax: record3.starParallax
4366
4411
  };
4367
4412
  }
4368
4413
  function atmosphereSpaceOpacity(zoom) {
@@ -4389,6 +4434,162 @@ function createAtmosphereStars(count = 650) {
4389
4434
  }));
4390
4435
  }
4391
4436
 
4437
+ // src/atmosphere-rim-browser.ts
4438
+ var tileflowAtmosphereRimLayerId = "tileflow-atmosphere-rim";
4439
+ function atmosphereRimEllipse(matrix, width, height) {
4440
+ const x3 = [0, 4, 8, 12].map((i2) => (matrix[i2] + matrix[i2 + 3]) * width / 2);
4441
+ const y2 = [1, 5, 9, 13].map((i2) => (matrix[i2 + 2] - matrix[i2]) * height / 2);
4442
+ const w2 = [3, 7, 11, 15].map((i2) => matrix[i2]);
4443
+ const dot3 = (a2, b3) => a2[0] * b3[0] + a2[1] * b3[1] + a2[2] * b3[2] - a2[3] * b3[3];
4444
+ const xx = dot3(x3, x3), xy = dot3(x3, y2), xw = dot3(x3, w2);
4445
+ const yy = dot3(y2, y2), yw = dot3(y2, w2), ww = dot3(w2, w2);
4446
+ const a = yy * ww - yw * yw, b2 = xw * yw - xy * ww, c = xx * ww - xw * xw;
4447
+ const d2 = xy * yw - xw * yy, e = xy * xw - xx * yw, f = xx * yy - xy * xy;
4448
+ const determinant = a * c - b2 * b2;
4449
+ if (!Number.isFinite(determinant) || determinant <= 0) return void 0;
4450
+ const centerX = (b2 * e - c * d2) / determinant;
4451
+ const centerY = (b2 * d2 - a * e) / determinant;
4452
+ const level = -(f + d2 * centerX + e * centerY);
4453
+ const middle = (a + c) / 2;
4454
+ const spread = Math.hypot((a - c) / 2, b2);
4455
+ const radiusX = Math.sqrt(level / (middle + spread));
4456
+ const radiusY = Math.sqrt(level / (middle - spread));
4457
+ if (![centerX, centerY, radiusX, radiusY].every(Number.isFinite) || Math.min(radiusX, radiusY) <= 0)
4458
+ return void 0;
4459
+ return { centerX, centerY, radiusX, radiusY, rotation: Math.atan2(2 * b2, a - c) / 2 };
4460
+ }
4461
+ function attachTileflowAtmosphereRim(map) {
4462
+ const container = map.getContainer();
4463
+ const document2 = container.ownerDocument;
4464
+ const browser = document2.defaultView;
4465
+ if (!browser) return () => {
4466
+ };
4467
+ let disposed = false;
4468
+ let canvas;
4469
+ let context = null;
4470
+ let lastDraw = "";
4471
+ let atmosphere;
4472
+ function removeCanvas() {
4473
+ canvas?.remove();
4474
+ canvas = void 0;
4475
+ context = null;
4476
+ lastDraw = "";
4477
+ }
4478
+ const layer = {
4479
+ id: tileflowAtmosphereRimLayerId,
4480
+ type: "custom",
4481
+ // Keep projection reads out of terrain's offscreen ground textures.
4482
+ renderingMode: "3d",
4483
+ render(_gl, input) {
4484
+ if (!atmosphere || !canvas || !context) return;
4485
+ const { mainMatrix, projectionTransition } = input.defaultProjectionData;
4486
+ const width = container.clientWidth, height = container.clientHeight;
4487
+ if (!width || !height) return;
4488
+ const pixelRatio2 = Math.min(browser.devicePixelRatio || 1, 2);
4489
+ const transition = Math.max(0, Math.min(1, (projectionTransition - 0.98) / 0.02));
4490
+ const opacity = atmosphereSpaceOpacity(map.getZoom()) * transition * transition * (3 - 2 * transition);
4491
+ const key = JSON.stringify([
4492
+ Array.from(mainMatrix),
4493
+ width,
4494
+ height,
4495
+ pixelRatio2,
4496
+ opacity,
4497
+ atmosphere.horizonColor
4498
+ ]);
4499
+ if (key === lastDraw) return;
4500
+ lastDraw = key;
4501
+ canvas.style.opacity = String(opacity);
4502
+ if (!opacity) return;
4503
+ const ellipse = atmosphereRimEllipse(mainMatrix, width, height);
4504
+ if (!ellipse) return;
4505
+ const physicalWidth = Math.round(width * pixelRatio2), physicalHeight = Math.round(height * pixelRatio2);
4506
+ if (canvas.width !== physicalWidth || canvas.height !== physicalHeight) {
4507
+ canvas.width = physicalWidth;
4508
+ canvas.height = physicalHeight;
4509
+ }
4510
+ context.setTransform(pixelRatio2, 0, 0, pixelRatio2, 0, 0);
4511
+ context.clearRect(0, 0, width, height);
4512
+ context.save();
4513
+ context.translate(ellipse.centerX, ellipse.centerY);
4514
+ context.rotate(ellipse.rotation);
4515
+ context.scale(ellipse.radiusX, ellipse.radiusY);
4516
+ const radius = Math.min(ellipse.radiusX, ellipse.radiusY);
4517
+ const extent5 = 1 + 120 / radius;
4518
+ const gradient = context.createRadialGradient(0, 0, 0, 0, 0, extent5);
4519
+ gradient.addColorStop(0, "transparent");
4520
+ gradient.addColorStop(Math.max(0, 1 - 0.5 / radius) / extent5, "transparent");
4521
+ const colour = Number.parseInt(atmosphere.horizonColor.slice(1), 16);
4522
+ const outer = [(colour >> 16) * 0.35, (colour >> 8 & 255) * 0.6, colour & 255];
4523
+ const white = [245, 250, 255];
4524
+ for (const distance of [0, 1, 2, 3, 5, 8, 12, 18, 26, 36, 50, 70, 96, 120]) {
4525
+ const tint = Math.exp(-distance / 7);
4526
+ const channels = outer.map(
4527
+ (channel, index) => Math.round(channel + (white[index] - channel) * tint)
4528
+ );
4529
+ const alpha = distance === 120 ? 0 : Math.min(1, 0.85 * Math.exp(-distance / 3) + 0.55 * Math.exp(-distance / 24));
4530
+ gradient.addColorStop(
4531
+ (1 + distance / radius) / extent5,
4532
+ `rgba(${channels.join(", ")}, ${alpha})`
4533
+ );
4534
+ }
4535
+ context.fillStyle = gradient;
4536
+ context.fillRect(-extent5, -extent5, extent5 * 2, extent5 * 2);
4537
+ context.restore();
4538
+ }
4539
+ };
4540
+ function sync(styleLoaded2 = false) {
4541
+ if (disposed) return;
4542
+ const style = map.getStyle();
4543
+ if (!style) return;
4544
+ atmosphere = style.projection?.type === "globe" ? readTileflowAtmosphere(
4545
+ style.metadata?.[tileflowAtmosphereMetadataKey]
4546
+ ) : void 0;
4547
+ try {
4548
+ const present = Boolean(map.getLayer(layer.id));
4549
+ if (!atmosphere) {
4550
+ if (present) map.removeLayer(layer.id);
4551
+ removeCanvas();
4552
+ return;
4553
+ }
4554
+ if (!canvas) {
4555
+ canvas = document2.createElement("canvas");
4556
+ canvas.setAttribute("aria-hidden", "true");
4557
+ canvas.setAttribute("data-tileflow-atmosphere-rim", "");
4558
+ Object.assign(canvas.style, {
4559
+ position: "absolute",
4560
+ inset: "0",
4561
+ width: "100%",
4562
+ height: "100%",
4563
+ pointerEvents: "none"
4564
+ });
4565
+ context = canvas.getContext("2d");
4566
+ container.insertBefore(canvas, container.firstChild);
4567
+ }
4568
+ if (present || !styleLoaded2 && !map.isStyleLoaded()) return;
4569
+ map.addLayer(layer);
4570
+ } catch {
4571
+ }
4572
+ }
4573
+ const styleLoaded = () => sync(true);
4574
+ const styleData = () => sync();
4575
+ map.on("style.load", styleLoaded);
4576
+ map.on("styledata", styleData);
4577
+ map.on("idle", styleData);
4578
+ sync();
4579
+ return () => {
4580
+ if (disposed) return;
4581
+ disposed = true;
4582
+ map.off("style.load", styleLoaded);
4583
+ map.off("styledata", styleData);
4584
+ map.off("idle", styleData);
4585
+ removeCanvas();
4586
+ try {
4587
+ if (map.getLayer(layer.id)) map.removeLayer(layer.id);
4588
+ } catch {
4589
+ }
4590
+ };
4591
+ }
4592
+
4392
4593
  // src/sky-browser.ts
4393
4594
  init_sun();
4394
4595
  init_theme_blend();
@@ -5289,10 +5490,10 @@ function attachTileflowSkyHaze(map) {
5289
5490
  }
5290
5491
  function sync() {
5291
5492
  if (disposed) return;
5292
- const sky = map.getSky?.();
5293
- const wanted = typeof sky?.["horizon-color"] === "string";
5294
- const present = Boolean(map.getLayer(tileflowSkyHazeLayerId));
5295
5493
  try {
5494
+ const sky = map.getSky?.();
5495
+ const wanted = typeof sky?.["horizon-color"] === "string";
5496
+ const present = Boolean(map.getLayer(tileflowSkyHazeLayerId));
5296
5497
  if (!wanted) {
5297
5498
  if (present) map.removeLayer(tileflowSkyHazeLayerId);
5298
5499
  return;
@@ -5377,7 +5578,10 @@ function createProgram(gl) {
5377
5578
  }
5378
5579
 
5379
5580
  // src/atmosphere-browser.ts
5380
- function attachTileflowAtmosphere(map) {
5581
+ function attachTileflowAtmosphere(map, runtimeOptions = {}) {
5582
+ const starParallaxScale = runtimeOptions.starParallaxScale ?? 1;
5583
+ if (!Number.isFinite(starParallaxScale))
5584
+ throw new RangeError("starParallaxScale must be a finite number.");
5381
5585
  const container = map.getContainer();
5382
5586
  const document2 = container.ownerDocument;
5383
5587
  const browser = document2.defaultView;
@@ -5388,16 +5592,15 @@ function attachTileflowAtmosphere(map) {
5388
5592
  };
5389
5593
  const detachHaze = layered ? attachTileflowSkyHaze(map) : () => {
5390
5594
  };
5391
- const mapCanvas = map.getCanvas();
5392
- const previousFilter = mapCanvas.style.filter;
5595
+ const detachRim = layered ? attachTileflowAtmosphereRim(map) : () => {
5596
+ };
5393
5597
  const reducedMotion = browser.matchMedia("(prefers-reduced-motion: reduce)");
5394
- const stars = createAtmosphereStars();
5598
+ let stars = [];
5395
5599
  let options;
5396
5600
  let canvas;
5397
5601
  let context = null;
5398
5602
  let frame;
5399
5603
  let disposed = false;
5400
- let appliedFilter;
5401
5604
  let width = 0;
5402
5605
  let height = 0;
5403
5606
  let pixelRatio2 = 0;
@@ -5405,17 +5608,11 @@ function attachTileflowAtmosphere(map) {
5405
5608
  let previousBearing = map.getBearing();
5406
5609
  let longitude = previousLongitude;
5407
5610
  let bearing = previousBearing;
5408
- function restoreFilter() {
5409
- if (appliedFilter !== void 0 && mapCanvas.style.filter === appliedFilter)
5410
- mapCanvas.style.filter = previousFilter;
5411
- appliedFilter = void 0;
5412
- }
5413
5611
  function removeCanvas() {
5414
5612
  canvas?.remove();
5415
5613
  canvas = void 0;
5416
5614
  context = null;
5417
5615
  width = height = pixelRatio2 = 0;
5418
- restoreFilter();
5419
5616
  }
5420
5617
  function syncStyle() {
5421
5618
  if (disposed) return;
@@ -5430,6 +5627,7 @@ function attachTileflowAtmosphere(map) {
5430
5627
  removeCanvas();
5431
5628
  return;
5432
5629
  }
5630
+ if (stars.length !== options.starCount) stars = createAtmosphereStars(options.starCount);
5433
5631
  if (!canvas) {
5434
5632
  canvas = document2.createElement("canvas");
5435
5633
  canvas.setAttribute("aria-hidden", "true");
@@ -5458,13 +5656,7 @@ function attachTileflowAtmosphere(map) {
5458
5656
  previousBearing = map.getBearing();
5459
5657
  const opacity = atmosphereSpaceOpacity(map.getZoom());
5460
5658
  canvas.style.opacity = String(opacity);
5461
- if (opacity === 0) {
5462
- restoreFilter();
5463
- return;
5464
- }
5465
- const baseFilter = previousFilter && previousFilter !== "none" ? `${previousFilter} ` : "";
5466
- mapCanvas.style.filter = `${baseFilter}drop-shadow(0 0 2px ${withAlpha(options.horizonColor, opacity * 0.65)}) drop-shadow(0 0 12px ${withAlpha(options.horizonColor, opacity * 0.4)})`;
5467
- appliedFilter = mapCanvas.style.filter;
5659
+ if (opacity === 0) return;
5468
5660
  if (!context) return;
5469
5661
  const nextWidth = container.clientWidth;
5470
5662
  const nextHeight = container.clientHeight;
@@ -5479,30 +5671,34 @@ function attachTileflowAtmosphere(map) {
5479
5671
  context.setTransform(pixelRatio2, 0, 0, pixelRatio2, 0, 0);
5480
5672
  }
5481
5673
  context.clearRect(0, 0, width, height);
5482
- if (options.starIntensity === 0) return;
5483
- const motion = reducedMotion.matches ? 0 : options.starParallax / 0.4;
5674
+ if (options.starIntensity === 0 || options.starSize === 0) return;
5675
+ const motion = reducedMotion.matches ? 0 : options.starParallax / 0.4 * starParallaxScale;
5484
5676
  const xOffset = motion * (-longitude * 0.8 - bearing * 0.35);
5485
5677
  const yOffset = motion * (center.lat * 0.6 + map.getPitch() * 0.4);
5486
5678
  const intensity = options.starIntensity / 0.6;
5487
5679
  const fieldWidth = 1600;
5488
5680
  const fieldHeight = 1e3;
5489
5681
  for (const star of stars) {
5682
+ const radius = (star.radius + 0.25) * options.starSize;
5683
+ const margin = star.radius > 0.95 ? radius * 2.5 : radius;
5684
+ const alpha = Math.min(1, star.alpha * 1.35 * intensity);
5490
5685
  const x3 = wrapAtmosphereStar(star.x * fieldWidth + xOffset, fieldWidth);
5491
5686
  const y2 = wrapAtmosphereStar(star.y * fieldHeight + yOffset, fieldHeight);
5492
5687
  for (let tileX = -1; tileX * fieldWidth < width; tileX++) {
5493
5688
  for (let tileY = -1; tileY * fieldHeight < height; tileY++) {
5494
5689
  const screenX = x3 + tileX * fieldWidth;
5495
5690
  const screenY = y2 + tileY * fieldHeight;
5496
- if (screenX < -3 || screenX > width + 3 || screenY < -3 || screenY > height + 3) continue;
5691
+ if (screenX < -margin || screenX > width + margin || screenY < -margin || screenY > height + margin)
5692
+ continue;
5497
5693
  if (star.radius > 0.95) {
5498
- context.fillStyle = withAlpha(options.horizonColor, star.alpha * intensity * 0.12);
5694
+ context.fillStyle = withAlpha(options.horizonColor, alpha * 0.1);
5499
5695
  context.beginPath();
5500
- context.arc(screenX, screenY, star.radius * 2.5, 0, Math.PI * 2);
5696
+ context.arc(screenX, screenY, radius * 2.5, 0, Math.PI * 2);
5501
5697
  context.fill();
5502
5698
  }
5503
- context.fillStyle = `rgba(208, 227, 255, ${Math.min(1, star.alpha * intensity)})`;
5699
+ context.fillStyle = withAlpha(options.starColor, alpha);
5504
5700
  context.beginPath();
5505
- context.arc(screenX, screenY, star.radius, 0, Math.PI * 2);
5701
+ context.arc(screenX, screenY, radius, 0, Math.PI * 2);
5506
5702
  context.fill();
5507
5703
  }
5508
5704
  }
@@ -5516,6 +5712,7 @@ function attachTileflowAtmosphere(map) {
5516
5712
  disposed = true;
5517
5713
  detachSky();
5518
5714
  detachHaze();
5715
+ detachRim();
5519
5716
  if (frame !== void 0) browser.cancelAnimationFrame(frame);
5520
5717
  map.off("move", schedule);
5521
5718
  map.off("resize", schedule);
@@ -5698,6 +5895,95 @@ function promotedKey(map, source) {
5698
5895
  return value === "ref" ? "ref" : void 0;
5699
5896
  }
5700
5897
 
5898
+ // src/cartography/label-placement.ts
5899
+ var roadLabelPlacementKey = "tileflow:road-label-placement";
5900
+ var groundRoadLabelMetadata = { [roadLabelPlacementKey]: { version: 1, mode: "ground" } };
5901
+ function isGroundRoadLabel(layer) {
5902
+ const policy = layer.metadata?.[roadLabelPlacementKey];
5903
+ return policy?.version === 1 && policy.mode === "ground";
5904
+ }
5905
+
5906
+ // src/label-placement-browser.ts
5907
+ function attachTileflowLabelPlacement(map) {
5908
+ let disposed = false;
5909
+ let targets = [];
5910
+ let ordering = false;
5911
+ let flatOrder = map.getPitch() < 30;
5912
+ function orderRoads(restore = false) {
5913
+ if (ordering || !map.moveLayer || !targets.length) return;
5914
+ const style = map.getStyle();
5915
+ const layers = (map.getLayersOrder?.() ?? style?.layers?.map((layer) => layer.id) ?? []).map(
5916
+ (id) => {
5917
+ const layer = map.getLayer(id);
5918
+ return {
5919
+ id,
5920
+ type: layer?.type,
5921
+ renderingMode: layer?.implementation?.renderingMode ?? layer?.renderingMode,
5922
+ vegetation: (layer?.implementation?.metadata ?? layer?.metadata)?.["tileflow:scene-kind"] === "vegetation"
5923
+ };
5924
+ }
5925
+ );
5926
+ const roads = new Set(targets);
5927
+ const anchors = style?.metadata?.["tileflow:overlay-placement-manifest"];
5928
+ const ceiling = layers.findIndex((layer) => layer.id === anchors?.anchors?.["above-buildings"]);
5929
+ const scene = layers.filter(
5930
+ (layer, index) => (ceiling < 0 || index < ceiling) && (layer.type === "fill-extrusion" || layer.type === "custom" && layer.renderingMode === "3d")
5931
+ );
5932
+ if (!scene.length) return;
5933
+ const solidScene = scene.filter((layer) => !layer.vegetation);
5934
+ const flat = !restore && map.getPitch() < 30;
5935
+ const boundary = flat || !restore && !solidScene.length ? layers.slice(layers.indexOf(scene.at(-1)) + 1).find((layer) => !roads.has(layer.id))?.id : (restore ? scene[0] : solidScene[0]).id;
5936
+ const order = layers.map((layer) => layer.id);
5937
+ const names = order.filter((id) => roads.has(id));
5938
+ const above = flat || !restore && !solidScene.length ? scene.at(-1) : !restore ? scene.filter(
5939
+ (layer) => layer.vegetation && layers.indexOf(layer) < layers.indexOf(solidScene[0])
5940
+ ).at(-1) : void 0;
5941
+ const below = flat || !restore && !solidScene.length ? void 0 : boundary;
5942
+ if (names.every(
5943
+ (id) => (!above || order.indexOf(id) > order.indexOf(above.id)) && (!below || order.indexOf(id) < order.indexOf(below))
5944
+ ))
5945
+ return;
5946
+ ordering = true;
5947
+ try {
5948
+ for (const id of names) map.moveLayer(id, boundary);
5949
+ } finally {
5950
+ ordering = false;
5951
+ }
5952
+ }
5953
+ function syncStyle() {
5954
+ if (disposed || ordering) return;
5955
+ targets = (map.getStyle()?.layers ?? []).filter(isGroundRoadLabel).map(({ id }) => id);
5956
+ flatOrder = map.getPitch() < 30;
5957
+ orderRoads();
5958
+ }
5959
+ function pitch() {
5960
+ if (disposed) return;
5961
+ const flat = map.getPitch() < 30;
5962
+ if (flat === flatOrder) return;
5963
+ flatOrder = flat;
5964
+ orderRoads();
5965
+ }
5966
+ function release(restore) {
5967
+ if (disposed) return;
5968
+ disposed = true;
5969
+ map.off("pitch", pitch);
5970
+ map.off("moveend", pitch);
5971
+ map.off("style.load", syncStyle);
5972
+ map.off("styledata", syncStyle);
5973
+ map.off("remove", removed);
5974
+ if (restore) orderRoads(true);
5975
+ targets = [];
5976
+ }
5977
+ const removed = () => release(false);
5978
+ map.on("pitch", pitch);
5979
+ map.on("moveend", pitch);
5980
+ map.on("style.load", syncStyle);
5981
+ map.on("styledata", syncStyle);
5982
+ map.on("remove", removed);
5983
+ syncStyle();
5984
+ return () => release(true);
5985
+ }
5986
+
5701
5987
  // src/line-progress.ts
5702
5988
  var epsilon = 5e-4;
5703
5989
  var transparent = "rgba(0, 0, 0, 0)";
@@ -6120,6 +6406,50 @@ function record(value) {
6120
6406
  return typeof value === "object" && value !== null && !Array.isArray(value);
6121
6407
  }
6122
6408
 
6409
+ // src/buildings-3d-surfaces.ts
6410
+ function readTileflowBuildingSurfaces(value) {
6411
+ if (!record2(value)) return void 0;
6412
+ const number = (value2, min, max2, fallback) => typeof value2 === "number" && Number.isFinite(value2) && value2 >= min && value2 <= max2 ? value2 : fallback;
6413
+ const result = {};
6414
+ if (record2(value.walls) && value.walls.kind === "brick") {
6415
+ const size = Array.isArray(value.walls.size) ? value.walls.size : [];
6416
+ const width = number(size[0], 0.5, 100, 6);
6417
+ const height = number(size[1], 0.5, 100, 3);
6418
+ result.walls = {
6419
+ kind: "brick",
6420
+ size: [width, height],
6421
+ jointWidth: Math.min(
6422
+ number(value.walls.jointWidth, 0.01, 2, 0.12),
6423
+ Math.min(width, height) * 0.25
6424
+ ),
6425
+ contrast: number(value.walls.contrast, 0, 1, 0.2)
6426
+ };
6427
+ }
6428
+ if (record2(value.roof) && value.roof.kind === "tiles") {
6429
+ const size = number(value.roof.size, 0.5, 100, 8);
6430
+ result.roof = {
6431
+ kind: "tiles",
6432
+ size,
6433
+ jointWidth: Math.min(number(value.roof.jointWidth, 0.01, 2, 0.12), size * 0.25),
6434
+ contrast: number(value.roof.contrast, 0, 1, 0.1)
6435
+ };
6436
+ }
6437
+ if (record2(value.cornice))
6438
+ result.cornice = {
6439
+ height: number(value.cornice.height, 0.05, 5, 0.6),
6440
+ contrast: number(value.cornice.contrast, 0, 1, 0.2)
6441
+ };
6442
+ return Object.keys(result).length ? result : void 0;
6443
+ }
6444
+ function tileflowBuildingSurfaceTile(x3, y2, zoom, size) {
6445
+ const span = 4007501668557849e-8 / 2 ** zoom;
6446
+ const phase = (value) => (value % size + size) % size;
6447
+ return [phase(x3 * span), phase(y2 * span), span / 8192];
6448
+ }
6449
+ function record2(value) {
6450
+ return value !== null && typeof value === "object" && !Array.isArray(value);
6451
+ }
6452
+
6123
6453
  // src/buildings-3d-design.ts
6124
6454
  var tileflowBuildingsMetadataKey = "tileflow:buildings";
6125
6455
  var tileflowDefaultBuildings3DDesign = Object.freeze({
@@ -6147,6 +6477,7 @@ function readTileflowBuildings3D(metadata) {
6147
6477
  if (typeof color !== "string" && !Array.isArray(color)) return void 0;
6148
6478
  const within = (number, high, fallback) => typeof number === "number" && number >= 0 && number <= high ? number : fallback;
6149
6479
  const defaults = tileflowDefaultBuildings3DDesign;
6480
+ const surfaces = readTileflowBuildingSurfaces(value.surfaces);
6150
6481
  const floodLight = readBuildingFloodLight(value.floodLight);
6151
6482
  const modelLighting = readModelRoleLighting(value.modelLighting);
6152
6483
  return {
@@ -6166,6 +6497,7 @@ function readTileflowBuildings3D(metadata) {
6166
6497
  ...floodLight ? { floodLight } : {},
6167
6498
  ...modelLighting ? { modelLighting } : {},
6168
6499
  windows: value.windows === true,
6500
+ ...surfaces ? { surfaces } : {},
6169
6501
  ...readTileflowBuildingsEntrance(value.entrance),
6170
6502
  shadows: typeof value.shadows === "boolean" ? value.shadows : defaults.shadows,
6171
6503
  occlusion: typeof value.occlusion === "boolean" ? value.occlusion : defaults.occlusion,
@@ -8097,7 +8429,9 @@ uniform vec2 u_palette_rows; // rows per theme; texels per row
8097
8429
  uniform vec2 u_palette_themes; // the themes either side of the blend position
8098
8430
  uniform float u_palette_mix;
8099
8431
  uniform float u_variation; // how far buildings' brightness strays from their colour, either way
8432
+ uniform vec3 u_surface_tile; // repeating projected-metre phase and metres per tile unit
8100
8433
  ${growth}
8434
+ out vec2 v_surface;
8101
8435
  out vec3 v_colour;
8102
8436
  out float v_base;
8103
8437
  out vec3 v_facade; // metres along the wall, metres up as built, the building's top
@@ -8142,6 +8476,7 @@ void main() {
8142
8476
  // Neighbours of one colour stay apart: each building a little lighter or darker than its colour.
8143
8477
  v_colour *= 1.0 + (a_wave.x - 0.5) * 2.0 * u_variation;
8144
8478
  v_base = base;
8479
+ v_surface = a_pos * u_surface_tile.z + u_surface_tile.xy;
8145
8480
  v_edge = wall > 0.5 ? vec3(a_edge.x, 0.0, 0.0) : vec3(equal(vec3(a_edge.x), vec3(0.0, 1.0, 2.0)));
8146
8481
  v_outline = a_edge.y;
8147
8482
  v_facade = vec3(a_along * 0.1, own, top);
@@ -8152,6 +8487,10 @@ var tileflowBuildingFragment = `#version 300 es
8152
8487
  precision highp float;
8153
8488
  in vec3 v_colour;
8154
8489
  in float v_base;
8490
+ in vec2 v_surface;
8491
+ uniform vec4 u_surface_walls; // width, course height, joint width, contrast
8492
+ uniform vec3 u_surface_roof; // square size, joint width, contrast
8493
+ uniform vec2 u_surface_cornice; // band height, contrast
8155
8494
  uniform vec3 u_style_light_position;
8156
8495
  uniform vec3 u_style_light_colour;
8157
8496
  uniform float u_style_light_intensity;
@@ -8256,6 +8595,62 @@ float edgeOf() {
8256
8595
  return 1.0 - smoothstep(u_edge_width - 0.75, u_edge_width + 0.25, near);
8257
8596
  }
8258
8597
 
8598
+ // A filtered joint between large, softly shaded blocks. Derivatives are taken before the
8599
+ // stagger/periodic wrap, so row boundaries do not create false level-of-detail transitions.
8600
+ float surfaceBlocks(vec2 position, vec2 size, float joint, float contrast, float stagger) {
8601
+ vec2 footprint = max(fwidth(position), vec2(0.0001));
8602
+ float visible = smoothstep(2.0, 7.0, min(size.x / footprint.x, size.y / footprint.y));
8603
+ vec2 uv = position / size;
8604
+ uv.x += mod(floor(uv.y), 2.0) * stagger;
8605
+ vec2 cell = fract(uv) * size;
8606
+ vec2 distance = min(cell, size - cell);
8607
+ vec2 aa = footprint * 0.65;
8608
+ vec2 seam = 1.0 - smoothstep(vec2(joint * 0.5) - aa, vec2(joint * 0.5) + aa, distance);
8609
+ float groove = max(seam.x, seam.y);
8610
+ // A quiet bevel on the upper and left edges makes the painted blocks catch light.
8611
+ vec2 bevel = (1.0 - smoothstep(vec2(joint), vec2(joint + 0.35) + aa, cell)) * (1.0 - seam);
8612
+ return 1.0 + contrast * visible * (max(bevel.x, bevel.y) * 0.3 - groove * 0.65);
8613
+ }
8614
+
8615
+ // Distance to the actual roof outline in the roof's projected-metre plane. The triangle's
8616
+ // barycentric gradient ignores internal triangulation and tile cuts, including around patios.
8617
+ float roofOutlineDistance() {
8618
+ vec2 dx = dFdx(v_surface), dy = dFdy(v_surface);
8619
+ float determinant = dx.x * dy.y - dx.y * dy.x;
8620
+ if (abs(determinant) < 1e-10) return 1e6;
8621
+ vec3 bx = dFdx(v_edge), by = dFdy(v_edge);
8622
+ vec3 gx = (bx * dy.y - by * dx.y) / determinant;
8623
+ vec3 gy = (by * dx.x - bx * dy.x) / determinant;
8624
+ vec3 distance = v_edge / max(sqrt(gx * gx + gy * gy), vec3(1e-7));
8625
+ int sides = int(v_outline + 0.5);
8626
+ float nearest = 1e6;
8627
+ if ((sides & 1) != 0) nearest = min(nearest, distance.x);
8628
+ if ((sides & 2) != 0) nearest = min(nearest, distance.y);
8629
+ if ((sides & 4) != 0) nearest = min(nearest, distance.z);
8630
+ return nearest;
8631
+ }
8632
+
8633
+ vec3 surfaceColour() {
8634
+ vec3 colour = v_colour;
8635
+ bool wall = v_building.z > 0.5;
8636
+ float pattern = 1.0;
8637
+ if (wall && u_surface_walls.w > 0.0)
8638
+ pattern = surfaceBlocks(v_facade.xy, u_surface_walls.xy, u_surface_walls.z, u_surface_walls.w, 0.5);
8639
+ if (!wall && u_surface_roof.z > 0.0)
8640
+ pattern = surfaceBlocks(v_surface, vec2(u_surface_roof.x), u_surface_roof.y, u_surface_roof.z, 0.0);
8641
+ float band = 0.0, seam = 0.0;
8642
+ if (u_surface_cornice.y > 0.0) {
8643
+ float distance = wall ? v_facade.z - v_facade.y : roofOutlineDistance();
8644
+ float width = wall ? min(u_surface_cornice.x, (v_facade.z - v_base) * 0.2) : u_surface_cornice.x;
8645
+ float pixel = max(fwidth(distance), 0.001);
8646
+ float visible = smoothstep(0.4, 1.5, width / pixel);
8647
+ band = (1.0 - smoothstep(width - pixel * 0.5, width + pixel * 0.5, distance)) * visible;
8648
+ seam = (1.0 - smoothstep(0.0, pixel + width * 0.15, abs(distance - width))) * visible;
8649
+ }
8650
+ colour *= mix(pattern, 1.0, band) * (1.0 - seam * u_surface_cornice.y * 0.25);
8651
+ return mix(colour, mix(colour, vec3(1.0), u_surface_cornice.y * 0.45), band);
8652
+ }
8653
+
8259
8654
  void main() {
8260
8655
  vec3 normal = normalize(v_normal);
8261
8656
  // A narrow lighting transition softens the roof/wall junction without moving the roof
@@ -8266,8 +8661,9 @@ void main() {
8266
8661
  normal = normalize(mix(normal, vec3(0.0, 0.0, 1.0), rim));
8267
8662
  }
8268
8663
  float lit = dot(normal, u_sun_dir) > 0.0 ? visibility(v_shadow, 0.3) : 0.0;
8269
- vec3 colour = mix(styleColour(v_colour, normal) * (1.0 - u_shadow * (1.0 - lit)),
8270
- v_colour * shade(normal, lit), u_sun_lighting);
8664
+ vec3 surface = surfaceColour();
8665
+ vec3 colour = mix(styleColour(surface, normal) * (1.0 - u_shadow * (1.0 - lit)),
8666
+ surface * shade(normal, lit), u_sun_lighting);
8271
8667
  colour *= facadeShade();
8272
8668
  // Roof outlines and outer corners catch the light, so where one building ends and the next starts
8273
8669
  // stays legible, at night most of all.
@@ -9360,6 +9756,8 @@ function readTileflowVegetation3D(metadata) {
9360
9756
  colors: { bark: colors.bark, broadleaf, conifer, palm, hedge },
9361
9757
  heightScale: scale(heightScale),
9362
9758
  crownScale: scale(crownScale),
9759
+ minimumHeight: typeof value.minimumHeight === "number" && Number.isFinite(value.minimumHeight) ? clamp(value.minimumHeight, [0, 20]) : 0,
9760
+ materialVariation: typeof value.materialVariation === "number" && Number.isFinite(value.materialVariation) ? clamp(value.materialVariation, [0, 1]) : 0,
9363
9761
  forms,
9364
9762
  models,
9365
9763
  finish: finish2,
@@ -9649,7 +10047,7 @@ function browserWorker() {
9649
10047
  if (typeof Worker === "undefined" || false)
9650
10048
  return;
9651
10049
  const url = URL.createObjectURL(
9652
- new Blob(['"use strict";(()=>{var Be=new Set,ln=!1;function Pe(e,n,t=2){let i=n&&n.length,o=i?n[0]*t:e.length;Be.size&&Be.clear();let r=zn(e,0,o,t,!0),s=[];if(!r||r.next===r.prev)return s;let a=0,l=0,u=0;if(i&&(r=xt(e,n,r,t)),e.length>80*t){a=e[0],l=e[1];let c=a,f=l;for(let d=t;d<o;d+=t){let g=e[d],m=e[d+1];g<a&&(a=g),m<l&&(l=m),g>c&&(c=g),m>f&&(f=m)}u=Math.max(c-a,f-l),u=u!==0?32767/u:0}return un(r,s,a,l,u),s}function zn(e,n,t,i,o){let r=null;if(o===Ut(e,n,t,i)>0)for(let s=n;s<t;s+=i)r=In(s/i|0,e[s],e[s+1],r);else for(let s=t-i;s>=n;s-=i)r=In(s/i|0,e[s],e[s+1],r);return r&&Oe(r,r.next)&&(Ce(r),r=r.next),r}function ge(e,n=e){let t=n===e,i=e,o;do o=!1,i!==i.next&&(Be.size===0||!Be.has(i))&&(Oe(i,i.next)||Q(i.prev,i,i.next)===0)?((t||i===n)&&(n=i.prev),ln=!0,Ce(i),i=i.prev,o=!0):(t||i!==n)&&(i=i.next,o=!t);while(o||i!==n);return n}function un(e,n,t,i,o){o&&At(e,t,i,o);let r=e,s=!1;for(;e.prev!==e.next;){let a=e.prev,l=e.next;if(Q(a,e,l)<0&&(o?bt(e,t,i,o):yt(e))){n.push(a.i,e.i,l.i),Ce(e),e=l,r=l;continue}if(e=l,e===r){if(ln=!1,e=ge(e),ln){r=e;continue}if(!s){e=gt(e,n),r=e,s=!0;continue}wt(e,n,t,i,o);break}}}function yt(e){let n=e.prev,t=e,i=e.next,o=n.x,r=t.x,s=i.x,a=n.y,l=t.y,u=i.y,c=Math.min(o,r,s),f=Math.min(a,l,u),d=Math.max(o,r,s),g=Math.max(a,l,u),m=i.next;for(;m!==n;){if(m.x>=c&&m.x<=d&&m.y>=f&&m.y<=g&&!(o===m.x&&a===m.y)&&Ke(o,a,r,l,s,u,m.x,m.y)&&Q(m.prev,m,m.next)>=0)return!1;m=m.next}return!0}function bt(e,n,t,i){let o=e.prev,r=e,s=e.next,a=o.x,l=r.x,u=s.x,c=o.y,f=r.y,d=s.y,g=Math.min(a,l,u),m=Math.min(c,f,d),p=Math.max(a,l,u),h=Math.max(c,f,d),_=mn(g,m,n,t,i),A=mn(p,h,n,t,i),k=e.prevZ;for(;k&&k.z>=_;){if(k.x>=g&&k.x<=p&&k.y>=m&&k.y<=h&&k!==s&&!(a===k.x&&c===k.y)&&Ke(a,c,l,f,u,d,k.x,k.y)&&Q(k.prev,k,k.next)>=0)return!1;k=k.prevZ}let M=e.nextZ;for(;M&&M.z<=A;){if(M.x>=g&&M.x<=p&&M.y>=m&&M.y<=h&&M!==s&&!(a===M.x&&c===M.y)&&Ke(a,c,l,f,u,d,M.x,M.y)&&Q(M.prev,M,M.next)>=0)return!1;M=M.nextZ}return!0}function gt(e,n){let t=e,i=!1;do{let o=t.prev,r=t.next.next;Nn(o,t,t.next,r,!1)&&Ue(o,r)&&Ue(r,o)&&(n.push(o.i,t.i,r.i),Ce(t),Ce(t.next),t=e=r,i=!0),t=t.next}while(t!==e);return i?ge(t):t}function wt(e,n,t,i,o){let r=e;do{let s=r.next.next;for(;s!==r.prev;){if(r.i!==s.i&&Lt(r,s)){let a=Vn(r,s);r=ge(r,r.next),a=ge(a,a.next),un(r,n,t,i,o),un(a,n,t,i,o);return}s=s.next}r=r.next}while(r!==e)}var cn=!1;function xt(e,n,t,i){let o=[];for(let r=0,s=n.length;r<s;r++){let a=n[r]*i,l=r<s-1?n[r+1]*i:e.length,u=zn(e,a,l,i,!1);u===u.next&&Be.add(u),o.push(St(u))}o.sort(Tt),kt(e.length/i,n.length),Dn(t,t),cn=!0;for(let r=0;r<o.length;r++)t=Mt(o[r],t);return cn=!1,ge(t)}function Tt(e,n){return e.x-n.x||e.y-n.y||(e.next.y-e.y)/(e.next.x-e.x)-(n.next.y-n.y)/(n.next.x-n.x)}function Mt(e,n){let t=Rt(e,n);if(!t)return n;let i=Vn(t,e),o=i.next;return Dn(t,o.next),ge(i,i.next),ge(t,t.next)}var jn=16,X=new Float64Array(0),Je=0,fn=[],dn=[];function kt(e,n){let t=Math.ceil((e+2*n)/jn)+n+2;X.length<t*4&&(X=new Float64Array(t*4)),Je=0}function Dn(e,n){let t=e;do{let i=Je++;fn[i]=t;let o=t.x,r=t.y,s=t.x,a=t.y,l=0;do{let c=t.next;t.z=i,c.x<o&&(o=c.x),c.x>s&&(s=c.x),c.y<r&&(r=c.y),c.y>a&&(a=c.y),t=c}while(++l<jn&&t!==n);dn[i]=t;let u=i*4;X[u]=o,X[u+1]=r,X[u+2]=s,X[u+3]=a}while(t!==n)}function vt(e,n){let t=e.z*4;n.x<X[t]&&(X[t]=n.x),n.y<X[t+1]&&(X[t+1]=n.y),n.x>X[t+2]&&(X[t+2]=n.x),n.y>X[t+3]&&(X[t+3]=n.y)}function Pn(e){let n=dn[e];for(;n.prev.next!==n;)n=n.next;return dn[e]=n,n}function En(e){let n=fn[e];for(;n.prev.next!==n;)n=n.next;return fn[e]=n,n}function Rt(e,n){let t=n,i=e.x,o=e.y,r=-1/0,s;if(Oe(e,t))return t;for(let d=0,g=0;d<Je;d++,g+=4){if(o<X[g+1]||o>X[g+3]||X[g]>i||X[g+2]<=r)continue;let m=Pn(d);t=En(d);do{if(t.prev.next===t){if(Oe(e,t.next))return t.next;if(o<=t.y&&o>=t.next.y&&t.next.y!==t.y){let p=t.x+(o-t.y)*(t.next.x-t.x)/(t.next.y-t.y);if(p<=i&&p>r&&(r=p,s=t.x<t.next.x?t:t.next,p===i))return s}}t=t.next}while(t!==m)}if(!s)return null;let a=s.x,l=s.y,u=Math.min(o,l),c=Math.max(o,l),f=1/0;for(let d=0,g=0;d<Je;d++,g+=4){if(X[g+2]<a||X[g]>i||X[g+3]<u||X[g+1]>c)continue;let m=Pn(d);t=En(d);do{if(t.prev.next===t&&i>=t.x&&t.x>=a&&i!==t.x&&Ke(o<l?i:r,o,a,l,o<l?r:i,o,t.x,t.y)){let p=Math.abs(o-t.y)/(i-t.x);(Ue(t,e)||t.y===o&&t.next.y===o&&t.next.x>i)&&(p<f||p===f&&(t.x>s.x||t.x===s.x&&_t(s,t)))&&(s=t,f=p)}t=t.next}while(t!==m)}return s}function _t(e,n){return Q(e.prev,e,n.prev)<0&&Q(n.next,e,e.next)<0}var ie=[],ve=[],be=new Uint32Array(0),Se=new Uint32Array(0),Le=new Uint32Array(256);function At(e,n,t,i){let o=e,r=0;do o.z=mn(o.x,o.y,n,t,i),ie[r++]=o,o=o.next;while(o!==e);Ft(r);let s=null;for(let a=0;a<r;a++){let l=ie[a];l.prevZ=s,s&&(s.nextZ=l),s=l}s.nextZ=null,ie.fill(null,0,r),ve.fill(null,0,r)}function Ft(e){if(e<=32){for(let n=1;n<e;n++){let t=ie[n],i=t.z,o=n-1;for(;o>=0&&ie[o].z>i;)ie[o+1]=ie[o],o--;ie[o+1]=t}return}be.length<e&&(be=new Uint32Array(e),Se=new Uint32Array(e),ve=new Array(e));for(let n=0;n<e;n++)be[n]=ie[n].z;Xe(e,ie,be,ve,Se,0),Xe(e,ve,Se,ie,be,8),Xe(e,ie,be,ve,Se,16),Xe(e,ve,Se,ie,be,24)}function Xe(e,n,t,i,o,r){Le.fill(0);for(let a=0;a<e;a++)Le[t[a]>>>r&255]++;let s=0;for(let a=0;a<256;a++){let l=Le[a];Le[a]=s,s+=l}for(let a=0;a<e;a++){let l=t[a],u=Le[l>>>r&255]++;i[u]=n[a],o[u]=l}}function mn(e,n,t,i,o){return e=(e-t)*o|0,n=(n-i)*o|0,e=(e|e<<8)&16711935,e=(e|e<<4)&252645135,e=(e|e<<2)&858993459,e=(e|e<<1)&1431655765,n=(n|n<<8)&16711935,n=(n|n<<4)&252645135,n=(n|n<<2)&858993459,n=(n|n<<1)&1431655765,e|n<<1}function St(e){let n=e,t=e;do(n.x<t.x||n.x===t.x&&n.y<t.y)&&(t=n),n=n.next;while(n!==e);return t}function Ke(e,n,t,i,o,r,s,a){return(o-s)*(n-a)>=(e-s)*(r-a)&&(e-s)*(i-a)>=(t-s)*(n-a)&&(t-s)*(r-a)>=(o-s)*(i-a)}function Lt(e,n){let t=Oe(e,n)&&Q(e.prev,e,e.next)>0&&Q(n.prev,n,n.next)>0;return e.next.i!==n.i&&(t||Ue(e,n)&&Ue(n,e)&&(Q(e.prev,e,n.prev)!==0||Q(e,n.prev,n)!==0))&&!Bt(e,n)&&(t||Ot(e,n))}function Q(e,n,t){return(n.y-e.y)*(t.x-n.x)-(n.x-e.x)*(t.y-n.y)}function Oe(e,n){return e.x===n.x&&e.y===n.y}function Nn(e,n,t,i,o=!0){let r=Q(e,n,t),s=Q(e,n,i),a=Q(t,i,e),l=Q(t,i,n);return(r>0&&s<0||r<0&&s>0)&&(a>0&&l<0||a<0&&l>0)?!0:o?!!(r===0&&Ye(e,t,n)||s===0&&Ye(e,i,n)||a===0&&Ye(t,e,i)||l===0&&Ye(t,n,i)):!1}function Ye(e,n,t){return n.x<=Math.max(e.x,t.x)&&n.x>=Math.min(e.x,t.x)&&n.y<=Math.max(e.y,t.y)&&n.y>=Math.min(e.y,t.y)}function Bt(e,n){let t=Math.min(e.x,n.x),i=Math.max(e.x,n.x),o=Math.min(e.y,n.y),r=Math.max(e.y,n.y),s=e;do{let a=s.next;if(s.x>i&&a.x>i||s.x<t&&a.x<t||s.y>r&&a.y>r||s.y<o&&a.y<o){s=a;continue}if(s.i!==e.i&&a.i!==e.i&&s.i!==n.i&&a.i!==n.i&&Nn(s,a,e,n))return!0;s=a}while(s!==e);return!1}function Ue(e,n){return Q(e.prev,e,e.next)<0?Q(e,n,e.next)>=0&&Q(e,e.prev,n)>=0:Q(e,n,e.prev)<0||Q(e,e.next,n)<0}function Ot(e,n){let t=e,i=!1,o=(e.x+n.x)/2,r=(e.y+n.y)/2;do{let s=t.next;t.y>r!=s.y>r&&o<(s.x-t.x)*(r-t.y)/(s.y-t.y)+t.x&&(i=!i),t=s}while(t!==e);return i}function Vn(e,n){let t=hn(e.i,e.x,e.y),i=hn(n.i,n.x,n.y),o=e.next,r=n.prev;return e.next=n,n.prev=e,t.next=o,o.prev=t,i.next=t,t.prev=i,r.next=i,i.prev=r,i}function In(e,n,t,i){let o=hn(e,n,t);return i?(o.next=i.next,o.prev=i,i.next.prev=o,i.next=o):(o.prev=o,o.next=o),o}function Ce(e){e.next.prev=e.prev,e.prev.next=e.next,e.prevZ&&(e.prevZ.nextZ=e.nextZ),e.nextZ&&(e.nextZ.prevZ=e.prevZ),cn&&vt(e.prev,e.next)}function hn(e,n,t){return{i:e,x:n,y:t,prev:null,next:null,z:0,prevZ:null,nextZ:null}}function Ut(e,n,t,i){let o=0;for(let r=n,s=t-i;r<t;r+=i)o+=(e[s]-e[r])*(e[r+1]+e[s+1]),s=r;return o}var Ct=.7,Pt=Math.tan(Math.PI/6),Et=Math.tan(35*Math.PI/180),It=Math.tan(Math.PI/18),Ee=.65,Ie=.4;function Zn(e,n,t,i,o,r,s){let a=String(t.roof_shape??"");if(!a||a==="flat"||a==="sawtooth"||Vt(e,s))return;let l=Dt(e);if(!l||Math.abs(pn(e))<Ct*4*l.halfU*l.halfV)return;let u=l.u,c=l.v,f=l.halfU*r,d=l.halfV*r;f<d&&([u,c,f,d]=[c,u,d,f]);let g=Gn(t.roof_direction),m=g===void 0?void 0:[Math.sin(g*Math.PI/180),-Math.cos(g*Math.PI/180)];(m!==void 0?Math.abs(m[0]*u[0]+m[1]*u[1])>Math.abs(m[0]*c[0]+m[1]*c[1]):t.roof_orientation==="across")&&a!=="skillion"&&([u,c,f,d]=[c,u,d,f]);let h=jt(a,f,d,m&&[$n(m,u),$n(m,c)]);if(!h)return;let _=Math.max(0,o-i),A=Gn(t.roof_height),k,M;if(A!==void 0&&A>0)M=o,k=Math.max(i+Math.min(2,_/2),o-A);else{let y=Math.min(zt(a,d),_*.6,30);t.height_source==="height"?(M=o,k=o-y):(k=o,M=o+y)}let B=M-k;if(!(B>=.3))return;let[U,E]=l.centre,C=(y,b)=>{let x=(y-U)*r,T=(b-E)*r;return[x*u[0]+T*u[1],x*c[0]+T*c[1]]},I=(y,b)=>[U+(y*u[0]+b*c[0])/r,E+(y*u[1]+b*c[1])/r],N=(y,b)=>{let x=1/0;for(let[T,F,v]of h)x=Math.min(x,T*y+F*b+v);return Math.max(0,x)},K=(y,b)=>k+B*N(...C(y,b)),$=[];for(let y=0;y+1<n.length;y+=2)$.push(...C(n[y],n[y+1]));pn($)<0&&Ht($);let D=1.01,Y=[-f*D,-d*D,f*D,-d*D,f*D,d*D,-f*D,d*D],w=[];for(let[y,b]of h.entries()){let x=Y;for(let[P,Z]of h.entries()){if(P===y)continue;let j=b[0]-Z[0],G=b[1]-Z[1],W=b[2]-Z[2];if(Math.abs(j)+Math.abs(G)+Math.abs(W)<1e-9){P<y&&(x=[]);continue}if(x=Hn(x,j,G,W),x.length<6)break}if(x.length<6)continue;let T=$,F=x.length/2;for(let P=0;P<F&&T.length>=6;P+=1){let[Z,j]=[x[P*2],x[P*2+1]],[G,W]=[x[(P+1)%F*2],x[(P+1)%F*2+1]];T=Hn(T,W-j,Z-G,-(W-j)*Z-(Z-G)*j)}if(T.length<6||Math.abs(pn(T))<1e-6)continue;let v=[];for(let P=0;P<T.length;P+=2)v.push(...I(T[P],T[P+1]));let L=Pe(v);if(L.length===0)continue;let O=B*b[0],V=B*b[1],R=O*u[0]+V*c[0],S=O*u[1]+V*c[1],z=Math.hypot(R,S,1);w.push({ring:v,triangles:L,normal:[-R/z,-S/z]})}if(w.length!==0)return{eaves:k,ridge:M,faces:w,heightAt:K,breaks(y,b,x,T){let[F,v]=C(y,b),[L,O]=C(x,T),V=[];for(let R=0;R<h.length;R+=1)for(let S=R+1;S<h.length;S+=1){let z=(ae,H)=>(h[R][0]-h[S][0])*ae+(h[R][1]-h[S][1])*H+(h[R][2]-h[S][2]),P=z(F,v),Z=z(L,O);if(P===Z||P*Z>0)continue;let j=P/(P-Z);if(j<=1e-4||j>=1-1e-4)continue;let G=F+(L-F)*j,W=v+(O-v)*j;h[R][0]*G+h[R][1]*W+h[R][2]<=N(G,W)+1e-6&&V.push(j)}return[...new Set(V.map(R=>Math.round(R*1e6)/1e6))].sort((R,S)=>R-S)}}}function zt(e,n){switch(e){case"skillion":return 2*n*It;case"pyramidal":return n*Et;case"gambrel":case"mansard":return n*.8;case"dome":case"onion":case"round":return n;default:return n*Pt}}function jt(e,n,t,i){let o=n,r=t,s=[[0,-1/r,1],[0,1/r,1]],a=u=>u.flatMap(c=>[1,-1].flatMap(f=>{let d=c==="v"?r:o,g=Ee/(Ie*r)*f,m=(1-Ee)/((1-Ie)*r)*f,p=h=>c==="v"?[0,-h]:[-h,0];return[[...p(g),Ee/(Ie*r)*d],[...p(m),Ee+(1-Ee)/((1-Ie)*r)*(d-Ie*r)]]})),l=[.99,.8,.5,.2];switch(e){case"gabled":return s;case"saltbox":{let u=r/3;return[[0,-1/(r-u),1+u/(r-u)],[0,1/(r+u),1-u/(r+u)]]}case"hipped":return[...s,[-1/r,0,o/r],[1/r,0,o/r]];case"half_hipped":return[...s,[-1/r,0,.5+o/r],[1/r,0,.5+o/r]];case"pyramidal":return[...s,[-1/o,0,1],[1/o,0,1]];case"gambrel":return a(["v"]);case"mansard":return a(["v","u"]);case"skillion":{let[u,c]=i??[0,1],f=Math.abs(u)*o+Math.abs(c)*r;return f>0?[[-u/(2*f),-c/(2*f),.5]]:void 0}case"round":return[[0,0,1],...l.flatMap(u=>{let c=Math.sqrt(1-u*u);return[1,-1].map(f=>[0,-f*u/(r*c),1/c])})];case"dome":case"onion":return[[0,0,1],...l.flatMap(u=>{let c=Math.sqrt(1-u*u);return Array.from({length:12},(f,d)=>{let g=d*Math.PI/6;return[-u*Math.cos(g)/(o*c),-u*Math.sin(g)/(r*c),1/c]})})];default:return}}function Hn(e,n,t,i){let o=e.length/2,r=[];for(let s=0;s<o;s+=1){let a=e[s*2],l=e[s*2+1],u=e[(s+1)%o*2],c=e[(s+1)%o*2+1],f=n*a+t*l+i,d=n*u+t*c+i;if(f<=0&&r.push(a,l),f<0&&d>0||f>0&&d<0){let g=f/(f-d);r.push(a+(u-a)*g,l+(c-l)*g)}}return r}function Dt(e){let n=Nt(e);if(n.length<3)return;let t,i=1/0;for(let o=0;o<n.length;o+=1){let[r,s]=n[o],[a,l]=n[(o+1)%n.length],u=Math.hypot(a-r,l-s);if(u===0)continue;let c=[(a-r)/u,(l-s)/u],f=[-c[1],c[0]],[d,g,m,p]=[1/0,-1/0,1/0,-1/0];for(let[_,A]of n){let k=_*c[0]+A*c[1],M=_*f[0]+A*f[1];d=Math.min(d,k),g=Math.max(g,k),m=Math.min(m,M),p=Math.max(p,M)}let h=(g-d)*(p-m);if(h<i){i=h;let _=(d+g)/2,A=(m+p)/2;t={centre:[_*c[0]+A*f[0],_*c[1]+A*f[1]],u:c,v:f,halfU:(g-d)/2,halfV:(p-m)/2}}}return t&&t.halfU>0&&t.halfV>0?t:void 0}function Nt(e){let n=[];for(let r=0;r+1<e.length;r+=2)n.push([e[r],e[r+1]]);n.sort((r,s)=>r[0]-s[0]||r[1]-s[1]);let t=(r,s,a)=>(s[0]-r[0])*(a[1]-r[1])-(s[1]-r[1])*(a[0]-r[0]),i=[];for(let r of n){for(;i.length>=2&&t(i.at(-2),i.at(-1),r)<=0;)i.pop();i.push(r)}let o=[];for(let r of n.reverse()){for(;o.length>=2&&t(o.at(-2),o.at(-1),r)<=0;)o.pop();o.push(r)}return[...i.slice(0,-1),...o.slice(0,-1)]}function Vt(e,n){let[t,i,o,r]=[1/0,-1/0,1/0,-1/0];for(let a=0;a+1<e.length;a+=2)t=Math.min(t,e[a]),i=Math.max(i,e[a]),o=Math.min(o,e[a+1]),r=Math.max(r,e[a+1]);let s=e.length/2;for(let a=0;a<s;a+=1){let l=e[a*2],u=e[a*2+1],c=e[(a+1)%s*2],f=e[(a+1)%s*2+1];if(t<0&&l===t&&c===t||i>n&&l===i&&c===i||o<0&&u===o&&f===o||r>n&&u===r&&f===r)return!0}return!1}function pn(e){let n=0,t=e.length/2;for(let i=0;i<t;i+=1){let o=(i+1)%t;n+=e[i*2]*e[o*2+1]-e[o*2]*e[i*2+1]}return n/2}function Ht(e){let n=[];for(let t=0;t<e.length;t+=2)n.push([e[t],e[t+1]]);n.reverse(),e.splice(0,e.length,...n.flat())}function $n(e,n){return e[0]*n[0]+e[1]*n[1]}function Gn(e){let n=typeof e=="string"?Number(e):e;return typeof n=="number"&&Number.isFinite(n)?n:void 0}var jr=Object.freeze({surface:0,secondary:1,glass:2,accent:3,roof:4}),Dr=Object.freeze({unclassified:0,wall:1,door:2,roof:3,window:4,lamp:5,logo:6}),Nr=Object.freeze([1,1,4,1,3]),Vr=Object.freeze({levels:3,vertices:2e5,triangles:2e5,footprintPoints:4096,radius:2e3,height:1e3,models:512,bytes:16*1024*1024});function yn(e,n,t){for(let i of e){let o=!1;for(let r=0,s=i.length-2;r<i.length;s=r,r+=2){let a=i[r],l=i[r+1],u=i[s],c=i[s+1];l>t!=c>t&&n<(u-a)*(t-l)/(c-l)+a&&(o=!o)}if(o)return!0}return!1}function Yn(e,n,t){for(let i of n){let[o,r,s,a]=Xn(i);for(let l of e){let[u,c,f,d]=Xn(l);if(!(u>s-t||f<o+t||c>a-t||d<r+t)&&(Wn(l,i,t)||Wn(i,l,t)))return!0}}return!1}function Wn(e,n,t){let i=(o,r)=>yn([n],o,r)&&Gt(n,o,r)>t;for(let o=0;o+1<e.length;o+=2)if(i(e[o],e[o+1]))return!0;for(let o=0,r=e.length-2;o<e.length;r=o,o+=2){let[s,a,l,u]=[e[r],e[r+1],e[o],e[o+1]],c=[0,1];for(let f=0,d=n.length-2;f<n.length;d=f,f+=2){let g=$t(s,a,l,u,n[d],n[d+1],n[f],n[f+1]);g!==void 0&&c.push(g)}if(c.length!==2){c.sort((f,d)=>f-d);for(let f=1;f<c.length;f+=1){let d=(c[f-1]+c[f])/2;if(i(s+(l-s)*d,a+(u-a)*d))return!0}}}return!1}function $t(e,n,t,i,o,r,s,a){let l=t-e,u=i-n,c=s-o,f=a-r,d=l*f-u*c;if(d===0)return;let g=((o-e)*f-(r-n)*c)/d,m=((o-e)*u-(r-n)*l)/d;return g>0&&g<1&&m>=0&&m<=1?g:void 0}function Gt(e,n,t){let i=1/0;for(let o=0,r=e.length-2;o<e.length;r=o,o+=2){let[s,a,l,u]=[e[r],e[r+1],e[o],e[o+1]],c=(l-s)**2+(u-a)**2,f=c>0?Math.max(0,Math.min(1,((n-s)*(l-s)+(t-a)*(u-a))/c)):0;i=Math.min(i,Math.hypot(n-(s+(l-s)*f),t-(a+(u-a)*f)))}return i}function Xn(e){let[n,t,i,o]=[1/0,1/0,-1/0,-1/0];for(let r=0;r+1<e.length;r+=2)n=Math.min(n,e[r]),i=Math.max(i,e[r]),t=Math.min(t,e[r+1]),o=Math.max(o,e[r+1]);return[n,t,i,o]}var ue=8192,pe=28,Zt={commercial:1,active:2,destination:3},Wt={residential:1,...Object.fromEntries(["civic","commercial","education","entertainment","medical","transportation"].map(e=>[e,2])),...Object.fromEntries(["agricultural","industrial","military","outbuilding","religious","service"].map(e=>[e,3]))},Xt={dining:1,entertainment:2,nightlife:3},bn={...Object.fromEntries(["alcoholic_beverage_venue","bar","beer","biergarten","brewery","casino","cocktail_bar","dance_club","karaoke","lounge","music_venue","night_club","nightclub","pub","wine_bar"].map(e=>[e,3])),...Object.fromEntries(["arts_centre","bowling_alley","cinema","comedy_club","concert_hall","movie_theater","opera","performing_arts_venue","theater","theatre","theatre_venue"].map(e=>[e,2])),...Object.fromEntries(["casual_eatery","fast_food","fast_food_restaurant","food_court","restaurant"].map(e=>[e,1]))},Yt=6,Jt=.5,Kt=.5;function Kn(e,n){let t=ue/e.extent,i=n.tileMetres/ue,o=n.defaultHeight??5,r=Number.isFinite(n.edgeRadius)?Math.max(0,Math.min(1,n.edgeRadius))/i:0,s=new wn,a=new Qe,l=new Qe,u=[],c=[],f=0,d=nr(e,n);for(let[M,B]of e.features.entries()){if(B.type!=="Polygon"||u.length>=65535)continue;let U=B.properties,E=U.hide_3d;if(E===!0||E===1||E==="1"||E==="true")continue;let C=Math.min(6e3,Jn(U.render_height)??o),I=Math.min(C,Jn(U.render_min_height)??0),N=Zt[String(U.building_tone??"")]??0,K=Wt[String(U.class??"")]??0,$=d.get(M)??0,D=u.length,Y=!1;for(let w of tr(B.geometry,t)){let y=w.map(or).filter(S=>S.length>=6);if(y.length===0||qe(y[0])===0)continue;let[b,x]=rr(y[0]);if(n.masks?.length&&(yn(n.masks,b,x)||Yn(y,n.masks,Kt/i)))continue;let T={cell:Math.min(7,Math.max(0,Math.floor(x/1024)))*8+Math.min(7,Math.max(0,Math.floor(b/1024))),bounds:[1/0,1/0,-1/0,-1/0,C+.1],roofsFrom:a.length,roofsCount:0,wallsFrom:l.length,wallsCount:0};for(let S of y)for(let z=0;z<S.length;z+=2)T.bounds[0]=Math.min(T.bounds[0],S[z]-1),T.bounds[1]=Math.min(T.bounds[1],S[z+1]-1),T.bounds[2]=Math.max(T.bounds[2],S[z]+1),T.bounds[3]=Math.max(T.bounds[3],S[z+1]+1);Y=!0,f=Math.max(f,C);let F=Number.isSafeInteger(B.id),v=gn(F?B.id*.0731:b*.0731+x*.19137+D*1.618),L=!F&&y[0].some(S=>S<=0||S>=ue)?gn(C*7.31+I*3.17+N):v,O={base:I,top:C,jitter:L,seed:v,tone:N,group:K,use:$,cx:b,cy:x,index:D},V=y.map((S,z)=>er(S,z,r,n.cornerAngle));y=V.map(({ring:S})=>S);let R=w.length===1&&y.length===1?Zn(w[0],y[0],U,I,C,i,ue):void 0;R?(f=Math.max(f,R.ridge),T.bounds[4]=Math.max(T.bounds[4],R.ridge+.1),qt(R,O,s,a)):Qt(y,O,s,a);for(let[S,z]of y.entries()){let P=qe(z)>0,Z=S===0?P?-1:1:P?1:-1,j=z.length/2,G=H=>{let J=(H%j+j)%j;return[z[J*2],z[J*2+1]]},W=H=>{let[J,re]=G(H-1),[ne,te]=G(H),[le,de]=G(H+1);if(we(J,re,ne,te)||we(ne,te,le,de))return!1;let me=Math.hypot(ne-J,te-re),ce=Math.hypot(le-ne,de-te);if(!me||!ce)return!1;let je=-(te-re)/me*Z,De=(ne-J)/me*Z;return(je*(le-ne)+De*(de-te))/ce>Jt},se=(H,J)=>R?R.heightAt(H,J):C,ae=0;for(let H=0;H<j;H+=1){let[J,re]=G(H),[ne,te]=G(H+1),le=Math.hypot(ne-J,te-re);if(le===0||we(J,re,ne,te))continue;let de=-(te-re)/le*Z,me=(ne-J)/le*Z,ce=V[S].normals[H]??[de,me],je=V[S].normals[(H+1)%j]??[de,me],De=oe=>{let _e=ce[0]+(je[0]-ce[0])*oe,Ae=ce[1]+(je[1]-ce[1])*oe,ye=Math.hypot(_e,Ae)||1;return[_e/ye,Ae/ye]},he=[0,...R?R.breaks(J,re,ne,te):[],1];for(let oe=0;oe+1<he.length;oe+=1){let _e=oe===0,Ae=oe+2===he.length,ye=J+(ne-J)*he[oe],Ne=re+(te-re)*he[oe],Ve=J+(ne-J)*he[oe+1],He=re+(te-re)*he[oe+1],Fe=Math.hypot(Ve-ye,He-Ne)/ue*n.tileMetres,$e=(_e&&W(H)?1:0)|(Ae&&W(H+1)?2:0)|(S>0?4:0),Ge=(_e&&xn(J,re)?1:0)|(Ae&&xn(ne,te)?2:0),an=ae+Fe,Ze=De(he[oe]),We=De(he[oe+1]),Un=se(ye,Ne),Cn=se(Ve,He),ke=s.write(O,ye,Ne,0,Ze[0],Ze[1],1,ae,$e,Fe,0,Ge,Un);s.write(O,Ve,He,0,We[0],We[1],1,an,$e,Fe,1,Ge,Cn),s.write(O,ye,Ne,1,Ze[0],Ze[1],1,ae,$e,Fe,0,Ge,Un),s.write(O,Ve,He,1,We[0],We[1],1,an,$e,Fe,1,Ge,Cn),l.push(ke,ke+1,ke+2,ke+1,ke+3,ke+2),ae=an}}}T.roofsCount=a.length-T.roofsFrom,T.wallsCount=l.length-T.wallsFrom,c.push(T)}Y&&u.push(U)}if(s.count===0)return;let g=new Uint32Array(a.length+l.length),m=[],p=0,h=a.length,_=a.values(),A=l.values();c.sort((M,B)=>M.cell-B.cell);let k=-1;for(let M of c){M.cell!==k&&(k=M.cell,m.push({bounds:[...M.bounds],roofsFrom:p,roofsCount:0,wallsFrom:h,wallsCount:0}));let B=m.at(-1);for(let U=0;U<5;U+=1)B.bounds[U]=U<2?Math.min(B.bounds[U],M.bounds[U]):Math.max(B.bounds[U],M.bounds[U]);g.set(_.subarray(M.roofsFrom,M.roofsFrom+M.roofsCount),p),g.set(A.subarray(M.wallsFrom,M.wallsFrom+M.wallsCount),h),p+=M.roofsCount,h+=M.wallsCount,B.roofsCount+=M.roofsCount,B.wallsCount+=M.wallsCount}return{groups:m,vertices:s.bytes(),indices:g,wallsFrom:a.length,top:f,features:u}}function Qt(e,n,t,i){let o=[],r=[];for(let l of e)r.push(o.length/2),o.push(...l);r.push(o.length/2);let s=(l,u)=>{let c=r.findIndex((p,h)=>l>=p&&l<r[h+1]),[f,d]=[r[c],r[c+1]-1];if(u<f||u>d)return!1;let[g,m]=l<u?[l,u]:[u,l];return m-g!==1&&!(g===f&&m===d)?!1:!we(o[l*2],o[l*2+1],o[u*2],o[u*2+1])},a=Pe(o,r.slice(1,-1),2);for(let l=0;l+2<a.length;l+=3){let u=[a[l],a[l+1],a[l+2]],c=0;for(let f=0;f<3;f+=1)s(u[(f+1)%3],u[(f+2)%3])&&(c|=1<<f);for(let[f,d]of u.entries())i.push(t.write(n,o[d*2],o[d*2+1],1,0,0,0,0,0,0,f,c))}}function qt(e,n,t,i){for(let o of e.faces){let r=o.ring,s=r.length/2,a=(l,u)=>{let[c,f]=l<u?[l,u]:[u,l];return f-c!==1&&!(c===0&&f===s-1)?!1:!we(r[l*2],r[l*2+1],r[u*2],r[u*2+1])};for(let l=0;l+2<o.triangles.length;l+=3){let u=[o.triangles[l],o.triangles[l+1],o.triangles[l+2]],c=0;for(let f=0;f<3;f+=1)a(u[(f+1)%3],u[(f+2)%3])&&(c|=1<<f);for(let[f,d]of u.entries()){let g=r[d*2],m=r[d*2+1];i.push(t.write(n,g,m,1,o.normal[0],o.normal[1],0,0,0,0,f,c,e.heightAt(g,m)))}}}}function er(e,n,t,i=Math.PI/6){if(t<1)return{ring:e,normals:[]};let o=e.length/2,r=qe(e)>0,s=n===0?r?-1:1:r?1:-1,a=[],l=[],u=(c,f,d)=>{c=Re(c),f=Re(f),!(a.at(-2)===c&&a.at(-1)===f)&&(a.push(c,f),l.push(d))};for(let c=0;c<o;c+=1){let f=(c+o-1)%o,d=(c+1)%o,[g,m]=[e[f*2],e[f*2+1]],[p,h]=[e[c*2],e[c*2+1]],[_,A]=[e[d*2],e[d*2+1]],k=Math.hypot(p-g,h-m),M=Math.hypot(_-p,A-h);if(!k||!M||xn(p,h)||we(g,m,p,h)||we(p,h,_,A)){u(p,h);continue}let[B,U]=[(p-g)/k,(h-m)/k],[E,C]=[(_-p)/M,(A-h)/M],I=Math.atan2(B*C-U*E,B*E+U*C);if(I*s>=-.08||Math.abs(I)>Math.PI*.85){u(p,h);continue}let N=Math.tan(Math.abs(I)/2),K=Math.min(t*N,k*.2,M*.2),$=K/N;if($<1){u(p,h);continue}let[D,Y]=[-U*s,B*s],[w,y]=[p-B*K-D*$,h-U*K-Y*$],b=Math.atan2(Y,D),x=Math.max(i<=Math.PI/6?2:1,Math.ceil(Math.abs(I)/Math.max(Math.PI/6,Math.min(Math.PI/3,i))));for(let T=0;T<=x;T+=1){let F=b+I*T/x,v=[Math.cos(F),Math.sin(F)];u(w+v[0]*$,y+v[1]*$,v)}}return a[0]===a.at(-2)&&a[1]===a.at(-1)&&(a.splice(-2),l.pop()),a.length>=6?{ring:a,normals:l}:{ring:e,normals:[]}}var wn=class{#e=new ArrayBuffer(4096*pe);#n=new DataView(this.#e);count=0;write(n,t,i,o,r,s,a,l,u,c,f=0,d=0,g=n.top){let m=pe;if((this.count+1)*m>this.#e.byteLength){let _=new ArrayBuffer(this.#e.byteLength*2);new Uint8Array(_).set(new Uint8Array(this.#e)),this.#e=_,this.#n=new DataView(_)}let p=this.#n,h=this.count*m;return p.setUint16(h,Re(t),!0),p.setUint16(h+2,Re(i),!0),p.setUint16(h+4,Math.min(65535,Math.round(n.base*10)),!0),p.setUint16(h+6,Math.min(65535,Math.max(0,Math.round(g*10))),!0),p.setInt8(h+8,Math.round(r*127)),p.setInt8(h+9,Math.round(s*127)),p.setUint8(h+10,o),p.setUint8(h+11,a),p.setUint16(h+12,Math.round(l*10)%65536,!0),p.setUint8(h+14,Math.round(n.jitter*255)),p.setUint8(h+15,Math.round(n.seed*255)),p.setUint16(h+16,Re(n.cx),!0),p.setUint16(h+18,Re(n.cy),!0),p.setUint8(h+20,n.tone+4*n.group),p.setUint8(h+21,n.use),p.setUint8(h+22,u),p.setUint8(h+23,Math.min(255,Math.round(c))),p.setUint16(h+24,n.index,!0),p.setUint8(h+26,f),p.setUint8(h+27,d),this.count+=1,this.count-1}bytes(){return new Uint8Array(this.#e.slice(0,this.count*pe))}},Qe=class{#e=new Uint32Array(8192);length=0;push(...n){if(this.length+n.length>this.#e.length){let t=new Uint32Array(Math.max(this.length+n.length,this.#e.length*2));t.set(this.#e),this.#e=t}for(let t of n)this.#e[this.length++]=t}values(){return this.#e.subarray(0,this.length)}};function nr(e,n){let t=new Map;if(e.features.some(a=>a.properties.night_use!==void 0)){for(let[a,l]of e.features.entries()){let u=Xt[String(l.properties.night_use??"")];u&&t.set(a,u)}return t}let i=n.places;if(!i||i.features.length===0)return t;let o=Yt/n.tileMetres*e.extent,r=[];for(let[a,l]of e.features.entries()){if(l.type!=="Polygon")continue;let u=l.properties.hide_3d;if(u===!0||u===1||u==="1"||u==="true")continue;let c=[1/0,1/0,-1/0,-1/0];for(let f of l.geometry)for(let d=0;d+1<f.length;d+=2)c[0]=Math.min(c[0],f[d]),c[1]=Math.min(c[1],f[d+1]),c[2]=Math.max(c[2],f[d]),c[3]=Math.max(c[3],f[d+1]);r.push({index:a,rings:l.geometry,box:c})}let s=e.extent/i.extent;for(let a of i.features){if(a.type!=="Point")continue;let l=a.properties,u=bn[String(l.type??"")]??bn[String(l.subclass??"")]??bn[String(l.class??"")];if(u)for(let c of a.geometry)for(let f=0;f+1<c.length;f+=2){let d=c[f]*s,g=c[f+1]*s,m,p,h=o;for(let A of r){let[k,M,B,U]=A.box;if(d<k-o||d>B+o||g<M-o||g>U+o)continue;let E=!1;for(let C of A.rings)for(let I=0,N=C.length-2;I+1<C.length;N=I,I+=2){let K=C[N],$=C[N+1],D=C[I],Y=C[I+1];Y>g!=$>g&&d<(K-D)*(g-Y)/($-Y)+D&&(E=!E);let w=D-K,y=Y-$,b=w*w+y*y,x=b?Math.min(1,Math.max(0,((d-K)*w+(g-$)*y)/b)):0,T=Math.hypot(d-K-x*w,g-$-x*y);T<h&&(h=T,p=A.index)}if(E){m=A.index;break}}let _=m??p;_!==void 0&&t.set(_,Math.max(t.get(_)??0,u))}}return t}function Re(e){return Math.min(ue,Math.max(0,Math.round(e)))}function Jn(e){let n=Number(e);return Number.isFinite(n)&&n>0?n:void 0}function tr(e,n){let t=[],i;for(let o of e){let r=[];for(let a=0;a+1<o.length;a+=2){let l=o[a]*n,u=o[a+1]*n;r.length&&l===r.at(-2)&&u===r.at(-1)||r.push(l,u)}if(r.length>=6&&r[0]===r.at(-2)&&r[1]===r.at(-1)&&(r.length-=2),r.length<6)continue;let s=Math.sign(qe(r));s&&(i??=s,s===i||t.length===0?t.push([r]):t.at(-1).push(r))}return t}function qe(e){let n=0,t=e.length/2;for(let i=0;i<t;i+=1){let o=(i+1)%t;n+=e[i*2]*e[o*2+1]-e[o*2]*e[i*2+1]}return n}function rr(e){let n=0,t=0,i=e.length/2;for(let o=0;o<i;o+=1)n+=e[o*2],t+=e[o*2+1];return[n/i,t/i]}function xn(e,n){return e<=0||n<=0||e>=ue||n>=ue}function we(e,n,t,i){let o=ue;return e<=0&&t<=0||e>=o&&t>=o||n<=0&&i<=0||n>=o&&i>=o}function or(e){let n=ue,t=[...e],i=[[0,0,o=>o>=0],[0,n,o=>o<=n],[1,0,o=>o>=0],[1,n,o=>o<=n]];for(let[o,r,s]of i){let a=[],l=t.length/2;for(let u=0;u<l;u+=1){let c=[t[u*2],t[u*2+1]],f=[t[(u+1)%l*2],t[(u+1)%l*2+1]],d=s(c[o]),g=s(f[o]);if(d&&a.push(c[0],c[1]),d!==g){let m=(r-c[o])/(f[o]-c[o]);a.push(c[0]+(f[0]-c[0])*m,c[1]+(f[1]-c[1])*m)}}if(t=a,t.length<6)return[]}return t}function gn(e){let n=Math.sin(e*12.9898+78.233)*43758.5453;return n-Math.floor(n)}var Qn=`\nin float v_haze_depth;\nuniform vec3 u_haze_colour;\nuniform vec3 u_haze; // strength; the view depths where the haze starts and is complete\n\nfloat hazeOf() {\n return u_haze.x > 0.0 ? u_haze.x * smoothstep(u_haze.y, u_haze.z, v_haze_depth) : 0.0;\n}\n\nvec3 hazed(vec3 colour) {\n return mix(colour, u_haze_colour, hazeOf());\n}`;function qn(e){let n=(e.indices.length-e.wallsFrom)/6,t=new Uint8Array(n*16);for(let i=0;i<n;i+=1){let o=e.wallsFrom+i*6,r=e.indices[o]*pe,s=e.indices[o+1]*pe;t.set(e.vertices.subarray(r,r+4),i*16),t.set(e.vertices.subarray(s,s+4),i*16+4),t.set(e.vertices.subarray(r+4,r+8),i*16+8),t[i*16+12]=e.vertices[r+14],t[i*16+13]=e.vertices[r+27]}return t}var Kr=`#version 300 es\nprecision highp float;\nuniform highp sampler2D u_contact;\n${Qn}\nout vec4 fragColor;\nvoid main() {\n float shade = mix(texelFetch(u_contact, ivec2(gl_FragCoord.xy), 0).r, 1.0, hazeOf());\n fragColor = vec4(vec3(shade), 1.0);\n}`;function et(e){let n=e.vertices.length/pe;return{mesh:{...e.groups?{groups:e.groups}:{},wallsFrom:e.wallsFrom,top:e.top,features:e.features,vertexCount:n,indexCount:e.indices.length},data:{vertices:e.vertices,indices:n<=65536?Uint16Array.from(e.indices):e.indices,contact:qn(e)}}}function nt({data:e}){return[e.vertices.buffer,e.indices.buffer,e.contact.buffer]}function Tn(e){let n=ir(e);return n?[Math.min(1,Math.max(0,n[0]/255)),Math.min(1,Math.max(0,n[1]/255)),Math.min(1,Math.max(0,n[2]/255)),Math.min(1,Math.max(0,n[3]))]:null}function ir(e){let n=e.trim().toLowerCase(),t=/^#([\\da-f]{3,8})$/u.exec(n)?.[1];if(t&&[3,4,6,8].includes(t.length)){let _=(t.length<=4?[...t].map(A=>A+A).join(""):t).match(/../gu).map(A=>Number.parseInt(A,16));return[_[0],_[1],_[2],_.length>3?_[3]/255:1]}let i=/^(rgba?|hsla?)\\(([^)]+)\\)$/u.exec(n);if(!i)return null;let o=i[2].split(/[\\s,/]+/u).filter(Boolean);if(o.length<3||o.length>4)return null;let r=o[3]===void 0?1:en(o[3],1);if(i[1].startsWith("rgb")){let[h,_,A]=o.slice(0,3).map(k=>en(k,255));return[h,_,A,r].some(k=>k===null)?null:[h,_,A,r]}let s=Number.parseFloat(o[0]),a=en(o[1],1),l=en(o[2],1);if(!Number.isFinite(s)||a===null||l===null||r===null)return null;let u=(1-Math.abs(2*l-1))*a,c=(s%360+360)%360/60,f=u*(1-Math.abs(c%2-1)),[d,g,m]=c<1?[u,f,0]:c<2?[f,u,0]:c<3?[0,u,f]:c<4?[0,f,u]:c<5?[f,0,u]:[u,0,f],p=l-u/2;return[(d+p)*255,(g+p)*255,(m+p)*255,r]}function en(e,n){let t=e.endsWith("%"),i=Number.parseFloat(e);return Number.isFinite(i)?t?i/100*n:i:null}var fe=8192,Mn=12,sr={primary:{spacing:30,kerb:10},secondary:{spacing:32,kerb:8.5},tertiary:{spacing:34,kerb:7},minor:{spacing:36,kerb:5.5},pedestrian:{spacing:26,kerb:3}},ar={motorway:{spacing:45,kerb:14},trunk:{spacing:40,kerb:12},service:{spacing:38,kerb:4},path:{spacing:28,kerb:1.5},track:{spacing:40,kerb:2.5}},lr={spacing:30,kerb:0},ur=12,cr=18,fr=9,dr={sodium:"#ffa64d",high_pressure_sodium:"#ffa64d",low_pressure_sodium:"#ff9326",led:"#fff1db",mercury:"#e3ecff",metal_halide:"#f4f4ff",fluorescent:"#eef9ff",electric:"#ffd59a",incandescent:"#ffd59a",halogen:"#ffe3b0",gas:"#ffd28a",gaslight:"#ffd28a"},mr={orange:"#ffa64d",yellow:"#ffd27a",warm_white:"#ffe2b8",white:"#fff4e6",cool_white:"#eef4ff",neutral_white:"#fff8f0",blue:"#b8d0ff",green:"#c4ffd0",red:"#ff9a8a"},hr=new Set(["wall","wall_mounted","wall_bracket"]),pr=new Set(["suspended","cable","catenary","wire"]);function it(e,n){let t=n.estimate??"lit",i=new vn,o=new nn(cr),r=new nn(fr),s=e.streetFurniture;if(s){let m=fe/s.extent;for(let p of s.features){let h=p.properties;if(p.type!=="Point"||h.subclass!=="street_lamp")continue;let _=yr(h),A=br(h),k=Math.max(1,Math.min(4,Number(h.light_count)||1)),M=Math.min(24,Math.max(5,_*1.7*(k>1?1.15:1)));for(let B of p.geometry)for(let U=0;U+1<B.length;U+=2){let E=B[U]*m,C=B[U+1]*m;if(!rt(E,C))continue;i.write(E,C,_,M,!0,A);let I=ot(E,C,n.tileMetres);o.add(...I),r.add(...I)}}}let a=i.count;if(t==="none")return i.done(a);let l=e.transportation,u=0;if(l){let m=n.tileMetres/l.extent;for(let p of l.features)if(!(p.type!=="LineString"||!tt(p.properties,"streets")))for(let h of p.geometry)u+=gr(h,l.extent)*m}let c=u>0&&a/(u/1e3)>=ur,f=t==="streets"&&!c?"streets":"lit",d=(m,p,h,_)=>{let A=fe/m.extent,k=[];for(let N=0;N+1<p.length;N+=2)k.push(p[N]*A,p[N+1]*A);let M=n.tileMetres/fe,B=h.kerb*.45/M,U=Rn(k[0]*.013+k[1]*.029+_)*h.spacing,E=0,C=U,I=Rn(k[0]+k[1]*3.1)<.5?1:-1;for(let N=2;N<k.length;N+=2){let K=k[N-2],$=k[N-1],D=k[N],Y=k[N+1],w=Math.hypot(D-K,Y-$)*M;if(w!==0){for(;C<=E+w;){let y=(C-E)/w,b=-(Y-$)/(w/M)*I,x=(D-K)/(w/M)*I,T=K+(D-K)*y+b*B,F=$+(Y-$)*y+x*B;if(C+=h.kerb>0?h.spacing/2:h.spacing,h.kerb>0&&(I=-I),!rt(T,F))continue;let v=ot(T,F,n.tileMetres);o.near(...v)||r.near(...v)||(r.add(...v),i.write(T,F,7,15,!1))}E+=w}}};if(l)for(let m of l.features){if(m.type!=="LineString")continue;let p=tt(m.properties,f);if(p)for(let h of m.geometry)d(l,h,p,1)}let g=e.sidewalks;if(g){for(let m of g.features)if(!(m.type==="Point"||!kn(m.properties.lit)))for(let p of m.geometry)d(g,p,lr,2)}return i.done(a)}function tt(e,n){if(e.brunnel==="tunnel"||e.covered===!0)return;let t=e.lit;if(t===!1||t==="no")return;let i=String(e.class??""),o=String(e.subclass??""),r=i==="path"&&(o==="pedestrian"||o==="living_street")?"pedestrian":i,s=sr[r];if(s&&(n==="streets"||kn(t)))return s;let a=ar[r];if(a&&kn(t))return a}function kn(e){return e===!0||e==="yes"||e===1||e==="1"||e==="true"}function yr(e){let n=Number(e.height);if(Number.isFinite(n)&&n>=.5&&n<=40)return n;let t=String(e.lamp_mount??"").toLowerCase();return hr.has(t)?4.5:pr.has(t)?7.5:7}function br(e){let n=e.light_colour??e["light:colour"];if(typeof n=="string"&&n){let r=n.toLowerCase().replaceAll(" ","_"),s=Tn(mr[r]??n);if(s)return[s[0],s[1],s[2]]}let t=String(e.lamp_type??"").toLowerCase().replaceAll("-","_").replaceAll(" ","_"),i=dr[t];if(!i)return;let o=Tn(i);return[o[0],o[1],o[2]]}function rt(e,n){return e>=0&&n>=0&&e<fe&&n<fe}function ot(e,n,t){return[e/fe*t,n/fe*t]}function gr(e,n){let t=0;for(let i=2;i+1<e.length;i+=2){let o=(e[i-2]+e[i])/2,r=(e[i-1]+e[i+1])/2;o<0||r<0||o>=n||r>=n||(t+=Math.hypot(e[i]-e[i-2],e[i+1]-e[i-1]))}return t}var nn=class{constructor(n){this.size=n}size;#e=new Map;add(n,t){let i=`${Math.floor(n/this.size)}/${Math.floor(t/this.size)}`,o=this.#e.get(i);o?o.push([n,t]):this.#e.set(i,[[n,t]])}near(n,t){let i=Math.floor(n/this.size),o=Math.floor(t/this.size);for(let r=-1;r<=1;r+=1)for(let s=-1;s<=1;s+=1)for(let[a,l]of this.#e.get(`${i+r}/${o+s}`)??[])if(Math.hypot(a-n,l-t)<this.size)return!0;return!1}},vn=class{#e=new ArrayBuffer(256*Mn);#n=new DataView(this.#e);count=0;write(n,t,i,o,r,s){let a=Mn;if((this.count+1)*a>this.#e.byteLength){let c=new ArrayBuffer(this.#e.byteLength*2);new Uint8Array(c).set(new Uint8Array(this.#e)),this.#e=c,this.#n=new DataView(c)}let l=this.#n,u=this.count*a;l.setUint16(u,Math.min(fe,Math.max(0,Math.round(n))),!0),l.setUint16(u+2,Math.min(fe,Math.max(0,Math.round(t))),!0),l.setUint16(u+4,Math.min(65535,Math.round(i*10)),!0),l.setUint8(u+6,Math.min(255,Math.round(o))),l.setUint8(u+7,(r?1:0)|(s?2:0)),l.setUint8(u+8,Math.round((s?.[0]??0)*255)),l.setUint8(u+9,Math.round((s?.[1]??0)*255)),l.setUint8(u+10,Math.round((s?.[2]??0)*255)),l.setUint8(u+11,Math.round(Rn(n*.0731+t*.19137)*255)),this.count+=1}done(n){if(this.count!==0)return{lamps:new Uint8Array(this.#e.slice(0,this.count*Mn)),mapped:n,estimated:this.count-n}}};function Rn(e){let n=Math.sin(e*12.9898+78.233)*43758.5453;return n-Math.floor(n)}var oo=Object.freeze({source:"tileflow",layers:Object.freeze({streetFurniture:"street_furniture",transportation:"transportation",sidewalk:"sidewalk"}),estimate:"lit",color:"#ffcf8f",intensity:1});var Me=["round","open","tall","conifer","columnar","palm"];var ut=Object.freeze({height:"height",diameterCrown:"diameter_crown",circumference:"circumference",genus:"genus",species:"species",leafType:"leaf_type",taxon:"taxon",canopyRank:"rank",canopyClearance:"clearance_px_z15",canopyCover:"cover_pct",canopyHeight:"height_m",subclass:"subclass",hedge:"hedge"}),Sn=Object.freeze({round:1,open:1,tall:1}),tn=16,q=8192,rn=16,st={round:{height:[6,12],crown:[.66,.9]},open:{height:[5,10],crown:[.8,1.05]},tall:{height:[9,17],crown:[.48,.68]},conifer:{height:[7,16],crown:[.46,.66]},columnar:{height:[9,18],crown:[.22,.36]},palm:{height:[12,20],crown:[.42,.55]}};var on=[2,45],_n=[1,25],wr=1.2,xr=1.5,Tr=1.3,Mr=1,kr=[.3,10],vr=new Set(["acoelorrhaphe","adonidia","archontophoenix","areca","arecastrum","bismarckia","brahea","butia","caryota","chamaedorea","chamaerops","coccothrinax","cocos","dypsis","elaeis","howea","jubaea","licuala","livistona","phoenix","pritchardia","ptychosperma","rhapis","roystonea","sabal","serenoa","syagrus","thrinax","trachycarpus","veitchia","washingtonia","wodyetia"]),Rr=new Set(["cupressus","calocedrus","thuja"]),_r=new Set(["abies","araucaria","cedrus","cryptomeria","juniperus","larix","metasequoia","picea","pinus","pseudotsuga","sequoia","sequoiadendron","taxodium","taxus","tsuga"]),at=Object.freeze({...Object.fromEntries(["acacia","albizia","arbutus","bursera","ceratonia","delonix","ficus","gleditsia","jacaranda","olea","quercus","robinia","schinus","sophora","styphnolobium","tamarix"].map(e=>[e,"open"])),...Object.fromEntries(["betula","celtis","fraxinus","ginkgo","liquidambar","liriodendron","magnolia","platanus","populus","pyrus","ulmus","zelkova"].map(e=>[e,"tall"])),...Object.fromEntries(["acer","aesculus","carpinus","castanea","catalpa","cercis","citrus","fagus","lagerstroemia","malus","melia","morus","prunus","sorbus","tilia"].map(e=>[e,"round"]))});function lt(e,n={}){let t={...ut,...n},i=String(e[t.leafType]??"").toLowerCase(),o=String(e[t.taxon]??"").toLowerCase(),r=An(e[t.genus])??An(e[t.species])??(o.endsWith("aceae")?void 0:An(e[t.taxon]));if(i.includes("palm")||o.includes("arecaceae")||r&&vr.has(r))return"palm";if(o.includes("cupressaceae")&&!r||o.includes("pinaceae"))return"conifer";if(r&&Rr.has(r))return"columnar";if(i.includes("needle")||r&&_r.has(r))return"conifer";if(r&&at[r])return at[r];if(i.includes("broad"))return"broadleaf"}function An(e){return typeof e!="string"?void 0:e.trim().split(/\\s+/u)[0]?.toLowerCase()||void 0}function ct(e,n){let t={...ut,...n.fields},i=n.unknownForms??Sn,o=n.regions??[],{tile:r,tileMetres:s}=n,a=s/2**(15-r.z)/512,l=[],u=0,c=0,f=(w,y)=>{if(o.length===0)return i;let[b,x]=Fr(r,w/q,y/q);for(let T of o){let[F,v,L,O]=T.bounds;if(x>=v&&x<=O&&(F<=L?b>=F&&b<=L:b>=F||b<=L))return T.unknownForms}return i},d=(w,y,b,x)=>{let T=st[w],F=Fn(T.crown,ee(y,2)),v=b,L=x;return v===void 0&&L===void 0&&(v=Fn(T.height,ee(y,1))),v===void 0&&(v=L/F),L===void 0&&(L=v*F),{height:Te(v,on),crown:Te(L,_n)}},g=(w,y,b,x,T,F)=>{let v=ze(r.x*q+w,r.y*q+y,7),L=b===void 0?sn(f(w,y),ee(v,3)):b==="broadleaf"?sn(Ar(f(w,y)),ee(v,3)):b,O=x===void 0&&T===void 0&&F!==void 0?d(L,v,Fn(st[L].height,Te(F/3,[0,1]))):d(L,v,x,T);l.push({x:w,y,...O,turn:ee(v,4),shade:ee(v,5),form:Me.indexOf(L),rank:Math.floor(ee(v,6)*rn),seed:ee(v,7),canopy:0}),u+=1},m=e.trees;if(m){let w=q/m.extent;for(let y of m.features){if(y.type!=="Point")continue;let b=y.properties,x=lt(b,t),T=xe(b[t.height],on),F=xe(b[t.diameterCrown],_n),v=xe(b[t.circumference],[.1,12]);for(let L of y.geometry)for(let O=0;O+1<L.length;O+=2){let V=L[O],R=L[O+1];V<0||R<0||V>=m.extent||R>=m.extent||g(V*w,R*w,x,T,F,v)}}}let p=e.trees;if(p){let w=q/p.extent,y=(n.rowSpacing??8)/(s/p.extent);for(let b of p.features){if(b.type!=="LineString")continue;let x=b.properties,T=lt(x,t),F=xe(x[t.height],on),v=xe(x[t.diameterCrown],_n);for(let L of b.geometry){let O=y/2,V=0;for(let R=0;R+3<L.length;R+=2){let[S,z,P,Z]=[L[R],L[R+1],L[R+2],L[R+3]],j=Math.hypot(P-S,Z-z);for(;O<=V+j;){let G=j>0?(O-V)/j:0,W=S+(P-S)*G,se=z+(Z-z)*G;W>=0&&se>=0&&W<p.extent&&se<p.extent&&g(W*w,se*w,T,F,v,void 0),O+=y}V+=j}}}}let h=e.canopy;if(h){let w=q/h.extent;for(let y of h.features){if(y.type!=="Point")continue;let b=y.properties,x=Te(Math.floor(Number(b[t.canopyRank]??8)),[0,rn-1]),T=Math.max(4,Number(b[t.canopyClearance]??8))*a,F=Number(b[t.canopyCover]??30),v=F>=60?3:F>=30?2:1;for(let L of y.geometry)for(let O=0;O+1<L.length;O+=2){let V=L[O],R=L[O+1];if(V<0||R<0||V>=h.extent||R>=h.extent)continue;let S=V*w,z=R*w,P=ze(r.x*q+S,r.y*q+z,11),Z=f(S,z),j=xe(b[t.canopyHeight],on),G=Te(Math.min(T*(v===1?1.3:.95),11)*(.85+ee(P,1)*.25),[3,12]),W=Math.max(0,Math.min(G*.5,T-G/2)),se=ee(P,2)*Math.PI*2;for(let ae=0;ae<v;ae+=1){let H=ze(P,ae,13),J=se+ae*Math.PI*2/v,re=v===1?W*.3*ee(H,1):W,ne=S+Math.cos(J)*re/(s/q),te=z+Math.sin(J)*re/(s/q);if(ne<0||te<0||ne>=q||te>=q)continue;let le=sn(Z,ee(H,3)),de=G*(.85+ee(H,2)*.3),me=j===void 0?void 0:j*(.85+ee(H,6)*.25),ce=d(le,H,me,le==="palm"?void 0:de);l.push({x:ne,y:te,...ce,turn:ee(H,4),shade:ee(H,5),form:Me.indexOf(le),rank:x,seed:ee(H,7),canopy:1}),c+=1}}}}let _=[],A=e.hedges;if(A){let w=q/A.extent,y=wr/(s/A.extent);for(let b of A.features){if(b.type==="Point"||b.properties[t.subclass]!=="hedge")continue;let x=b.properties[t.hedge]==="hedge_bank"?Mr:0,T=(xe(b.properties[t.height],kr)??Tr)+x;for(let F of b.geometry){let v=y/2,L=0;for(let O=0;O+3<F.length;O+=2){let[V,R,S,z]=[F[O],F[O+1],F[O+2],F[O+3]],P=Math.hypot(S-V,z-R),Z=(Math.atan2(R-z,S-V)/(Math.PI*2)+1)%1;for(;v<=L+P;){let j=P>0?(v-L)/P:0,G=V+(S-V)*j,W=R+(z-R)*j;if(G>=0&&W>=0&&G<A.extent&&W<A.extent){let se=ze(r.x*q+G*w,r.y*q+W*w,17);_.push({x:G*w,y:W*w,height:T,turn:Z,shade:ee(se,5),seed:ee(se,7)})}v+=y}L+=P}}}}let k=w=>Te(Math.floor(n.variants?.[Me[w]]??1),[1,4]),M=w=>Math.min(k(w.form)-1,Math.floor(ee(Math.floor(w.seed*256),9)*k(w.form))),B=l.map(M),U=l.map((w,y)=>y);U.sort((w,y)=>l[w].form-l[y].form||B[w]-B[y]||l[w].rank-l[y].rank);let E=new Uint8Array(l.length*tn),C=new DataView(E.buffer),I=0,N=()=>({start:0,count:0,upTo:new Array(rn).fill(0)}),K=Object.fromEntries(Me.map((w,y)=>[w,{...N(),variants:Array.from({length:k(y)},N)}])),$=(w,y,b)=>{w.count===0&&(w.start=y),w.count+=1;for(let x=b;x<rn;x+=1)w.upTo[x]+=1};U.forEach((w,y)=>{let b=l[w],x=y*tn;C.setUint16(x,Math.min(q-1,Math.round(b.x)),!0),C.setUint16(x+2,Math.min(q-1,Math.round(b.y)),!0),C.setUint16(x+4,Math.round(b.height*10),!0),C.setUint16(x+6,Math.round(b.crown*10),!0),E[x+8]=Math.floor(b.turn*256)&255,E[x+9]=Math.floor(b.shade*256)&255,E[x+10]=b.form,E[x+11]=b.rank,E[x+12]=Math.floor(b.seed*256)&255,E[x+13]=b.canopy,E[x+14]=B[w],I=Math.max(I,b.height);let T=K[Me[b.form]];$(T,y,b.rank),$(T.variants[B[w]],y,b.rank)});let D=new Uint8Array(_.length*tn),Y=new DataView(D.buffer);return _.forEach((w,y)=>{let b=y*tn;Y.setUint16(b,Math.min(q-1,Math.round(w.x)),!0),Y.setUint16(b+2,Math.min(q-1,Math.round(w.y)),!0),Y.setUint16(b+4,Math.round(w.height*10),!0),Y.setUint16(b+6,Math.round(xr*10),!0),D[b+8]=Math.round(w.turn*256)&255,D[b+9]=Math.floor(w.shade*256)&255,D[b+12]=Math.floor(w.seed*256)&255,I=Math.max(I,w.height)}),{trees:E,forms:K,hedges:D,tallest:I,mapped:u,canopy:c}}function Ar(e){let n={round:e.round??0,open:e.open??0,tall:e.tall??0};return n.round+n.open+n.tall>0?n:Sn}function sn(e,n){let t=0;for(let o of Me)t+=Math.max(0,e[o]??0);if(t<=0)return sn(Sn,n);let i=n*t;for(let o of Me){let r=Math.max(0,e[o]??0);if(i<r)return o;i-=r}return"round"}function xe(e,n){let t=typeof e=="number"?e:typeof e=="string"?Number.parseFloat(e):NaN;return Number.isFinite(t)&&t>0?Te(t,n):void 0}function Te(e,[n,t]){return Math.min(t,Math.max(n,e))}function Fn([e,n],t){return e+(n-e)*t}function Fr(e,n,t){let i=2**e.z,o=(e.x+n)/i*360-180,r=Math.atan(Math.sinh(Math.PI*(1-2*(e.y+t)/i)))*180/Math.PI;return[o,r]}function ze(e,n,t){let i=(Math.imul(Math.floor(e)|0,668265261)^Math.imul(Math.floor(n)|0,374761393)^Math.imul(t,2654435761))>>>0;return i=Math.imul(i^i>>>15,2246822507)>>>0,i=Math.imul(i^i>>>13,3266489909)>>>0,(i^i>>>16)>>>0}function ee(e,n){return ze(e,n,20973)/4294967296}var Sr=[void 0,"Point","LineString","Polygon"];function ft(e,n={}){let t=n.layers?new Set(n.layers):void 0,i={},o=new Bn(e,0,e.length);for(;o.more();){let[r,s]=o.tag();if(r!==3){o.skip(s);continue}let a=o.message(),l=Lr(a,t);l&&!(l.name in i)&&(i[l.name]=l.layer)}return i}function Lr(e,n){let t,i=4096,o=[],r=[],s=[];for(;e.more();){let[a,l]=e.tag();if(a===1?t=e.string():a===2?s.push(e.message()):a===3?o.push(e.string()):a===4?r.push(Ur(e.message())):a===5?i=e.varint():e.skip(l),t!==void 0&&n&&!n.has(t))return}if(!(t===void 0||n&&!n.has(t)))return{name:t,layer:Object.freeze({extent:i,features:Object.freeze(s.flatMap(a=>{let l=Br(a,o,r);return l?[l]:[]}))})}}function Br(e,n,t){let i,o,r={},s=[];for(;e.more();){let[a,l]=e.tag();if(a===1)i=e.varint();else if(a===2){let u=e.packed();for(let c=0;c+1<u.length;c+=2){let f=n[u[c]],d=t[u[c+1]];f!==void 0&&d!==void 0&&(r[f]=d)}}else a===3?o=Sr[e.varint()]:a===4?s=e.packed():e.skip(l)}if(o)return Object.freeze({...i===void 0?{}:{id:i},type:o,properties:Object.freeze(r),geometry:Object.freeze(Or(s,o))})}function Or(e,n){let t=[],i,o=0,r=0,s=0;for(;s<e.length;){let a=e[s++],l=a&7,u=a>>>3;if(l===7){i&&i.length>=2&&i.push(i[0],i[1]);continue}if(l!==1&&l!==2)throw new Error(`Unknown geometry command ${l} in vector tile.`);if(s+u*2>e.length)throw new Error("Truncated vector tile geometry.");for(let c=0;c<u;c+=1){if(o+=Ln(e[s++]),r+=Ln(e[s++]),l===1&&(n!=="Point"||c===0)&&t.push(i=[]),!i)throw new Error("Vector tile geometry draws a line before moving to its start.");i.push(o,r)}}return t}var Ln=e=>e%2===1?-(e+1)/2:e/2;function Ur(e){let n="";for(;e.more();){let[t,i]=e.tag();t===1?n=e.string():t===2?n=e.float():t===3?n=e.double():t===4?n=e.varint(!0):t===5?n=e.varint():t===6?n=Ln(e.varint()):t===7?n=e.varint()!==0:e.skip(i)}return n}var Cr=new TextDecoder,Bn=class e{constructor(n,t,i){this.bytes=n;this.end=i;this.position=t,this.view=new DataView(n.buffer,n.byteOffset,n.byteLength)}bytes;end;position;view;more(){return this.position<this.end}tag(){let n=this.varint();return[Math.floor(n/8),n&7]}varint(n=!1){let t=0,i=0;for(let o=0;o<10;o+=1){if(this.position>=this.end)throw new Error("Truncated vector tile.");let r=this.bytes[this.position++];if(o<4?t|=(r&127)<<o*7:o===4?(t|=(r&15)<<28,i=(r&112)>>4):o<9?i|=(r&127)<<(o-5)*7+3:i|=(r&1)<<31,r<128)return n?i*4294967296+(t>>>0):(i>>>0)*4294967296+(t>>>0)}throw new Error("Invalid varint in vector tile.")}span(){let n=this.varint(),t=this.position;if(t+n>this.end)throw new Error("Truncated vector tile.");return this.position=t+n,[t,t+n]}message(){let[n,t]=this.span();return new e(this.bytes,n,t)}string(){let[n,t]=this.span();return Cr.decode(this.bytes.subarray(n,t))}packed(){let[n,t]=this.span(),i=new e(this.bytes,n,t),o=[];for(;i.more();)o.push(i.varint());return o}float(){if(this.position+4>this.end)throw new Error("Truncated vector tile.");let n=this.view.getFloat32(this.position,!0);return this.position+=4,n}double(){if(this.position+8>this.end)throw new Error("Truncated vector tile.");let n=this.view.getFloat64(this.position,!0);return this.position+=8,n}skip(n){if(n===0)this.varint();else if(n===1)this.position+=8;else if(n===2)this.span();else if(n===5)this.position+=4;else throw new Error(`Unsupported protocol buffer wire type ${n} in vector tile.`);if(this.position>this.end)throw new Error("Truncated vector tile.")}};function dt(e){return Object.values(e.layers).filter(n=>typeof n=="string")}function mt(e,n){if(e.kind==="buildings"){let r=n(e.layers.building);if(!r)return;let s=n(e.layers.places),a=Kn(r,{...e.options,...s?{places:s}:{}});return a&&et(a)}if(e.kind==="trees"){let r=n(e.layers.tree),s=n(e.layers.canopy),a=n(e.layers.hedge);if(!r&&!s&&!a)return;let l=ct({...r?{trees:r}:{},...s?{canopy:s}:{},...a?{hedges:a}:{}},e.options);return l.trees.length>0||l.hedges.length>0?l:void 0}let t=n(e.layers.streetFurniture),i=n(e.layers.transportation),o=n(e.layers.sidewalk);return it({...t?{streetFurniture:t}:{},...i?{transportation:i}:{},...o?{sidewalks:o}:{}},e.options)}function ht(e,n){if(!n)return[];if(e==="buildings")return nt(n);if(e==="trees"){let{trees:t,hedges:i}=n;return[t.buffer,i.buffer].filter((o,r,s)=>s.indexOf(o)===r)}return[n.lamps.buffer]}function pt(e=16){let n=new Map;return{read(t,i,o){let r=n.get(t);for(n.delete(t),r??={bytes:i,layers:new Map},n.set(t,r);n.size>e;)n.delete(n.keys().next().value);let s=o.filter(l=>!r.layers.has(l));if(s.length>0){let l=ft(r.bytes,{layers:s});for(let u of s)r.layers.set(u,l[u])}let a=r.layers;return l=>l===void 0?void 0:a.get(l)}}}var On=globalThis,Pr=pt();On.onmessage=({data:{url:e,bytes:n,task:t}})=>{try{let i=mt(t,Pr.read(e,n,dt(t)));On.postMessage({result:i},ht(t.kind,i))}catch(i){On.postMessage({error:String(i)})}};})();\n'], { type: "text/javascript" })
10050
+ new Blob(['"use strict";(()=>{var Be=new Set,ln=!1;function Pe(e,n,t=2){let i=n&&n.length,o=i?n[0]*t:e.length;Be.size&&Be.clear();let r=zn(e,0,o,t,!0),s=[];if(!r||r.next===r.prev)return s;let a=0,l=0,u=0;if(i&&(r=xt(e,n,r,t)),e.length>80*t){a=e[0],l=e[1];let c=a,f=l;for(let d=t;d<o;d+=t){let g=e[d],m=e[d+1];g<a&&(a=g),m<l&&(l=m),g>c&&(c=g),m>f&&(f=m)}u=Math.max(c-a,f-l),u=u!==0?32767/u:0}return un(r,s,a,l,u),s}function zn(e,n,t,i,o){let r=null;if(o===Ut(e,n,t,i)>0)for(let s=n;s<t;s+=i)r=In(s/i|0,e[s],e[s+1],r);else for(let s=t-i;s>=n;s-=i)r=In(s/i|0,e[s],e[s+1],r);return r&&Oe(r,r.next)&&(Ce(r),r=r.next),r}function ge(e,n=e){let t=n===e,i=e,o;do o=!1,i!==i.next&&(Be.size===0||!Be.has(i))&&(Oe(i,i.next)||Q(i.prev,i,i.next)===0)?((t||i===n)&&(n=i.prev),ln=!0,Ce(i),i=i.prev,o=!0):(t||i!==n)&&(i=i.next,o=!t);while(o||i!==n);return n}function un(e,n,t,i,o){o&&Ft(e,t,i,o);let r=e,s=!1;for(;e.prev!==e.next;){let a=e.prev,l=e.next;if(Q(a,e,l)<0&&(o?bt(e,t,i,o):yt(e))){n.push(a.i,e.i,l.i),Ce(e),e=l,r=l;continue}if(e=l,e===r){if(ln=!1,e=ge(e),ln){r=e;continue}if(!s){e=gt(e,n),r=e,s=!0;continue}wt(e,n,t,i,o);break}}}function yt(e){let n=e.prev,t=e,i=e.next,o=n.x,r=t.x,s=i.x,a=n.y,l=t.y,u=i.y,c=Math.min(o,r,s),f=Math.min(a,l,u),d=Math.max(o,r,s),g=Math.max(a,l,u),m=i.next;for(;m!==n;){if(m.x>=c&&m.x<=d&&m.y>=f&&m.y<=g&&!(o===m.x&&a===m.y)&&Ke(o,a,r,l,s,u,m.x,m.y)&&Q(m.prev,m,m.next)>=0)return!1;m=m.next}return!0}function bt(e,n,t,i){let o=e.prev,r=e,s=e.next,a=o.x,l=r.x,u=s.x,c=o.y,f=r.y,d=s.y,g=Math.min(a,l,u),m=Math.min(c,f,d),p=Math.max(a,l,u),h=Math.max(c,f,d),_=mn(g,m,n,t,i),F=mn(p,h,n,t,i),k=e.prevZ;for(;k&&k.z>=_;){if(k.x>=g&&k.x<=p&&k.y>=m&&k.y<=h&&k!==s&&!(a===k.x&&c===k.y)&&Ke(a,c,l,f,u,d,k.x,k.y)&&Q(k.prev,k,k.next)>=0)return!1;k=k.prevZ}let M=e.nextZ;for(;M&&M.z<=F;){if(M.x>=g&&M.x<=p&&M.y>=m&&M.y<=h&&M!==s&&!(a===M.x&&c===M.y)&&Ke(a,c,l,f,u,d,M.x,M.y)&&Q(M.prev,M,M.next)>=0)return!1;M=M.nextZ}return!0}function gt(e,n){let t=e,i=!1;do{let o=t.prev,r=t.next.next;Nn(o,t,t.next,r,!1)&&Ue(o,r)&&Ue(r,o)&&(n.push(o.i,t.i,r.i),Ce(t),Ce(t.next),t=e=r,i=!0),t=t.next}while(t!==e);return i?ge(t):t}function wt(e,n,t,i,o){let r=e;do{let s=r.next.next;for(;s!==r.prev;){if(r.i!==s.i&&Lt(r,s)){let a=Vn(r,s);r=ge(r,r.next),a=ge(a,a.next),un(r,n,t,i,o),un(a,n,t,i,o);return}s=s.next}r=r.next}while(r!==e)}var cn=!1;function xt(e,n,t,i){let o=[];for(let r=0,s=n.length;r<s;r++){let a=n[r]*i,l=r<s-1?n[r+1]*i:e.length,u=zn(e,a,l,i,!1);u===u.next&&Be.add(u),o.push(St(u))}o.sort(Tt),kt(e.length/i,n.length),Dn(t,t),cn=!0;for(let r=0;r<o.length;r++)t=Mt(o[r],t);return cn=!1,ge(t)}function Tt(e,n){return e.x-n.x||e.y-n.y||(e.next.y-e.y)/(e.next.x-e.x)-(n.next.y-n.y)/(n.next.x-n.x)}function Mt(e,n){let t=Rt(e,n);if(!t)return n;let i=Vn(t,e),o=i.next;return Dn(t,o.next),ge(i,i.next),ge(t,t.next)}var jn=16,X=new Float64Array(0),Je=0,fn=[],dn=[];function kt(e,n){let t=Math.ceil((e+2*n)/jn)+n+2;X.length<t*4&&(X=new Float64Array(t*4)),Je=0}function Dn(e,n){let t=e;do{let i=Je++;fn[i]=t;let o=t.x,r=t.y,s=t.x,a=t.y,l=0;do{let c=t.next;t.z=i,c.x<o&&(o=c.x),c.x>s&&(s=c.x),c.y<r&&(r=c.y),c.y>a&&(a=c.y),t=c}while(++l<jn&&t!==n);dn[i]=t;let u=i*4;X[u]=o,X[u+1]=r,X[u+2]=s,X[u+3]=a}while(t!==n)}function vt(e,n){let t=e.z*4;n.x<X[t]&&(X[t]=n.x),n.y<X[t+1]&&(X[t+1]=n.y),n.x>X[t+2]&&(X[t+2]=n.x),n.y>X[t+3]&&(X[t+3]=n.y)}function Pn(e){let n=dn[e];for(;n.prev.next!==n;)n=n.next;return dn[e]=n,n}function En(e){let n=fn[e];for(;n.prev.next!==n;)n=n.next;return fn[e]=n,n}function Rt(e,n){let t=n,i=e.x,o=e.y,r=-1/0,s;if(Oe(e,t))return t;for(let d=0,g=0;d<Je;d++,g+=4){if(o<X[g+1]||o>X[g+3]||X[g]>i||X[g+2]<=r)continue;let m=Pn(d);t=En(d);do{if(t.prev.next===t){if(Oe(e,t.next))return t.next;if(o<=t.y&&o>=t.next.y&&t.next.y!==t.y){let p=t.x+(o-t.y)*(t.next.x-t.x)/(t.next.y-t.y);if(p<=i&&p>r&&(r=p,s=t.x<t.next.x?t:t.next,p===i))return s}}t=t.next}while(t!==m)}if(!s)return null;let a=s.x,l=s.y,u=Math.min(o,l),c=Math.max(o,l),f=1/0;for(let d=0,g=0;d<Je;d++,g+=4){if(X[g+2]<a||X[g]>i||X[g+3]<u||X[g+1]>c)continue;let m=Pn(d);t=En(d);do{if(t.prev.next===t&&i>=t.x&&t.x>=a&&i!==t.x&&Ke(o<l?i:r,o,a,l,o<l?r:i,o,t.x,t.y)){let p=Math.abs(o-t.y)/(i-t.x);(Ue(t,e)||t.y===o&&t.next.y===o&&t.next.x>i)&&(p<f||p===f&&(t.x>s.x||t.x===s.x&&_t(s,t)))&&(s=t,f=p)}t=t.next}while(t!==m)}return s}function _t(e,n){return Q(e.prev,e,n.prev)<0&&Q(n.next,e,e.next)<0}var ie=[],ve=[],be=new Uint32Array(0),Se=new Uint32Array(0),Le=new Uint32Array(256);function Ft(e,n,t,i){let o=e,r=0;do o.z=mn(o.x,o.y,n,t,i),ie[r++]=o,o=o.next;while(o!==e);At(r);let s=null;for(let a=0;a<r;a++){let l=ie[a];l.prevZ=s,s&&(s.nextZ=l),s=l}s.nextZ=null,ie.fill(null,0,r),ve.fill(null,0,r)}function At(e){if(e<=32){for(let n=1;n<e;n++){let t=ie[n],i=t.z,o=n-1;for(;o>=0&&ie[o].z>i;)ie[o+1]=ie[o],o--;ie[o+1]=t}return}be.length<e&&(be=new Uint32Array(e),Se=new Uint32Array(e),ve=new Array(e));for(let n=0;n<e;n++)be[n]=ie[n].z;Xe(e,ie,be,ve,Se,0),Xe(e,ve,Se,ie,be,8),Xe(e,ie,be,ve,Se,16),Xe(e,ve,Se,ie,be,24)}function Xe(e,n,t,i,o,r){Le.fill(0);for(let a=0;a<e;a++)Le[t[a]>>>r&255]++;let s=0;for(let a=0;a<256;a++){let l=Le[a];Le[a]=s,s+=l}for(let a=0;a<e;a++){let l=t[a],u=Le[l>>>r&255]++;i[u]=n[a],o[u]=l}}function mn(e,n,t,i,o){return e=(e-t)*o|0,n=(n-i)*o|0,e=(e|e<<8)&16711935,e=(e|e<<4)&252645135,e=(e|e<<2)&858993459,e=(e|e<<1)&1431655765,n=(n|n<<8)&16711935,n=(n|n<<4)&252645135,n=(n|n<<2)&858993459,n=(n|n<<1)&1431655765,e|n<<1}function St(e){let n=e,t=e;do(n.x<t.x||n.x===t.x&&n.y<t.y)&&(t=n),n=n.next;while(n!==e);return t}function Ke(e,n,t,i,o,r,s,a){return(o-s)*(n-a)>=(e-s)*(r-a)&&(e-s)*(i-a)>=(t-s)*(n-a)&&(t-s)*(r-a)>=(o-s)*(i-a)}function Lt(e,n){let t=Oe(e,n)&&Q(e.prev,e,e.next)>0&&Q(n.prev,n,n.next)>0;return e.next.i!==n.i&&(t||Ue(e,n)&&Ue(n,e)&&(Q(e.prev,e,n.prev)!==0||Q(e,n.prev,n)!==0))&&!Bt(e,n)&&(t||Ot(e,n))}function Q(e,n,t){return(n.y-e.y)*(t.x-n.x)-(n.x-e.x)*(t.y-n.y)}function Oe(e,n){return e.x===n.x&&e.y===n.y}function Nn(e,n,t,i,o=!0){let r=Q(e,n,t),s=Q(e,n,i),a=Q(t,i,e),l=Q(t,i,n);return(r>0&&s<0||r<0&&s>0)&&(a>0&&l<0||a<0&&l>0)?!0:o?!!(r===0&&Ye(e,t,n)||s===0&&Ye(e,i,n)||a===0&&Ye(t,e,i)||l===0&&Ye(t,n,i)):!1}function Ye(e,n,t){return n.x<=Math.max(e.x,t.x)&&n.x>=Math.min(e.x,t.x)&&n.y<=Math.max(e.y,t.y)&&n.y>=Math.min(e.y,t.y)}function Bt(e,n){let t=Math.min(e.x,n.x),i=Math.max(e.x,n.x),o=Math.min(e.y,n.y),r=Math.max(e.y,n.y),s=e;do{let a=s.next;if(s.x>i&&a.x>i||s.x<t&&a.x<t||s.y>r&&a.y>r||s.y<o&&a.y<o){s=a;continue}if(s.i!==e.i&&a.i!==e.i&&s.i!==n.i&&a.i!==n.i&&Nn(s,a,e,n))return!0;s=a}while(s!==e);return!1}function Ue(e,n){return Q(e.prev,e,e.next)<0?Q(e,n,e.next)>=0&&Q(e,e.prev,n)>=0:Q(e,n,e.prev)<0||Q(e,e.next,n)<0}function Ot(e,n){let t=e,i=!1,o=(e.x+n.x)/2,r=(e.y+n.y)/2;do{let s=t.next;t.y>r!=s.y>r&&o<(s.x-t.x)*(r-t.y)/(s.y-t.y)+t.x&&(i=!i),t=s}while(t!==e);return i}function Vn(e,n){let t=hn(e.i,e.x,e.y),i=hn(n.i,n.x,n.y),o=e.next,r=n.prev;return e.next=n,n.prev=e,t.next=o,o.prev=t,i.next=t,t.prev=i,r.next=i,i.prev=r,i}function In(e,n,t,i){let o=hn(e,n,t);return i?(o.next=i.next,o.prev=i,i.next.prev=o,i.next=o):(o.prev=o,o.next=o),o}function Ce(e){e.next.prev=e.prev,e.prev.next=e.next,e.prevZ&&(e.prevZ.nextZ=e.nextZ),e.nextZ&&(e.nextZ.prevZ=e.prevZ),cn&&vt(e.prev,e.next)}function hn(e,n,t){return{i:e,x:n,y:t,prev:null,next:null,z:0,prevZ:null,nextZ:null}}function Ut(e,n,t,i){let o=0;for(let r=n,s=t-i;r<t;r+=i)o+=(e[s]-e[r])*(e[r+1]+e[s+1]),s=r;return o}var Ct=.7,Pt=Math.tan(Math.PI/6),Et=Math.tan(35*Math.PI/180),It=Math.tan(Math.PI/18),Ee=.65,Ie=.4;function Zn(e,n,t,i,o,r,s){let a=String(t.roof_shape??"");if(!a||a==="flat"||a==="sawtooth"||Vt(e,s))return;let l=Dt(e);if(!l||Math.abs(pn(e))<Ct*4*l.halfU*l.halfV)return;let u=l.u,c=l.v,f=l.halfU*r,d=l.halfV*r;f<d&&([u,c,f,d]=[c,u,d,f]);let g=Gn(t.roof_direction),m=g===void 0?void 0:[Math.sin(g*Math.PI/180),-Math.cos(g*Math.PI/180)];(m!==void 0?Math.abs(m[0]*u[0]+m[1]*u[1])>Math.abs(m[0]*c[0]+m[1]*c[1]):t.roof_orientation==="across")&&a!=="skillion"&&([u,c,f,d]=[c,u,d,f]);let h=jt(a,f,d,m&&[$n(m,u),$n(m,c)]);if(!h)return;let _=Math.max(0,o-i),F=Gn(t.roof_height),k,M;if(F!==void 0&&F>0)M=o,k=Math.max(i+Math.min(2,_/2),o-F);else{let y=Math.min(zt(a,d),_*.6,30);t.height_source==="height"?(M=o,k=o-y):(k=o,M=o+y)}let B=M-k;if(!(B>=.3))return;let[U,E]=l.centre,C=(y,b)=>{let x=(y-U)*r,T=(b-E)*r;return[x*u[0]+T*u[1],x*c[0]+T*c[1]]},I=(y,b)=>[U+(y*u[0]+b*c[0])/r,E+(y*u[1]+b*c[1])/r],N=(y,b)=>{let x=1/0;for(let[T,A,v]of h)x=Math.min(x,T*y+A*b+v);return Math.max(0,x)},K=(y,b)=>k+B*N(...C(y,b)),$=[];for(let y=0;y+1<n.length;y+=2)$.push(...C(n[y],n[y+1]));pn($)<0&&Ht($);let D=1.01,Y=[-f*D,-d*D,f*D,-d*D,f*D,d*D,-f*D,d*D],w=[];for(let[y,b]of h.entries()){let x=Y;for(let[P,Z]of h.entries()){if(P===y)continue;let j=b[0]-Z[0],G=b[1]-Z[1],W=b[2]-Z[2];if(Math.abs(j)+Math.abs(G)+Math.abs(W)<1e-9){P<y&&(x=[]);continue}if(x=Hn(x,j,G,W),x.length<6)break}if(x.length<6)continue;let T=$,A=x.length/2;for(let P=0;P<A&&T.length>=6;P+=1){let[Z,j]=[x[P*2],x[P*2+1]],[G,W]=[x[(P+1)%A*2],x[(P+1)%A*2+1]];T=Hn(T,W-j,Z-G,-(W-j)*Z-(Z-G)*j)}if(T.length<6||Math.abs(pn(T))<1e-6)continue;let v=[];for(let P=0;P<T.length;P+=2)v.push(...I(T[P],T[P+1]));let L=Pe(v);if(L.length===0)continue;let O=B*b[0],V=B*b[1],R=O*u[0]+V*c[0],S=O*u[1]+V*c[1],z=Math.hypot(R,S,1);w.push({ring:v,triangles:L,normal:[-R/z,-S/z]})}if(w.length!==0)return{eaves:k,ridge:M,faces:w,heightAt:K,breaks(y,b,x,T){let[A,v]=C(y,b),[L,O]=C(x,T),V=[];for(let R=0;R<h.length;R+=1)for(let S=R+1;S<h.length;S+=1){let z=(ae,H)=>(h[R][0]-h[S][0])*ae+(h[R][1]-h[S][1])*H+(h[R][2]-h[S][2]),P=z(A,v),Z=z(L,O);if(P===Z||P*Z>0)continue;let j=P/(P-Z);if(j<=1e-4||j>=1-1e-4)continue;let G=A+(L-A)*j,W=v+(O-v)*j;h[R][0]*G+h[R][1]*W+h[R][2]<=N(G,W)+1e-6&&V.push(j)}return[...new Set(V.map(R=>Math.round(R*1e6)/1e6))].sort((R,S)=>R-S)}}}function zt(e,n){switch(e){case"skillion":return 2*n*It;case"pyramidal":return n*Et;case"gambrel":case"mansard":return n*.8;case"dome":case"onion":case"round":return n;default:return n*Pt}}function jt(e,n,t,i){let o=n,r=t,s=[[0,-1/r,1],[0,1/r,1]],a=u=>u.flatMap(c=>[1,-1].flatMap(f=>{let d=c==="v"?r:o,g=Ee/(Ie*r)*f,m=(1-Ee)/((1-Ie)*r)*f,p=h=>c==="v"?[0,-h]:[-h,0];return[[...p(g),Ee/(Ie*r)*d],[...p(m),Ee+(1-Ee)/((1-Ie)*r)*(d-Ie*r)]]})),l=[.99,.8,.5,.2];switch(e){case"gabled":return s;case"saltbox":{let u=r/3;return[[0,-1/(r-u),1+u/(r-u)],[0,1/(r+u),1-u/(r+u)]]}case"hipped":return[...s,[-1/r,0,o/r],[1/r,0,o/r]];case"half_hipped":return[...s,[-1/r,0,.5+o/r],[1/r,0,.5+o/r]];case"pyramidal":return[...s,[-1/o,0,1],[1/o,0,1]];case"gambrel":return a(["v"]);case"mansard":return a(["v","u"]);case"skillion":{let[u,c]=i??[0,1],f=Math.abs(u)*o+Math.abs(c)*r;return f>0?[[-u/(2*f),-c/(2*f),.5]]:void 0}case"round":return[[0,0,1],...l.flatMap(u=>{let c=Math.sqrt(1-u*u);return[1,-1].map(f=>[0,-f*u/(r*c),1/c])})];case"dome":case"onion":return[[0,0,1],...l.flatMap(u=>{let c=Math.sqrt(1-u*u);return Array.from({length:12},(f,d)=>{let g=d*Math.PI/6;return[-u*Math.cos(g)/(o*c),-u*Math.sin(g)/(r*c),1/c]})})];default:return}}function Hn(e,n,t,i){let o=e.length/2,r=[];for(let s=0;s<o;s+=1){let a=e[s*2],l=e[s*2+1],u=e[(s+1)%o*2],c=e[(s+1)%o*2+1],f=n*a+t*l+i,d=n*u+t*c+i;if(f<=0&&r.push(a,l),f<0&&d>0||f>0&&d<0){let g=f/(f-d);r.push(a+(u-a)*g,l+(c-l)*g)}}return r}function Dt(e){let n=Nt(e);if(n.length<3)return;let t,i=1/0;for(let o=0;o<n.length;o+=1){let[r,s]=n[o],[a,l]=n[(o+1)%n.length],u=Math.hypot(a-r,l-s);if(u===0)continue;let c=[(a-r)/u,(l-s)/u],f=[-c[1],c[0]],[d,g,m,p]=[1/0,-1/0,1/0,-1/0];for(let[_,F]of n){let k=_*c[0]+F*c[1],M=_*f[0]+F*f[1];d=Math.min(d,k),g=Math.max(g,k),m=Math.min(m,M),p=Math.max(p,M)}let h=(g-d)*(p-m);if(h<i){i=h;let _=(d+g)/2,F=(m+p)/2;t={centre:[_*c[0]+F*f[0],_*c[1]+F*f[1]],u:c,v:f,halfU:(g-d)/2,halfV:(p-m)/2}}}return t&&t.halfU>0&&t.halfV>0?t:void 0}function Nt(e){let n=[];for(let r=0;r+1<e.length;r+=2)n.push([e[r],e[r+1]]);n.sort((r,s)=>r[0]-s[0]||r[1]-s[1]);let t=(r,s,a)=>(s[0]-r[0])*(a[1]-r[1])-(s[1]-r[1])*(a[0]-r[0]),i=[];for(let r of n){for(;i.length>=2&&t(i.at(-2),i.at(-1),r)<=0;)i.pop();i.push(r)}let o=[];for(let r of n.reverse()){for(;o.length>=2&&t(o.at(-2),o.at(-1),r)<=0;)o.pop();o.push(r)}return[...i.slice(0,-1),...o.slice(0,-1)]}function Vt(e,n){let[t,i,o,r]=[1/0,-1/0,1/0,-1/0];for(let a=0;a+1<e.length;a+=2)t=Math.min(t,e[a]),i=Math.max(i,e[a]),o=Math.min(o,e[a+1]),r=Math.max(r,e[a+1]);let s=e.length/2;for(let a=0;a<s;a+=1){let l=e[a*2],u=e[a*2+1],c=e[(a+1)%s*2],f=e[(a+1)%s*2+1];if(t<0&&l===t&&c===t||i>n&&l===i&&c===i||o<0&&u===o&&f===o||r>n&&u===r&&f===r)return!0}return!1}function pn(e){let n=0,t=e.length/2;for(let i=0;i<t;i+=1){let o=(i+1)%t;n+=e[i*2]*e[o*2+1]-e[o*2]*e[i*2+1]}return n/2}function Ht(e){let n=[];for(let t=0;t<e.length;t+=2)n.push([e[t],e[t+1]]);n.reverse(),e.splice(0,e.length,...n.flat())}function $n(e,n){return e[0]*n[0]+e[1]*n[1]}function Gn(e){let n=typeof e=="string"?Number(e):e;return typeof n=="number"&&Number.isFinite(n)?n:void 0}var jr=Object.freeze({surface:0,secondary:1,glass:2,accent:3,roof:4}),Dr=Object.freeze({unclassified:0,wall:1,door:2,roof:3,window:4,lamp:5,logo:6}),Nr=Object.freeze([1,1,4,1,3]),Vr=Object.freeze({levels:3,vertices:2e5,triangles:2e5,footprintPoints:4096,radius:2e3,height:1e3,models:512,bytes:16*1024*1024});function yn(e,n,t){for(let i of e){let o=!1;for(let r=0,s=i.length-2;r<i.length;s=r,r+=2){let a=i[r],l=i[r+1],u=i[s],c=i[s+1];l>t!=c>t&&n<(u-a)*(t-l)/(c-l)+a&&(o=!o)}if(o)return!0}return!1}function Yn(e,n,t){for(let i of n){let[o,r,s,a]=Xn(i);for(let l of e){let[u,c,f,d]=Xn(l);if(!(u>s-t||f<o+t||c>a-t||d<r+t)&&(Wn(l,i,t)||Wn(i,l,t)))return!0}}return!1}function Wn(e,n,t){let i=(o,r)=>yn([n],o,r)&&Gt(n,o,r)>t;for(let o=0;o+1<e.length;o+=2)if(i(e[o],e[o+1]))return!0;for(let o=0,r=e.length-2;o<e.length;r=o,o+=2){let[s,a,l,u]=[e[r],e[r+1],e[o],e[o+1]],c=[0,1];for(let f=0,d=n.length-2;f<n.length;d=f,f+=2){let g=$t(s,a,l,u,n[d],n[d+1],n[f],n[f+1]);g!==void 0&&c.push(g)}if(c.length!==2){c.sort((f,d)=>f-d);for(let f=1;f<c.length;f+=1){let d=(c[f-1]+c[f])/2;if(i(s+(l-s)*d,a+(u-a)*d))return!0}}}return!1}function $t(e,n,t,i,o,r,s,a){let l=t-e,u=i-n,c=s-o,f=a-r,d=l*f-u*c;if(d===0)return;let g=((o-e)*f-(r-n)*c)/d,m=((o-e)*u-(r-n)*l)/d;return g>0&&g<1&&m>=0&&m<=1?g:void 0}function Gt(e,n,t){let i=1/0;for(let o=0,r=e.length-2;o<e.length;r=o,o+=2){let[s,a,l,u]=[e[r],e[r+1],e[o],e[o+1]],c=(l-s)**2+(u-a)**2,f=c>0?Math.max(0,Math.min(1,((n-s)*(l-s)+(t-a)*(u-a))/c)):0;i=Math.min(i,Math.hypot(n-(s+(l-s)*f),t-(a+(u-a)*f)))}return i}function Xn(e){let[n,t,i,o]=[1/0,1/0,-1/0,-1/0];for(let r=0;r+1<e.length;r+=2)n=Math.min(n,e[r]),i=Math.max(i,e[r]),t=Math.min(t,e[r+1]),o=Math.max(o,e[r+1]);return[n,t,i,o]}var ue=8192,pe=28,Zt={commercial:1,active:2,destination:3},Wt={residential:1,...Object.fromEntries(["civic","commercial","education","entertainment","medical","transportation"].map(e=>[e,2])),...Object.fromEntries(["agricultural","industrial","military","outbuilding","religious","service"].map(e=>[e,3]))},Xt={dining:1,entertainment:2,nightlife:3},bn={...Object.fromEntries(["alcoholic_beverage_venue","bar","beer","biergarten","brewery","casino","cocktail_bar","dance_club","karaoke","lounge","music_venue","night_club","nightclub","pub","wine_bar"].map(e=>[e,3])),...Object.fromEntries(["arts_centre","bowling_alley","cinema","comedy_club","concert_hall","movie_theater","opera","performing_arts_venue","theater","theatre","theatre_venue"].map(e=>[e,2])),...Object.fromEntries(["casual_eatery","fast_food","fast_food_restaurant","food_court","restaurant"].map(e=>[e,1]))},Yt=6,Jt=.5,Kt=.5;function Kn(e,n){let t=ue/e.extent,i=n.tileMetres/ue,o=n.defaultHeight??5,r=Number.isFinite(n.edgeRadius)?Math.max(0,Math.min(1,n.edgeRadius))/i:0,s=new wn,a=new Qe,l=new Qe,u=[],c=[],f=0,d=nr(e,n);for(let[M,B]of e.features.entries()){if(B.type!=="Polygon"||u.length>=65535)continue;let U=B.properties,E=U.hide_3d;if(E===!0||E===1||E==="1"||E==="true")continue;let C=Math.min(6e3,Jn(U.render_height)??o),I=Math.min(C,Jn(U.render_min_height)??0),N=Zt[String(U.building_tone??"")]??0,K=Wt[String(U.class??"")]??0,$=d.get(M)??0,D=u.length,Y=!1;for(let w of tr(B.geometry,t)){let y=w.map(or).filter(S=>S.length>=6);if(y.length===0||qe(y[0])===0)continue;let[b,x]=rr(y[0]);if(n.masks?.length&&(yn(n.masks,b,x)||Yn(y,n.masks,Kt/i)))continue;let T={cell:Math.min(7,Math.max(0,Math.floor(x/1024)))*8+Math.min(7,Math.max(0,Math.floor(b/1024))),bounds:[1/0,1/0,-1/0,-1/0,C+.1],roofsFrom:a.length,roofsCount:0,wallsFrom:l.length,wallsCount:0};for(let S of y)for(let z=0;z<S.length;z+=2)T.bounds[0]=Math.min(T.bounds[0],S[z]-1),T.bounds[1]=Math.min(T.bounds[1],S[z+1]-1),T.bounds[2]=Math.max(T.bounds[2],S[z]+1),T.bounds[3]=Math.max(T.bounds[3],S[z+1]+1);Y=!0,f=Math.max(f,C);let A=Number.isSafeInteger(B.id),v=gn(A?B.id*.0731:b*.0731+x*.19137+D*1.618),L=!A&&y[0].some(S=>S<=0||S>=ue)?gn(C*7.31+I*3.17+N):v,O={base:I,top:C,jitter:L,seed:v,tone:N,group:K,use:$,cx:b,cy:x,index:D},V=y.map((S,z)=>er(S,z,r,n.cornerAngle));y=V.map(({ring:S})=>S);let R=w.length===1&&y.length===1?Zn(w[0],y[0],U,I,C,i,ue):void 0;R?(f=Math.max(f,R.ridge),T.bounds[4]=Math.max(T.bounds[4],R.ridge+.1),qt(R,O,s,a)):Qt(y,O,s,a);for(let[S,z]of y.entries()){let P=qe(z)>0,Z=S===0?P?-1:1:P?1:-1,j=z.length/2,G=H=>{let J=(H%j+j)%j;return[z[J*2],z[J*2+1]]},W=H=>{let[J,re]=G(H-1),[ne,te]=G(H),[le,de]=G(H+1);if(we(J,re,ne,te)||we(ne,te,le,de))return!1;let me=Math.hypot(ne-J,te-re),ce=Math.hypot(le-ne,de-te);if(!me||!ce)return!1;let je=-(te-re)/me*Z,De=(ne-J)/me*Z;return(je*(le-ne)+De*(de-te))/ce>Jt},se=(H,J)=>R?R.heightAt(H,J):C,ae=0;for(let H=0;H<j;H+=1){let[J,re]=G(H),[ne,te]=G(H+1),le=Math.hypot(ne-J,te-re);if(le===0||we(J,re,ne,te))continue;let de=-(te-re)/le*Z,me=(ne-J)/le*Z,ce=V[S].normals[H]??[de,me],je=V[S].normals[(H+1)%j]??[de,me],De=oe=>{let _e=ce[0]+(je[0]-ce[0])*oe,Fe=ce[1]+(je[1]-ce[1])*oe,ye=Math.hypot(_e,Fe)||1;return[_e/ye,Fe/ye]},he=[0,...R?R.breaks(J,re,ne,te):[],1];for(let oe=0;oe+1<he.length;oe+=1){let _e=oe===0,Fe=oe+2===he.length,ye=J+(ne-J)*he[oe],Ne=re+(te-re)*he[oe],Ve=J+(ne-J)*he[oe+1],He=re+(te-re)*he[oe+1],Ae=Math.hypot(Ve-ye,He-Ne)/ue*n.tileMetres,$e=(_e&&W(H)?1:0)|(Fe&&W(H+1)?2:0)|(S>0?4:0),Ge=(_e&&xn(J,re)?1:0)|(Fe&&xn(ne,te)?2:0),an=ae+Ae,Ze=De(he[oe]),We=De(he[oe+1]),Un=se(ye,Ne),Cn=se(Ve,He),ke=s.write(O,ye,Ne,0,Ze[0],Ze[1],1,ae,$e,Ae,0,Ge,Un);s.write(O,Ve,He,0,We[0],We[1],1,an,$e,Ae,1,Ge,Cn),s.write(O,ye,Ne,1,Ze[0],Ze[1],1,ae,$e,Ae,0,Ge,Un),s.write(O,Ve,He,1,We[0],We[1],1,an,$e,Ae,1,Ge,Cn),l.push(ke,ke+1,ke+2,ke+1,ke+3,ke+2),ae=an}}}T.roofsCount=a.length-T.roofsFrom,T.wallsCount=l.length-T.wallsFrom,c.push(T)}Y&&u.push(U)}if(s.count===0)return;let g=new Uint32Array(a.length+l.length),m=[],p=0,h=a.length,_=a.values(),F=l.values();c.sort((M,B)=>M.cell-B.cell);let k=-1;for(let M of c){M.cell!==k&&(k=M.cell,m.push({bounds:[...M.bounds],roofsFrom:p,roofsCount:0,wallsFrom:h,wallsCount:0}));let B=m.at(-1);for(let U=0;U<5;U+=1)B.bounds[U]=U<2?Math.min(B.bounds[U],M.bounds[U]):Math.max(B.bounds[U],M.bounds[U]);g.set(_.subarray(M.roofsFrom,M.roofsFrom+M.roofsCount),p),g.set(F.subarray(M.wallsFrom,M.wallsFrom+M.wallsCount),h),p+=M.roofsCount,h+=M.wallsCount,B.roofsCount+=M.roofsCount,B.wallsCount+=M.wallsCount}return{groups:m,vertices:s.bytes(),indices:g,wallsFrom:a.length,top:f,features:u}}function Qt(e,n,t,i){let o=[],r=[];for(let l of e)r.push(o.length/2),o.push(...l);r.push(o.length/2);let s=(l,u)=>{let c=r.findIndex((p,h)=>l>=p&&l<r[h+1]),[f,d]=[r[c],r[c+1]-1];if(u<f||u>d)return!1;let[g,m]=l<u?[l,u]:[u,l];return m-g!==1&&!(g===f&&m===d)?!1:!we(o[l*2],o[l*2+1],o[u*2],o[u*2+1])},a=Pe(o,r.slice(1,-1),2);for(let l=0;l+2<a.length;l+=3){let u=[a[l],a[l+1],a[l+2]],c=0;for(let f=0;f<3;f+=1)s(u[(f+1)%3],u[(f+2)%3])&&(c|=1<<f);for(let[f,d]of u.entries())i.push(t.write(n,o[d*2],o[d*2+1],1,0,0,0,0,0,0,f,c))}}function qt(e,n,t,i){for(let o of e.faces){let r=o.ring,s=r.length/2,a=(l,u)=>{let[c,f]=l<u?[l,u]:[u,l];return f-c!==1&&!(c===0&&f===s-1)?!1:!we(r[l*2],r[l*2+1],r[u*2],r[u*2+1])};for(let l=0;l+2<o.triangles.length;l+=3){let u=[o.triangles[l],o.triangles[l+1],o.triangles[l+2]],c=0;for(let f=0;f<3;f+=1)a(u[(f+1)%3],u[(f+2)%3])&&(c|=1<<f);for(let[f,d]of u.entries()){let g=r[d*2],m=r[d*2+1];i.push(t.write(n,g,m,1,o.normal[0],o.normal[1],0,0,0,0,f,c,e.heightAt(g,m)))}}}}function er(e,n,t,i=Math.PI/6){if(t<1)return{ring:e,normals:[]};let o=e.length/2,r=qe(e)>0,s=n===0?r?-1:1:r?1:-1,a=[],l=[],u=(c,f,d)=>{c=Re(c),f=Re(f),!(a.at(-2)===c&&a.at(-1)===f)&&(a.push(c,f),l.push(d))};for(let c=0;c<o;c+=1){let f=(c+o-1)%o,d=(c+1)%o,[g,m]=[e[f*2],e[f*2+1]],[p,h]=[e[c*2],e[c*2+1]],[_,F]=[e[d*2],e[d*2+1]],k=Math.hypot(p-g,h-m),M=Math.hypot(_-p,F-h);if(!k||!M||xn(p,h)||we(g,m,p,h)||we(p,h,_,F)){u(p,h);continue}let[B,U]=[(p-g)/k,(h-m)/k],[E,C]=[(_-p)/M,(F-h)/M],I=Math.atan2(B*C-U*E,B*E+U*C);if(I*s>=-.08||Math.abs(I)>Math.PI*.85){u(p,h);continue}let N=Math.tan(Math.abs(I)/2),K=Math.min(t*N,k*.2,M*.2),$=K/N;if($<1){u(p,h);continue}let[D,Y]=[-U*s,B*s],[w,y]=[p-B*K-D*$,h-U*K-Y*$],b=Math.atan2(Y,D),x=Math.max(i<=Math.PI/6?2:1,Math.ceil(Math.abs(I)/Math.max(Math.PI/6,Math.min(Math.PI/3,i))));for(let T=0;T<=x;T+=1){let A=b+I*T/x,v=[Math.cos(A),Math.sin(A)];u(w+v[0]*$,y+v[1]*$,v)}}return a[0]===a.at(-2)&&a[1]===a.at(-1)&&(a.splice(-2),l.pop()),a.length>=6?{ring:a,normals:l}:{ring:e,normals:[]}}var wn=class{#e=new ArrayBuffer(4096*pe);#n=new DataView(this.#e);count=0;write(n,t,i,o,r,s,a,l,u,c,f=0,d=0,g=n.top){let m=pe;if((this.count+1)*m>this.#e.byteLength){let _=new ArrayBuffer(this.#e.byteLength*2);new Uint8Array(_).set(new Uint8Array(this.#e)),this.#e=_,this.#n=new DataView(_)}let p=this.#n,h=this.count*m;return p.setUint16(h,Re(t),!0),p.setUint16(h+2,Re(i),!0),p.setUint16(h+4,Math.min(65535,Math.round(n.base*10)),!0),p.setUint16(h+6,Math.min(65535,Math.max(0,Math.round(g*10))),!0),p.setInt8(h+8,Math.round(r*127)),p.setInt8(h+9,Math.round(s*127)),p.setUint8(h+10,o),p.setUint8(h+11,a),p.setUint16(h+12,Math.round(l*10)%65536,!0),p.setUint8(h+14,Math.round(n.jitter*255)),p.setUint8(h+15,Math.round(n.seed*255)),p.setUint16(h+16,Re(n.cx),!0),p.setUint16(h+18,Re(n.cy),!0),p.setUint8(h+20,n.tone+4*n.group),p.setUint8(h+21,n.use),p.setUint8(h+22,u),p.setUint8(h+23,Math.min(255,Math.round(c))),p.setUint16(h+24,n.index,!0),p.setUint8(h+26,f),p.setUint8(h+27,d),this.count+=1,this.count-1}bytes(){return new Uint8Array(this.#e.slice(0,this.count*pe))}},Qe=class{#e=new Uint32Array(8192);length=0;push(...n){if(this.length+n.length>this.#e.length){let t=new Uint32Array(Math.max(this.length+n.length,this.#e.length*2));t.set(this.#e),this.#e=t}for(let t of n)this.#e[this.length++]=t}values(){return this.#e.subarray(0,this.length)}};function nr(e,n){let t=new Map;if(e.features.some(a=>a.properties.night_use!==void 0)){for(let[a,l]of e.features.entries()){let u=Xt[String(l.properties.night_use??"")];u&&t.set(a,u)}return t}let i=n.places;if(!i||i.features.length===0)return t;let o=Yt/n.tileMetres*e.extent,r=[];for(let[a,l]of e.features.entries()){if(l.type!=="Polygon")continue;let u=l.properties.hide_3d;if(u===!0||u===1||u==="1"||u==="true")continue;let c=[1/0,1/0,-1/0,-1/0];for(let f of l.geometry)for(let d=0;d+1<f.length;d+=2)c[0]=Math.min(c[0],f[d]),c[1]=Math.min(c[1],f[d+1]),c[2]=Math.max(c[2],f[d]),c[3]=Math.max(c[3],f[d+1]);r.push({index:a,rings:l.geometry,box:c})}let s=e.extent/i.extent;for(let a of i.features){if(a.type!=="Point")continue;let l=a.properties,u=bn[String(l.type??"")]??bn[String(l.subclass??"")]??bn[String(l.class??"")];if(u)for(let c of a.geometry)for(let f=0;f+1<c.length;f+=2){let d=c[f]*s,g=c[f+1]*s,m,p,h=o;for(let F of r){let[k,M,B,U]=F.box;if(d<k-o||d>B+o||g<M-o||g>U+o)continue;let E=!1;for(let C of F.rings)for(let I=0,N=C.length-2;I+1<C.length;N=I,I+=2){let K=C[N],$=C[N+1],D=C[I],Y=C[I+1];Y>g!=$>g&&d<(K-D)*(g-Y)/($-Y)+D&&(E=!E);let w=D-K,y=Y-$,b=w*w+y*y,x=b?Math.min(1,Math.max(0,((d-K)*w+(g-$)*y)/b)):0,T=Math.hypot(d-K-x*w,g-$-x*y);T<h&&(h=T,p=F.index)}if(E){m=F.index;break}}let _=m??p;_!==void 0&&t.set(_,Math.max(t.get(_)??0,u))}}return t}function Re(e){return Math.min(ue,Math.max(0,Math.round(e)))}function Jn(e){let n=Number(e);return Number.isFinite(n)&&n>0?n:void 0}function tr(e,n){let t=[],i;for(let o of e){let r=[];for(let a=0;a+1<o.length;a+=2){let l=o[a]*n,u=o[a+1]*n;r.length&&l===r.at(-2)&&u===r.at(-1)||r.push(l,u)}if(r.length>=6&&r[0]===r.at(-2)&&r[1]===r.at(-1)&&(r.length-=2),r.length<6)continue;let s=Math.sign(qe(r));s&&(i??=s,s===i||t.length===0?t.push([r]):t.at(-1).push(r))}return t}function qe(e){let n=0,t=e.length/2;for(let i=0;i<t;i+=1){let o=(i+1)%t;n+=e[i*2]*e[o*2+1]-e[o*2]*e[i*2+1]}return n}function rr(e){let n=0,t=0,i=e.length/2;for(let o=0;o<i;o+=1)n+=e[o*2],t+=e[o*2+1];return[n/i,t/i]}function xn(e,n){return e<=0||n<=0||e>=ue||n>=ue}function we(e,n,t,i){let o=ue;return e<=0&&t<=0||e>=o&&t>=o||n<=0&&i<=0||n>=o&&i>=o}function or(e){let n=ue,t=[...e],i=[[0,0,o=>o>=0],[0,n,o=>o<=n],[1,0,o=>o>=0],[1,n,o=>o<=n]];for(let[o,r,s]of i){let a=[],l=t.length/2;for(let u=0;u<l;u+=1){let c=[t[u*2],t[u*2+1]],f=[t[(u+1)%l*2],t[(u+1)%l*2+1]],d=s(c[o]),g=s(f[o]);if(d&&a.push(c[0],c[1]),d!==g){let m=(r-c[o])/(f[o]-c[o]);a.push(c[0]+(f[0]-c[0])*m,c[1]+(f[1]-c[1])*m)}}if(t=a,t.length<6)return[]}return t}function gn(e){let n=Math.sin(e*12.9898+78.233)*43758.5453;return n-Math.floor(n)}var Qn=`\nin float v_haze_depth;\nuniform vec3 u_haze_colour;\nuniform vec3 u_haze; // strength; the view depths where the haze starts and is complete\n\nfloat hazeOf() {\n return u_haze.x > 0.0 ? u_haze.x * smoothstep(u_haze.y, u_haze.z, v_haze_depth) : 0.0;\n}\n\nvec3 hazed(vec3 colour) {\n return mix(colour, u_haze_colour, hazeOf());\n}`;function qn(e){let n=(e.indices.length-e.wallsFrom)/6,t=new Uint8Array(n*16);for(let i=0;i<n;i+=1){let o=e.wallsFrom+i*6,r=e.indices[o]*pe,s=e.indices[o+1]*pe;t.set(e.vertices.subarray(r,r+4),i*16),t.set(e.vertices.subarray(s,s+4),i*16+4),t.set(e.vertices.subarray(r+4,r+8),i*16+8),t[i*16+12]=e.vertices[r+14],t[i*16+13]=e.vertices[r+27]}return t}var Kr=`#version 300 es\nprecision highp float;\nuniform highp sampler2D u_contact;\n${Qn}\nout vec4 fragColor;\nvoid main() {\n float shade = mix(texelFetch(u_contact, ivec2(gl_FragCoord.xy), 0).r, 1.0, hazeOf());\n fragColor = vec4(vec3(shade), 1.0);\n}`;function et(e){let n=e.vertices.length/pe;return{mesh:{...e.groups?{groups:e.groups}:{},wallsFrom:e.wallsFrom,top:e.top,features:e.features,vertexCount:n,indexCount:e.indices.length},data:{vertices:e.vertices,indices:n<=65536?Uint16Array.from(e.indices):e.indices,contact:qn(e)}}}function nt({data:e}){return[e.vertices.buffer,e.indices.buffer,e.contact.buffer]}function Tn(e){let n=ir(e);return n?[Math.min(1,Math.max(0,n[0]/255)),Math.min(1,Math.max(0,n[1]/255)),Math.min(1,Math.max(0,n[2]/255)),Math.min(1,Math.max(0,n[3]))]:null}function ir(e){let n=e.trim().toLowerCase(),t=/^#([\\da-f]{3,8})$/u.exec(n)?.[1];if(t&&[3,4,6,8].includes(t.length)){let _=(t.length<=4?[...t].map(F=>F+F).join(""):t).match(/../gu).map(F=>Number.parseInt(F,16));return[_[0],_[1],_[2],_.length>3?_[3]/255:1]}let i=/^(rgba?|hsla?)\\(([^)]+)\\)$/u.exec(n);if(!i)return null;let o=i[2].split(/[\\s,/]+/u).filter(Boolean);if(o.length<3||o.length>4)return null;let r=o[3]===void 0?1:en(o[3],1);if(i[1].startsWith("rgb")){let[h,_,F]=o.slice(0,3).map(k=>en(k,255));return[h,_,F,r].some(k=>k===null)?null:[h,_,F,r]}let s=Number.parseFloat(o[0]),a=en(o[1],1),l=en(o[2],1);if(!Number.isFinite(s)||a===null||l===null||r===null)return null;let u=(1-Math.abs(2*l-1))*a,c=(s%360+360)%360/60,f=u*(1-Math.abs(c%2-1)),[d,g,m]=c<1?[u,f,0]:c<2?[f,u,0]:c<3?[0,u,f]:c<4?[0,f,u]:c<5?[f,0,u]:[u,0,f],p=l-u/2;return[(d+p)*255,(g+p)*255,(m+p)*255,r]}function en(e,n){let t=e.endsWith("%"),i=Number.parseFloat(e);return Number.isFinite(i)?t?i/100*n:i:null}var fe=8192,Mn=12,sr={primary:{spacing:30,kerb:10},secondary:{spacing:32,kerb:8.5},tertiary:{spacing:34,kerb:7},minor:{spacing:36,kerb:5.5},pedestrian:{spacing:26,kerb:3}},ar={motorway:{spacing:45,kerb:14},trunk:{spacing:40,kerb:12},service:{spacing:38,kerb:4},path:{spacing:28,kerb:1.5},track:{spacing:40,kerb:2.5}},lr={spacing:30,kerb:0},ur=12,cr=18,fr=9,dr={sodium:"#ffa64d",high_pressure_sodium:"#ffa64d",low_pressure_sodium:"#ff9326",led:"#fff1db",mercury:"#e3ecff",metal_halide:"#f4f4ff",fluorescent:"#eef9ff",electric:"#ffd59a",incandescent:"#ffd59a",halogen:"#ffe3b0",gas:"#ffd28a",gaslight:"#ffd28a"},mr={orange:"#ffa64d",yellow:"#ffd27a",warm_white:"#ffe2b8",white:"#fff4e6",cool_white:"#eef4ff",neutral_white:"#fff8f0",blue:"#b8d0ff",green:"#c4ffd0",red:"#ff9a8a"},hr=new Set(["wall","wall_mounted","wall_bracket"]),pr=new Set(["suspended","cable","catenary","wire"]);function it(e,n){let t=n.estimate??"lit",i=new vn,o=new nn(cr),r=new nn(fr),s=e.streetFurniture;if(s){let m=fe/s.extent;for(let p of s.features){let h=p.properties;if(p.type!=="Point"||h.subclass!=="street_lamp")continue;let _=yr(h),F=br(h),k=Math.max(1,Math.min(4,Number(h.light_count)||1)),M=Math.min(24,Math.max(5,_*1.7*(k>1?1.15:1)));for(let B of p.geometry)for(let U=0;U+1<B.length;U+=2){let E=B[U]*m,C=B[U+1]*m;if(!rt(E,C))continue;i.write(E,C,_,M,!0,F);let I=ot(E,C,n.tileMetres);o.add(...I),r.add(...I)}}}let a=i.count;if(t==="none")return i.done(a);let l=e.transportation,u=0;if(l){let m=n.tileMetres/l.extent;for(let p of l.features)if(!(p.type!=="LineString"||!tt(p.properties,"streets")))for(let h of p.geometry)u+=gr(h,l.extent)*m}let c=u>0&&a/(u/1e3)>=ur,f=t==="streets"&&!c?"streets":"lit",d=(m,p,h,_)=>{let F=fe/m.extent,k=[];for(let N=0;N+1<p.length;N+=2)k.push(p[N]*F,p[N+1]*F);let M=n.tileMetres/fe,B=h.kerb*.45/M,U=Rn(k[0]*.013+k[1]*.029+_)*h.spacing,E=0,C=U,I=Rn(k[0]+k[1]*3.1)<.5?1:-1;for(let N=2;N<k.length;N+=2){let K=k[N-2],$=k[N-1],D=k[N],Y=k[N+1],w=Math.hypot(D-K,Y-$)*M;if(w!==0){for(;C<=E+w;){let y=(C-E)/w,b=-(Y-$)/(w/M)*I,x=(D-K)/(w/M)*I,T=K+(D-K)*y+b*B,A=$+(Y-$)*y+x*B;if(C+=h.kerb>0?h.spacing/2:h.spacing,h.kerb>0&&(I=-I),!rt(T,A))continue;let v=ot(T,A,n.tileMetres);o.near(...v)||r.near(...v)||(r.add(...v),i.write(T,A,7,15,!1))}E+=w}}};if(l)for(let m of l.features){if(m.type!=="LineString")continue;let p=tt(m.properties,f);if(p)for(let h of m.geometry)d(l,h,p,1)}let g=e.sidewalks;if(g){for(let m of g.features)if(!(m.type==="Point"||!kn(m.properties.lit)))for(let p of m.geometry)d(g,p,lr,2)}return i.done(a)}function tt(e,n){if(e.brunnel==="tunnel"||e.covered===!0)return;let t=e.lit;if(t===!1||t==="no")return;let i=String(e.class??""),o=String(e.subclass??""),r=i==="path"&&(o==="pedestrian"||o==="living_street")?"pedestrian":i,s=sr[r];if(s&&(n==="streets"||kn(t)))return s;let a=ar[r];if(a&&kn(t))return a}function kn(e){return e===!0||e==="yes"||e===1||e==="1"||e==="true"}function yr(e){let n=Number(e.height);if(Number.isFinite(n)&&n>=.5&&n<=40)return n;let t=String(e.lamp_mount??"").toLowerCase();return hr.has(t)?4.5:pr.has(t)?7.5:7}function br(e){let n=e.light_colour??e["light:colour"];if(typeof n=="string"&&n){let r=n.toLowerCase().replaceAll(" ","_"),s=Tn(mr[r]??n);if(s)return[s[0],s[1],s[2]]}let t=String(e.lamp_type??"").toLowerCase().replaceAll("-","_").replaceAll(" ","_"),i=dr[t];if(!i)return;let o=Tn(i);return[o[0],o[1],o[2]]}function rt(e,n){return e>=0&&n>=0&&e<fe&&n<fe}function ot(e,n,t){return[e/fe*t,n/fe*t]}function gr(e,n){let t=0;for(let i=2;i+1<e.length;i+=2){let o=(e[i-2]+e[i])/2,r=(e[i-1]+e[i+1])/2;o<0||r<0||o>=n||r>=n||(t+=Math.hypot(e[i]-e[i-2],e[i+1]-e[i-1]))}return t}var nn=class{constructor(n){this.size=n}size;#e=new Map;add(n,t){let i=`${Math.floor(n/this.size)}/${Math.floor(t/this.size)}`,o=this.#e.get(i);o?o.push([n,t]):this.#e.set(i,[[n,t]])}near(n,t){let i=Math.floor(n/this.size),o=Math.floor(t/this.size);for(let r=-1;r<=1;r+=1)for(let s=-1;s<=1;s+=1)for(let[a,l]of this.#e.get(`${i+r}/${o+s}`)??[])if(Math.hypot(a-n,l-t)<this.size)return!0;return!1}},vn=class{#e=new ArrayBuffer(256*Mn);#n=new DataView(this.#e);count=0;write(n,t,i,o,r,s){let a=Mn;if((this.count+1)*a>this.#e.byteLength){let c=new ArrayBuffer(this.#e.byteLength*2);new Uint8Array(c).set(new Uint8Array(this.#e)),this.#e=c,this.#n=new DataView(c)}let l=this.#n,u=this.count*a;l.setUint16(u,Math.min(fe,Math.max(0,Math.round(n))),!0),l.setUint16(u+2,Math.min(fe,Math.max(0,Math.round(t))),!0),l.setUint16(u+4,Math.min(65535,Math.round(i*10)),!0),l.setUint8(u+6,Math.min(255,Math.round(o))),l.setUint8(u+7,(r?1:0)|(s?2:0)),l.setUint8(u+8,Math.round((s?.[0]??0)*255)),l.setUint8(u+9,Math.round((s?.[1]??0)*255)),l.setUint8(u+10,Math.round((s?.[2]??0)*255)),l.setUint8(u+11,Math.round(Rn(n*.0731+t*.19137)*255)),this.count+=1}done(n){if(this.count!==0)return{lamps:new Uint8Array(this.#e.slice(0,this.count*Mn)),mapped:n,estimated:this.count-n}}};function Rn(e){let n=Math.sin(e*12.9898+78.233)*43758.5453;return n-Math.floor(n)}var oo=Object.freeze({source:"tileflow",layers:Object.freeze({streetFurniture:"street_furniture",transportation:"transportation",sidewalk:"sidewalk"}),estimate:"lit",color:"#ffcf8f",intensity:1});var Me=["round","open","tall","conifer","columnar","palm"];var ut=Object.freeze({height:"height",diameterCrown:"diameter_crown",circumference:"circumference",genus:"genus",species:"species",leafType:"leaf_type",taxon:"taxon",canopyRank:"rank",canopyClearance:"clearance_px_z15",canopyCover:"cover_pct",canopyHeight:"height_m",subclass:"subclass",hedge:"hedge"}),Sn=Object.freeze({round:1,open:1,tall:1}),tn=16,q=8192,rn=16,st={round:{height:[6,12],crown:[.66,.9]},open:{height:[5,10],crown:[.8,1.05]},tall:{height:[9,17],crown:[.48,.68]},conifer:{height:[7,16],crown:[.46,.66]},columnar:{height:[9,18],crown:[.22,.36]},palm:{height:[12,20],crown:[.42,.55]}};var on=[2,45],_n=[1,25],wr=1.2,xr=1.5,Tr=1.3,Mr=1,kr=[.3,10],vr=new Set(["acoelorrhaphe","adonidia","archontophoenix","areca","arecastrum","bismarckia","brahea","butia","caryota","chamaedorea","chamaerops","coccothrinax","cocos","dypsis","elaeis","howea","jubaea","licuala","livistona","phoenix","pritchardia","ptychosperma","rhapis","roystonea","sabal","serenoa","syagrus","thrinax","trachycarpus","veitchia","washingtonia","wodyetia"]),Rr=new Set(["cupressus","calocedrus","thuja"]),_r=new Set(["abies","araucaria","cedrus","cryptomeria","juniperus","larix","metasequoia","picea","pinus","pseudotsuga","sequoia","sequoiadendron","taxodium","taxus","tsuga"]),at=Object.freeze({...Object.fromEntries(["acacia","albizia","arbutus","bursera","ceratonia","delonix","ficus","gleditsia","jacaranda","olea","quercus","robinia","schinus","sophora","styphnolobium","tamarix"].map(e=>[e,"open"])),...Object.fromEntries(["betula","celtis","fraxinus","ginkgo","liquidambar","liriodendron","magnolia","platanus","populus","pyrus","ulmus","zelkova"].map(e=>[e,"tall"])),...Object.fromEntries(["acer","aesculus","carpinus","castanea","catalpa","cercis","citrus","fagus","lagerstroemia","malus","melia","morus","prunus","sorbus","tilia"].map(e=>[e,"round"]))});function lt(e,n={}){let t={...ut,...n},i=String(e[t.leafType]??"").toLowerCase(),o=String(e[t.taxon]??"").toLowerCase(),r=Fn(e[t.genus])??Fn(e[t.species])??(o.endsWith("aceae")?void 0:Fn(e[t.taxon]));if(i.includes("palm")||o.includes("arecaceae")||r&&vr.has(r))return"palm";if(o.includes("cupressaceae")&&!r||o.includes("pinaceae"))return"conifer";if(r&&Rr.has(r))return"columnar";if(i.includes("needle")||r&&_r.has(r))return"conifer";if(r&&at[r])return at[r];if(i.includes("broad"))return"broadleaf"}function Fn(e){return typeof e!="string"?void 0:e.trim().split(/\\s+/u)[0]?.toLowerCase()||void 0}function ct(e,n){let t={...ut,...n.fields},i=n.unknownForms??Sn,o=n.regions??[],{tile:r,tileMetres:s}=n,a=s/2**(15-r.z)/512,l=[],u=0,c=0,f=(w,y)=>{if(o.length===0)return i;let[b,x]=Ar(r,w/q,y/q);for(let T of o){let[A,v,L,O]=T.bounds;if(x>=v&&x<=O&&(A<=L?b>=A&&b<=L:b>=A||b<=L))return T.unknownForms}return i},d=(w,y,b,x)=>{let T=st[w],A=An(T.crown,ee(y,2)),v=b,L=x;return v===void 0&&L===void 0&&(v=An(T.height,ee(y,1))),v===void 0&&(v=L/A),L===void 0&&(L=v*A),{height:Te(v,on),crown:Te(L,_n)}},g=(w,y,b,x,T,A)=>{let v=ze(r.x*q+w,r.y*q+y,7),L=b===void 0?sn(f(w,y),ee(v,3)):b==="broadleaf"?sn(Fr(f(w,y)),ee(v,3)):b,O=x===void 0&&T===void 0&&A!==void 0?d(L,v,An(st[L].height,Te(A/3,[0,1]))):d(L,v,x,T);l.push({x:w,y,...O,turn:ee(v,4),shade:ee(v,5),form:Me.indexOf(L),rank:Math.floor(ee(v,6)*rn),seed:ee(v,7),canopy:0}),u+=1},m=e.trees;if(m){let w=q/m.extent;for(let y of m.features){if(y.type!=="Point")continue;let b=y.properties,x=lt(b,t),T=xe(b[t.height],on),A=xe(b[t.diameterCrown],_n),v=xe(b[t.circumference],[.1,12]);for(let L of y.geometry)for(let O=0;O+1<L.length;O+=2){let V=L[O],R=L[O+1];V<0||R<0||V>=m.extent||R>=m.extent||g(V*w,R*w,x,T,A,v)}}}let p=e.trees;if(p){let w=q/p.extent,y=(n.rowSpacing??8)/(s/p.extent);for(let b of p.features){if(b.type!=="LineString")continue;let x=b.properties,T=lt(x,t),A=xe(x[t.height],on),v=xe(x[t.diameterCrown],_n);for(let L of b.geometry){let O=y/2,V=0;for(let R=0;R+3<L.length;R+=2){let[S,z,P,Z]=[L[R],L[R+1],L[R+2],L[R+3]],j=Math.hypot(P-S,Z-z);for(;O<=V+j;){let G=j>0?(O-V)/j:0,W=S+(P-S)*G,se=z+(Z-z)*G;W>=0&&se>=0&&W<p.extent&&se<p.extent&&g(W*w,se*w,T,A,v,void 0),O+=y}V+=j}}}}let h=e.canopy;if(h){let w=q/h.extent;for(let y of h.features){if(y.type!=="Point")continue;let b=y.properties,x=Te(Math.floor(Number(b[t.canopyRank]??8)),[0,rn-1]),T=Math.max(4,Number(b[t.canopyClearance]??8))*a,A=Number(b[t.canopyCover]??30),v=A>=60?3:A>=30?2:1;for(let L of y.geometry)for(let O=0;O+1<L.length;O+=2){let V=L[O],R=L[O+1];if(V<0||R<0||V>=h.extent||R>=h.extent)continue;let S=V*w,z=R*w,P=ze(r.x*q+S,r.y*q+z,11),Z=f(S,z),j=xe(b[t.canopyHeight],on),G=Te(Math.min(T*(v===1?1.3:.95),11)*(.85+ee(P,1)*.25),[3,12]),W=Math.max(0,Math.min(G*.5,T-G/2)),se=ee(P,2)*Math.PI*2;for(let ae=0;ae<v;ae+=1){let H=ze(P,ae,13),J=se+ae*Math.PI*2/v,re=v===1?W*.3*ee(H,1):W,ne=S+Math.cos(J)*re/(s/q),te=z+Math.sin(J)*re/(s/q);if(ne<0||te<0||ne>=q||te>=q)continue;let le=sn(Z,ee(H,3)),de=G*(.85+ee(H,2)*.3),me=j===void 0?void 0:j*(.85+ee(H,6)*.25),ce=d(le,H,me,le==="palm"?void 0:de);l.push({x:ne,y:te,...ce,turn:ee(H,4),shade:ee(H,5),form:Me.indexOf(le),rank:x,seed:ee(H,7),canopy:1}),c+=1}}}}let _=[],F=e.hedges;if(F){let w=q/F.extent,y=wr/(s/F.extent);for(let b of F.features){if(b.type==="Point"||b.properties[t.subclass]!=="hedge")continue;let x=b.properties[t.hedge]==="hedge_bank"?Mr:0,T=(xe(b.properties[t.height],kr)??Tr)+x;for(let A of b.geometry){let v=y/2,L=0;for(let O=0;O+3<A.length;O+=2){let[V,R,S,z]=[A[O],A[O+1],A[O+2],A[O+3]],P=Math.hypot(S-V,z-R),Z=(Math.atan2(R-z,S-V)/(Math.PI*2)+1)%1;for(;v<=L+P;){let j=P>0?(v-L)/P:0,G=V+(S-V)*j,W=R+(z-R)*j;if(G>=0&&W>=0&&G<F.extent&&W<F.extent){let se=ze(r.x*q+G*w,r.y*q+W*w,17);_.push({x:G*w,y:W*w,height:T,turn:Z,shade:ee(se,5),seed:ee(se,7)})}v+=y}L+=P}}}}let k=w=>Te(Math.floor(n.variants?.[Me[w]]??1),[1,4]),M=w=>Math.min(k(w.form)-1,Math.floor(ee(Math.floor(w.seed*256),9)*k(w.form))),B=l.map(M),U=l.map((w,y)=>y);U.sort((w,y)=>l[w].form-l[y].form||B[w]-B[y]||l[w].rank-l[y].rank);let E=new Uint8Array(l.length*tn),C=new DataView(E.buffer),I=0,N=()=>({start:0,count:0,upTo:new Array(rn).fill(0)}),K=Object.fromEntries(Me.map((w,y)=>[w,{...N(),variants:Array.from({length:k(y)},N)}])),$=(w,y,b)=>{w.count===0&&(w.start=y),w.count+=1;for(let x=b;x<rn;x+=1)w.upTo[x]+=1};U.forEach((w,y)=>{let b=l[w],x=y*tn;C.setUint16(x,Math.min(q-1,Math.round(b.x)),!0),C.setUint16(x+2,Math.min(q-1,Math.round(b.y)),!0),C.setUint16(x+4,Math.round(b.height*10),!0),C.setUint16(x+6,Math.round(b.crown*10),!0),E[x+8]=Math.floor(b.turn*256)&255,E[x+9]=Math.floor(b.shade*256)&255,E[x+10]=b.form,E[x+11]=b.rank,E[x+12]=Math.floor(b.seed*256)&255,E[x+13]=b.canopy,E[x+14]=B[w],I=Math.max(I,b.height);let T=K[Me[b.form]];$(T,y,b.rank),$(T.variants[B[w]],y,b.rank)});let D=new Uint8Array(_.length*tn),Y=new DataView(D.buffer);return _.forEach((w,y)=>{let b=y*tn;Y.setUint16(b,Math.min(q-1,Math.round(w.x)),!0),Y.setUint16(b+2,Math.min(q-1,Math.round(w.y)),!0),Y.setUint16(b+4,Math.round(w.height*10),!0),Y.setUint16(b+6,Math.round(xr*10),!0),D[b+8]=Math.round(w.turn*256)&255,D[b+9]=Math.floor(w.shade*256)&255,D[b+12]=Math.floor(w.seed*256)&255,I=Math.max(I,w.height)}),{trees:E,forms:K,hedges:D,tallest:I,mapped:u,canopy:c}}function Fr(e){let n={round:e.round??0,open:e.open??0,tall:e.tall??0};return n.round+n.open+n.tall>0?n:Sn}function sn(e,n){let t=0;for(let o of Me)t+=Math.max(0,e[o]??0);if(t<=0)return sn(Sn,n);let i=n*t;for(let o of Me){let r=Math.max(0,e[o]??0);if(i<r)return o;i-=r}return"round"}function xe(e,n){let t=typeof e=="number"?e:typeof e=="string"?Number.parseFloat(e):NaN;return Number.isFinite(t)&&t>0?Te(t,n):void 0}function Te(e,[n,t]){return Math.min(t,Math.max(n,e))}function An([e,n],t){return e+(n-e)*t}function Ar(e,n,t){let i=2**e.z,o=(e.x+n)/i*360-180,r=Math.atan(Math.sinh(Math.PI*(1-2*(e.y+t)/i)))*180/Math.PI;return[o,r]}function ze(e,n,t){let i=(Math.imul(Math.floor(e)|0,668265261)^Math.imul(Math.floor(n)|0,374761393)^Math.imul(t,2654435761))>>>0;return i=Math.imul(i^i>>>15,2246822507)>>>0,i=Math.imul(i^i>>>13,3266489909)>>>0,(i^i>>>16)>>>0}function ee(e,n){return ze(e,n,20973)/4294967296}var Sr=[void 0,"Point","LineString","Polygon"];function ft(e,n={}){let t=n.layers?new Set(n.layers):void 0,i={},o=new Bn(e,0,e.length);for(;o.more();){let[r,s]=o.tag();if(r!==3){o.skip(s);continue}let a=o.message(),l=Lr(a,t);l&&!(l.name in i)&&(i[l.name]=l.layer)}return i}function Lr(e,n){let t,i=4096,o=[],r=[],s=[];for(;e.more();){let[a,l]=e.tag();if(a===1?t=e.string():a===2?s.push(e.message()):a===3?o.push(e.string()):a===4?r.push(Ur(e.message())):a===5?i=e.varint():e.skip(l),t!==void 0&&n&&!n.has(t))return}if(!(t===void 0||n&&!n.has(t)))return{name:t,layer:Object.freeze({extent:i,features:Object.freeze(s.flatMap(a=>{let l=Br(a,o,r);return l?[l]:[]}))})}}function Br(e,n,t){let i,o,r={},s=[];for(;e.more();){let[a,l]=e.tag();if(a===1)i=e.varint();else if(a===2){let u=e.packed();for(let c=0;c+1<u.length;c+=2){let f=n[u[c]],d=t[u[c+1]];f!==void 0&&d!==void 0&&(r[f]=d)}}else a===3?o=Sr[e.varint()]:a===4?s=e.packed():e.skip(l)}if(o)return Object.freeze({...i===void 0?{}:{id:i},type:o,properties:Object.freeze(r),geometry:Object.freeze(Or(s,o))})}function Or(e,n){let t=[],i,o=0,r=0,s=0;for(;s<e.length;){let a=e[s++],l=a&7,u=a>>>3;if(l===7){i&&i.length>=2&&i.push(i[0],i[1]);continue}if(l!==1&&l!==2)throw new Error(`Unknown geometry command ${l} in vector tile.`);if(s+u*2>e.length)throw new Error("Truncated vector tile geometry.");for(let c=0;c<u;c+=1){if(o+=Ln(e[s++]),r+=Ln(e[s++]),l===1&&(n!=="Point"||c===0)&&t.push(i=[]),!i)throw new Error("Vector tile geometry draws a line before moving to its start.");i.push(o,r)}}return t}var Ln=e=>e%2===1?-(e+1)/2:e/2;function Ur(e){let n="";for(;e.more();){let[t,i]=e.tag();t===1?n=e.string():t===2?n=e.float():t===3?n=e.double():t===4?n=e.varint(!0):t===5?n=e.varint():t===6?n=Ln(e.varint()):t===7?n=e.varint()!==0:e.skip(i)}return n}var Cr=new TextDecoder,Bn=class e{constructor(n,t,i){this.bytes=n;this.end=i;this.position=t,this.view=new DataView(n.buffer,n.byteOffset,n.byteLength)}bytes;end;position;view;more(){return this.position<this.end}tag(){let n=this.varint();return[Math.floor(n/8),n&7]}varint(n=!1){let t=0,i=0;for(let o=0;o<10;o+=1){if(this.position>=this.end)throw new Error("Truncated vector tile.");let r=this.bytes[this.position++];if(o<4?t|=(r&127)<<o*7:o===4?(t|=(r&15)<<28,i=(r&112)>>4):o<9?i|=(r&127)<<(o-5)*7+3:i|=(r&1)<<31,r<128)return n?i*4294967296+(t>>>0):(i>>>0)*4294967296+(t>>>0)}throw new Error("Invalid varint in vector tile.")}span(){let n=this.varint(),t=this.position;if(t+n>this.end)throw new Error("Truncated vector tile.");return this.position=t+n,[t,t+n]}message(){let[n,t]=this.span();return new e(this.bytes,n,t)}string(){let[n,t]=this.span();return Cr.decode(this.bytes.subarray(n,t))}packed(){let[n,t]=this.span(),i=new e(this.bytes,n,t),o=[];for(;i.more();)o.push(i.varint());return o}float(){if(this.position+4>this.end)throw new Error("Truncated vector tile.");let n=this.view.getFloat32(this.position,!0);return this.position+=4,n}double(){if(this.position+8>this.end)throw new Error("Truncated vector tile.");let n=this.view.getFloat64(this.position,!0);return this.position+=8,n}skip(n){if(n===0)this.varint();else if(n===1)this.position+=8;else if(n===2)this.span();else if(n===5)this.position+=4;else throw new Error(`Unsupported protocol buffer wire type ${n} in vector tile.`);if(this.position>this.end)throw new Error("Truncated vector tile.")}};function dt(e){return Object.values(e.layers).filter(n=>typeof n=="string")}function mt(e,n){if(e.kind==="buildings"){let r=n(e.layers.building);if(!r)return;let s=n(e.layers.places),a=Kn(r,{...e.options,...s?{places:s}:{}});return a&&et(a)}if(e.kind==="trees"){let r=n(e.layers.tree),s=n(e.layers.canopy),a=n(e.layers.hedge);if(!r&&!s&&!a)return;let l=ct({...r?{trees:r}:{},...s?{canopy:s}:{},...a?{hedges:a}:{}},e.options);return l.trees.length>0||l.hedges.length>0?l:void 0}let t=n(e.layers.streetFurniture),i=n(e.layers.transportation),o=n(e.layers.sidewalk);return it({...t?{streetFurniture:t}:{},...i?{transportation:i}:{},...o?{sidewalks:o}:{}},e.options)}function ht(e,n){if(!n)return[];if(e==="buildings")return nt(n);if(e==="trees"){let{trees:t,hedges:i}=n;return[t.buffer,i.buffer].filter((o,r,s)=>s.indexOf(o)===r)}return[n.lamps.buffer]}function pt(e=16){let n=new Map;return{read(t,i,o){let r=n.get(t);for(n.delete(t),r??={bytes:i,layers:new Map},n.set(t,r);n.size>e;)n.delete(n.keys().next().value);let s=o.filter(l=>!r.layers.has(l));if(s.length>0){let l=ft(r.bytes,{layers:s});for(let u of s)r.layers.set(u,l[u])}let a=r.layers;return l=>l===void 0?void 0:a.get(l)}}}var On=globalThis,Pr=pt();On.onmessage=({data:{url:e,bytes:n,task:t}})=>{try{let i=mt(t,Pr.read(e,n,dt(t)));On.postMessage({result:i},ht(t.kind,i))}catch(i){On.postMessage({error:String(i)})}};})();\n'], { type: "text/javascript" })
9653
10051
  );
9654
10052
  try {
9655
10053
  return new Worker(url, { name: "tileflow-tiles" });
@@ -14185,6 +14583,7 @@ function createTileflowBuildings3D(options) {
14185
14583
  const nightLight2 = mixed2((entry) => entry.nightLight);
14186
14584
  const architectural = floodLightNow();
14187
14585
  const edges = mixed2((entry) => entry.edges);
14586
+ const surfaces = design().surfaces;
14188
14587
  const { occlusion: occlusionOn, windows: windowsOn } = design();
14189
14588
  const now = performance.now();
14190
14589
  const appearing = standing.filter((entry) => appearanceOf(entry, now) < 1);
@@ -14210,6 +14609,24 @@ function createTileflowBuildings3D(options) {
14210
14609
  context.uniform1f(u.u_corner, tileflowBuildingOcclusion.corner);
14211
14610
  context.uniform1f(u.u_night, light.night);
14212
14611
  context.uniform1f(u.u_windows, windowsOn ? 1 : 0);
14612
+ context.uniform4f(
14613
+ u.u_surface_walls,
14614
+ surfaces?.walls?.size[0] ?? 6,
14615
+ surfaces?.walls?.size[1] ?? 3,
14616
+ surfaces?.walls?.jointWidth ?? 0.12,
14617
+ mixed2((entry) => entry.surfaces?.walls?.contrast ?? 0)
14618
+ );
14619
+ context.uniform3f(
14620
+ u.u_surface_roof,
14621
+ surfaces?.roof?.size ?? 8,
14622
+ surfaces?.roof?.jointWidth ?? 0.12,
14623
+ mixed2((entry) => entry.surfaces?.roof?.contrast ?? 0)
14624
+ );
14625
+ context.uniform2f(
14626
+ u.u_surface_cornice,
14627
+ surfaces?.cornice?.height ?? 0.6,
14628
+ mixed2((entry) => entry.surfaces?.cornice?.contrast ?? 0)
14629
+ );
14213
14630
  context.uniform1f(u.u_flood, light.night * nightLight2);
14214
14631
  context.uniform3fv(u.u_flood_colour, flood.colour);
14215
14632
  context.uniform1f(u.u_architectural_intensity, architectural.intensity);
@@ -14252,6 +14669,10 @@ function createTileflowBuildings3D(options) {
14252
14669
  if (!ranges.length) continue;
14253
14670
  project(context, buildings, args, x3, y2);
14254
14671
  context.uniform2f(u.u_offset, ...placed2(x3, y2).offset);
14672
+ context.uniform3f(
14673
+ u.u_surface_tile,
14674
+ ...tileflowBuildingSurfaceTile(x3, y2, camera.zoom, surfaces?.roof?.size ?? 8)
14675
+ );
14255
14676
  context.uniform4f(u.u_ring ?? null, ...ringIn(x3, y2));
14256
14677
  context.uniform2f(u.u_ring_ahead ?? null, ...ahead);
14257
14678
  const palette = themes ? paletteOf(context, entry, themes.themes) : void 0;
@@ -15883,6 +16304,7 @@ var placement2 = `
15883
16304
  uniform float u_scale;
15884
16305
  uniform float u_metres; // metres per tile unit
15885
16306
  uniform vec2 u_offset; // this tile's corner from the scene's origin, in tile units
16307
+ uniform float u_minimum_height; // optional visual height floor, in metres
15886
16308
  uniform vec2 u_size_scale; // the map's height and crown scales, for this form
15887
16309
  uniform float u_round; // how far normals turn from the facets to the round shape, by finish
15888
16310
 
@@ -15898,17 +16320,20 @@ vec2 turned(vec2 v) {
15898
16320
  return vec2(v.x * c - v.y * s, v.x * s + v.y * c);
15899
16321
  }
15900
16322
 
16323
+ vec2 displaySize() {
16324
+ vec2 size = a_tree_size * 0.1 * u_size_scale;
16325
+ return size * max(1.0, u_minimum_height / max(size.x, 0.001));
16326
+ }
16327
+
15901
16328
  vec3 standing(float growth) {
15902
- float height = a_tree_size.x * 0.1 * u_size_scale.x;
15903
- float crown = a_tree_size.y * 0.1 * u_size_scale.y;
15904
- return vec3(turned(a_vertex.xy * crown), a_vertex.z * height) * growth;
16329
+ vec2 size = displaySize();
16330
+ return vec3(turned(a_vertex.xy * size.y), a_vertex.z * size.x) * growth;
15905
16331
  }
15906
16332
 
15907
16333
  vec3 normalOf() {
15908
- float height = max(a_tree_size.x * 0.1 * u_size_scale.x, 0.1);
15909
- float crown = max(a_tree_size.y * 0.1 * u_size_scale.y, 0.1);
16334
+ vec2 size = max(displaySize(), vec2(0.1));
15910
16335
  vec3 blended = normalize(mix(a_normal, a_round, u_round));
15911
- vec3 n = normalize(vec3(blended.xy / crown, blended.z / height));
16336
+ vec3 n = normalize(vec3(blended.xy / size.y, blended.z / size.x));
15912
16337
  return vec3(turned(n.xy), n.z);
15913
16338
  }
15914
16339
 
@@ -15998,6 +16423,7 @@ uniform float u_night;
15998
16423
  uniform float u_fade; // how far the layer has faded in, from 0 to 1
15999
16424
  uniform float u_toon; // 1 for light in bands, as a drawing has it
16000
16425
  uniform vec3 u_bark;
16426
+ uniform float u_material_variation;
16001
16427
  uniform vec3 u_leaves[4]; // the form's colours, sunlit
16002
16428
  uniform float u_leaf_count;
16003
16429
  out vec4 fragColor;
@@ -16008,7 +16434,7 @@ ${treeDither}
16008
16434
 
16009
16435
  vec3 leafColour() {
16010
16436
  float count = max(u_leaf_count, 1.0);
16011
- float at = v_shade * (count - 1.0);
16437
+ float at = clamp(v_shade + v_look.y * 0.45 * u_material_variation, 0.0, 1.0) * (count - 1.0);
16012
16438
  int low = int(floor(at));
16013
16439
  int high = min(low + 1, int(count) - 1);
16014
16440
  vec3 a = u_leaves[0];
@@ -16030,7 +16456,7 @@ void main() {
16030
16456
  // A palm's stem is paler than bark, ringed light and dark by its leaf scars.
16031
16457
  vec3 base = stem
16032
16458
  ? min(u_bark * 1.45 + 0.06, vec3(1.0)) * (1.0 + v_look.y * 0.12)
16033
- : bark ? u_bark : leafColour() * (1.0 + v_look.y * 0.09);
16459
+ : bark ? u_bark * (1.0 + ((v_shade - 0.5) * 0.32 + v_look.y * 0.08) * u_material_variation) : leafColour() * (1.0 + v_look.y * 0.09);
16034
16460
  float facing = dot(normal, u_sun_dir);
16035
16461
  // Leaves let light round and through them: wrapped light on the lit side, a glow against a low sun.
16036
16462
  float direct = bark ? max(facing, 0.0) : fronds ? abs(facing) * 0.85 : max((facing + 0.35) / 1.35, 0.0);
@@ -16438,6 +16864,7 @@ function createTileflowTrees3D(options) {
16438
16864
  palm: slots(theme?.colors.palm ?? ["#7fa45f"]),
16439
16865
  hedge: slots(theme?.colors.hedge ?? ["#5f8a55"]),
16440
16866
  size: [[theme?.heightScale ?? 1, theme?.crownScale ?? 1, 0]],
16867
+ materials: [[theme?.minimumHeight ?? 0, theme?.materialVariation ?? 0, 0]],
16441
16868
  forms: tileflowTreeForms.map((form) => [
16442
16869
  theme?.forms[form]?.heightScale ?? 1,
16443
16870
  theme?.forms[form]?.crownScale ?? 1,
@@ -16457,6 +16884,8 @@ function createTileflowTrees3D(options) {
16457
16884
  palm: mixList(x3.palm, y2.palm),
16458
16885
  hedge: mixList(x3.hedge, y2.hedge),
16459
16886
  size,
16887
+ minimumHeight: mixList(x3.materials, y2.materials)[0][0],
16888
+ materialVariation: mixList(x3.materials, y2.materials)[0][1],
16460
16889
  /** Each form's height and crown scale: the map's times the form's own. */
16461
16890
  sizes: Object.fromEntries(
16462
16891
  tileflowTreeForms.map((form, index) => [
@@ -16504,11 +16933,11 @@ function createTileflowTrees3D(options) {
16504
16933
  return {
16505
16934
  zoom: preferredZoom3,
16506
16935
  tiles: [left, top, right, bottom],
16507
- tallest: tallest * shown * size[0]
16936
+ tallest: Math.max(tallest * size[0], colours().minimumHeight) * shown
16508
16937
  };
16509
16938
  },
16510
16939
  // Camera-dependent density, detail and fading also change the trees casting shadows.
16511
- key: () => `trees:${map.isMoving?.() ? view().movingKey : view().key}:${fadeIn().toFixed(4)}:${visibleScale().toFixed(4)}:${generation}:${programs.depth ? 1 : 0}:${Object.values(
16940
+ key: () => `trees:${colours().minimumHeight.toFixed(3)}:${map.isMoving?.() ? view().movingKey : view().key}:${fadeIn().toFixed(4)}:${visibleScale().toFixed(4)}:${generation}:${programs.depth ? 1 : 0}:${Object.values(
16512
16941
  colours().sizes
16513
16942
  ).flat().map((value) => value.toFixed(3)).join()}:${drawn().map(({ x: x3, y: y2 }) => `${x3}/${y2}`).join(";")}`,
16514
16943
  drawDepth(context, frame) {
@@ -16520,12 +16949,14 @@ function createTileflowTrees3D(options) {
16520
16949
  context.uniform1f(u.u_metres, frame.metres);
16521
16950
  context.uniformMatrix4fv(u.u_light_matrix, false, frame.light.matrix);
16522
16951
  const sizes = colours().sizes;
16952
+ const minimumHeight = colours().minimumHeight;
16523
16953
  const camera = view();
16524
16954
  context.uniform1f(u.u_fade, 1);
16525
16955
  context.uniform2fv(u.u_reach, [...camera.reach]);
16526
16956
  for (const { x: x3, y: y2, set, value } of drawn()) {
16527
16957
  const selection = camera.tile(x3, y2);
16528
16958
  if (!selection) continue;
16959
+ context.uniform1f(u.u_minimum_height, minimumHeight);
16529
16960
  context.uniform2f(u.u_offset, ...frame.offsetOf({ x: x3, y: y2 }, set.zoom));
16530
16961
  context.uniform2f(
16531
16962
  u.u_centre,
@@ -16543,6 +16974,7 @@ function createTileflowTrees3D(options) {
16543
16974
  });
16544
16975
  const hedge = value.gl.hedge;
16545
16976
  if (hedge) {
16977
+ context.uniform1f(u.u_minimum_height, 0);
16546
16978
  context.uniform2f(u.u_size_scale, 1, 1);
16547
16979
  context.bindVertexArray(hedge.vao);
16548
16980
  context.drawArraysInstanced(
@@ -16589,6 +17021,7 @@ function createTileflowTrees3D(options) {
16589
17021
  context.uniform1f(u.u_scale, visibleScale());
16590
17022
  context.uniform1f(u.u_metres, metres);
16591
17023
  context.uniform1f(u.u_round, finishes[palette2.finish].round);
17024
+ context.uniform1f(u.u_material_variation, palette2.materialVariation);
16592
17025
  context.uniform1f(u.u_toon, palette2.finish === "toon" ? 1 : 0);
16593
17026
  context.uniform3fv(u.u_sun_dir, [...light.direction]);
16594
17027
  context.uniform3fv(u.u_shadow_dir, light.shadowDirection);
@@ -16625,21 +17058,41 @@ function createTileflowTrees3D(options) {
16625
17058
  palette2.sizes[form][0],
16626
17059
  palette2.sizes[form][1] * drawing.crown
16627
17060
  ];
17061
+ context.uniform1f(u.u_minimum_height, palette2.minimumHeight);
16628
17062
  context.uniform2f(u.u_size_scale, ...size);
16629
17063
  context.bindVertexArray(drawing.vao);
16630
17064
  context.drawArraysInstanced(context.TRIANGLES, 0, drawing.count, instances);
16631
17065
  count += instances;
16632
- draws.push({ x: x3, y: y2, offset, leaves, size, instances, drawing });
17066
+ draws.push({
17067
+ x: x3,
17068
+ y: y2,
17069
+ offset,
17070
+ leaves,
17071
+ size,
17072
+ minimumHeight: palette2.minimumHeight,
17073
+ instances,
17074
+ drawing
17075
+ });
16633
17076
  });
16634
17077
  }
16635
17078
  const hedge = value.gl.hedge;
16636
17079
  if (hedge) {
16637
17080
  const instances = value.placement.hedges.length / tileflowTreeBytes;
16638
17081
  context.uniform3fv(u.u_leaves, palette2.hedge.flat());
17082
+ context.uniform1f(u.u_minimum_height, 0);
16639
17083
  context.uniform2f(u.u_size_scale, 1, 1);
16640
17084
  context.bindVertexArray(hedge.vao);
16641
17085
  context.drawArraysInstanced(context.TRIANGLES, 0, hedge.count, instances);
16642
- draws.push({ x: x3, y: y2, offset, leaves: palette2.hedge, size: [1, 1], instances, drawing: hedge });
17086
+ draws.push({
17087
+ x: x3,
17088
+ y: y2,
17089
+ offset,
17090
+ leaves: palette2.hedge,
17091
+ size: [1, 1],
17092
+ minimumHeight: 0,
17093
+ instances,
17094
+ drawing: hedge
17095
+ });
16643
17096
  }
16644
17097
  }
16645
17098
  drawnLast = count;
@@ -16677,6 +17130,7 @@ function createTileflowTrees3D(options) {
16677
17130
  (channel) => palette2.edgeColor[channel] * own + draw2.leaves[0][channel] * 0.4 * (1 - own)
16678
17131
  )
16679
17132
  );
17133
+ context.uniform1f(e.u_minimum_height, draw2.minimumHeight);
16680
17134
  context.uniform2f(e.u_size_scale, ...draw2.size);
16681
17135
  context.bindVertexArray(draw2.drawing.vao);
16682
17136
  context.drawArraysInstanced(context.TRIANGLES, 0, draw2.drawing.count, draw2.instances);
@@ -16841,6 +17295,7 @@ ${shaderData.define}`;
16841
17295
  }
16842
17296
  const layer = {
16843
17297
  id: tileflowTrees3DLayerId,
17298
+ metadata: { "tileflow:scene-kind": "vegetation" },
16844
17299
  type: "custom",
16845
17300
  renderingMode: "3d",
16846
17301
  onAdd(_2, context) {
@@ -16931,8 +17386,14 @@ ${args.shaderData.define}`;
16931
17386
  }
16932
17387
  function beforeId() {
16933
17388
  if (options.beforeId) return map.getLayer(options.beforeId) ? options.beforeId : void 0;
16934
- if (map.getLayer(streetLightsLayerId2)) return streetLightsLayerId2;
16935
17389
  const style = map.getStyle();
17390
+ if (style?.layers?.some(isGroundRoadLabel)) {
17391
+ const boundary = style.layers.find(
17392
+ (entry) => isGroundRoadLabel(entry) || entry.type === "fill-extrusion"
17393
+ );
17394
+ if (boundary) return boundary.id;
17395
+ }
17396
+ if (map.getLayer(streetLightsLayerId2)) return streetLightsLayerId2;
16936
17397
  const anchors = style?.metadata?.["tileflow:overlay-placement-manifest"]?.anchors;
16937
17398
  const anchor = anchors?.["above-buildings"];
16938
17399
  if (typeof anchor === "string" && map.getLayer(anchor)) return anchor;
@@ -19632,6 +20093,7 @@ function validateTileflowBrowserThemeBlendSelection(value) {
19632
20093
  }
19633
20094
  var maximumBlendThemes = 8;
19634
20095
  var maximumTransitionMs = 5e3;
20096
+ var defaultThemeTransitionMs = 450;
19635
20097
  var blendLabelFadeMs = 450;
19636
20098
  var maximumTileflowBlendStyleBytes = 16 * 1024 * 1024;
19637
20099
  function validateStyleState(name, value) {
@@ -19647,6 +20109,10 @@ function createTileflowThemeController(options) {
19647
20109
  const loadStyle = options.loadStyle ?? loadTileflowBlendStyle;
19648
20110
  const timeoutMs = normalizeThemeTransitionTimeout(options.timeoutMs);
19649
20111
  const defaultTransition3 = normalizeThemeTransitionDuration(options.transition);
20112
+ const defaultThemeTransition = normalizeThemeTransitionDuration(
20113
+ options.transition,
20114
+ defaultThemeTransitionMs
20115
+ );
19650
20116
  const styleIdentities = /* @__PURE__ */ new WeakMap();
19651
20117
  const blendRouteInks = /* @__PURE__ */ new WeakMap();
19652
20118
  const blendMetadata = /* @__PURE__ */ new WeakMap();
@@ -19668,6 +20134,7 @@ function createTileflowThemeController(options) {
19668
20134
  let shown = { style: options.initial.style };
19669
20135
  let activeBlend;
19670
20136
  let pendingBlend;
20137
+ let stopThemeMotion;
19671
20138
  let disposed = false;
19672
20139
  let requestId = 0;
19673
20140
  let applyQueue = Promise.resolve();
@@ -19712,6 +20179,7 @@ function createTileflowThemeController(options) {
19712
20179
  return {
19713
20180
  dispose() {
19714
20181
  disposed = true;
20182
+ stopThemeMotion?.();
19715
20183
  releaseMetadata();
19716
20184
  images?.dispose();
19717
20185
  requestId += 1;
@@ -19811,9 +20279,10 @@ function createTileflowThemeController(options) {
19811
20279
  const invalid = validateBlendRequest(request);
19812
20280
  if (invalid) return Promise.resolve({ error: invalid, status: "failed", theme: targetTheme });
19813
20281
  if (disposed) return Promise.resolve(disposedResult(targetTheme));
19814
- const transition = transitionOf(changeOptions);
20282
+ const transition = transitionOf(changeOptions, defaultThemeTransition);
19815
20283
  if (transition instanceof TypeError)
19816
20284
  return Promise.resolve({ error: transition, status: "failed", theme: targetTheme });
20285
+ stopThemeMotion?.();
19817
20286
  const key = blendKey(request.themes);
19818
20287
  if (activeBlend?.key === key) {
19819
20288
  requestId += 1;
@@ -19851,9 +20320,10 @@ function createTileflowThemeController(options) {
19851
20320
  return Promise.resolve({ error: invalidTheme, status: "failed", theme: style.theme });
19852
20321
  }
19853
20322
  if (disposed) return Promise.resolve(disposedResult(style.theme));
19854
- const transition = transitionOf(changeOptions);
20323
+ const transition = transitionOf(changeOptions, defaultThemeTransition);
19855
20324
  if (transition instanceof TypeError)
19856
20325
  return Promise.resolve({ error: transition, status: "failed", theme: style.theme });
20326
+ stopThemeMotion?.();
19857
20327
  const runId = ++requestId;
19858
20328
  pendingBlend = void 0;
19859
20329
  options.onTransition?.({
@@ -19873,10 +20343,10 @@ function createTileflowThemeController(options) {
19873
20343
  );
19874
20344
  }
19875
20345
  };
19876
- function transitionOf(changeOptions) {
19877
- if (changeOptions?.transition === void 0) return defaultTransition3;
20346
+ function transitionOf(changeOptions, defaultDuration = defaultTransition3) {
20347
+ if (changeOptions?.transition === void 0) return defaultDuration;
19878
20348
  try {
19879
- return normalizeThemeTransitionDuration(changeOptions.transition);
20349
+ return normalizeThemeTransitionDuration(changeOptions.transition, defaultDuration);
19880
20350
  } catch (error) {
19881
20351
  return error;
19882
20352
  }
@@ -19955,11 +20425,55 @@ function createTileflowThemeController(options) {
19955
20425
  if (disposed || runId !== requestId) return { status: "superseded", theme: targetTheme };
19956
20426
  const previous = { current, shown };
19957
20427
  options.onTransition?.({ currentTheme: previous.current.theme, phase: "applying", targetTheme });
19958
- const cover = beginTileflowStyleCrossfade(options.map, target.transition);
19959
- activeBlend?.blender.dispose();
19960
- activeBlend = void 0;
20428
+ let cover;
19961
20429
  const styleInput = target.kind === "theme" ? target.style.style : target.plan.styleAt(target.position());
19962
20430
  try {
20431
+ let liveTransition = false;
20432
+ if (target.kind === "theme" && !activeBlend && target.transition > 0 && !reducedMotion() && tileflowThemeMotionView(options.map) && canBlendTileflowThemes(options.map)) {
20433
+ const themes = [previous.current, target.style];
20434
+ let plan;
20435
+ try {
20436
+ plan = await prepareBlend(themes);
20437
+ } catch {
20438
+ }
20439
+ if (disposed || runId !== requestId) return { status: "superseded", theme: targetTheme };
20440
+ if (plan) {
20441
+ liveTransition = true;
20442
+ const style = { ...plan.styleAt(0), transition: { duration: 0, delay: 0 } };
20443
+ const from = typeof previous.shown.style === "string" ? await loadStyle(previous.shown.style) : previous.shown.style;
20444
+ if (!await prepareGeometry(from, style, runId)) {
20445
+ if (!disposed) await restore(previous);
20446
+ return { status: "superseded", theme: targetTheme };
20447
+ }
20448
+ await applyMapStyle(options.map, style, timeoutMs);
20449
+ if (disposed) return { status: "superseded", theme: targetTheme };
20450
+ const blender = createBlender(plan, 0, true);
20451
+ activeBlend = { blender, key: "", plan, themes };
20452
+ shown = { blend: activeBlend, style };
20453
+ shownLayers = style.layers;
20454
+ resetEmphasis();
20455
+ resetStates();
20456
+ resetSun(void 0);
20457
+ await animateTheme(blender, themes, target.transition, runId);
20458
+ if (!disposed && runId === requestId) {
20459
+ const destination = typeof styleInput === "string" ? await loadStyle(styleInput) : styleInput;
20460
+ const finalBlendStyle = { ...plan.styleAt(1), transition: { duration: 0, delay: 0 } };
20461
+ await prepareGeometry(finalBlendStyle, destination, runId);
20462
+ }
20463
+ blender.dispose();
20464
+ activeBlend = void 0;
20465
+ if (disposed) return { status: "superseded", theme: targetTheme };
20466
+ if (runId !== requestId) {
20467
+ await restore(previous);
20468
+ return { status: "superseded", theme: targetTheme };
20469
+ }
20470
+ }
20471
+ }
20472
+ if (!liveTransition) {
20473
+ cover = beginTileflowStyleCrossfade(options.map, target.transition);
20474
+ }
20475
+ activeBlend?.blender.dispose();
20476
+ activeBlend = void 0;
19963
20477
  if (target.kind === "blend") images?.assertBlend(target.plan.images);
19964
20478
  invalidateMetadata();
19965
20479
  await applyMapStyle(options.map, styleInput, timeoutMs);
@@ -20000,6 +20514,8 @@ function createTileflowThemeController(options) {
20000
20514
  return { status: "applied", theme: current.theme };
20001
20515
  } catch (error) {
20002
20516
  cover?.cancel();
20517
+ activeBlend?.blender.dispose();
20518
+ activeBlend = void 0;
20003
20519
  const normalized = normalizeThemeTransitionError(error, "Tileflow theme change failed.");
20004
20520
  try {
20005
20521
  await restore(previous);
@@ -20015,14 +20531,66 @@ function createTileflowThemeController(options) {
20015
20531
  return { error: normalized, status: "failed", theme: targetTheme };
20016
20532
  }
20017
20533
  }
20018
- function createBlender(plan, position) {
20534
+ async function prepareGeometry(from, to, runId) {
20535
+ const getStyle = options.map.getStyle;
20536
+ const displayed = typeof getStyle === "function" ? getStyle.call(options.map) : void 0;
20537
+ const preparation = prepareTileflowThemeGeometry(displayed ?? from, to);
20538
+ if (!preparation) return !disposed && runId === requestId;
20539
+ await applyMapStyle(options.map, preparation.style, timeoutMs);
20540
+ const ready = await waitForTileflowThemeGeometry(
20541
+ options.map,
20542
+ timeoutMs,
20543
+ () => disposed || runId !== requestId
20544
+ );
20545
+ if (ready) preparation.reveal(options.map);
20546
+ return ready;
20547
+ }
20548
+ function animateTheme(blender, themes, duration, runId) {
20549
+ const view = tileflowThemeMotionView(options.map);
20550
+ return new Promise((resolve, reject) => {
20551
+ const now = () => view.performance?.now?.() ?? Date.now();
20552
+ const started = now();
20553
+ let frame;
20554
+ let settled = false;
20555
+ const finish2 = (error) => {
20556
+ if (settled) return;
20557
+ settled = true;
20558
+ if (frame !== void 0) {
20559
+ view.cancelAnimationFrame?.(frame);
20560
+ view.clearTimeout(frame);
20561
+ }
20562
+ if (stopThemeMotion === cancel) stopThemeMotion = void 0;
20563
+ if (error) reject(error);
20564
+ else resolve();
20565
+ };
20566
+ const cancel = () => finish2();
20567
+ const step = () => {
20568
+ frame = void 0;
20569
+ if (disposed || runId !== requestId) return finish2();
20570
+ try {
20571
+ const t = Math.min(1, (now() - started) / duration);
20572
+ blender.set(t * t * (3 - 2 * t));
20573
+ current = themes[blender.dominant];
20574
+ images?.invalidate();
20575
+ if (t >= 1) finish2();
20576
+ else frame = view.requestAnimationFrame?.(step) ?? view.setTimeout(step, 16);
20577
+ } catch (error) {
20578
+ finish2(error);
20579
+ }
20580
+ };
20581
+ stopThemeMotion = cancel;
20582
+ step();
20583
+ });
20584
+ }
20585
+ function createBlender(plan, position, liveTransition = false) {
20019
20586
  return createTileflowThemeBlender(options.map, plan, {
20020
20587
  cover(change) {
20588
+ if (liveTransition) return change();
20021
20589
  const fade = beginTileflowStyleCrossfade(options.map, blendLabelFadeMs);
20022
20590
  change();
20023
20591
  void fade?.finish();
20024
20592
  },
20025
- labelFadeMs: reducedMotion() ? 0 : blendLabelFadeMs,
20593
+ labelFadeMs: liveTransition || reducedMotion() ? 0 : blendLabelFadeMs,
20026
20594
  // The ground colour moves with the blend, and colours that recede follow it.
20027
20595
  onPosition: () => {
20028
20596
  if (emphasisShown) writeEmphasis(false);
@@ -20550,8 +21118,8 @@ function validateBlendRequest(request) {
20550
21118
  }
20551
21119
  return void 0;
20552
21120
  }
20553
- function normalizeThemeTransitionDuration(transition) {
20554
- const duration = transition?.duration ?? 0;
21121
+ function normalizeThemeTransitionDuration(transition, defaultDuration = 0) {
21122
+ const duration = transition?.duration ?? defaultDuration;
20555
21123
  if (typeof duration !== "number" || !Number.isFinite(duration) || duration < 0 || duration > maximumTransitionMs) {
20556
21124
  throw new TypeError(
20557
21125
  `A Tileflow theme transition duration must be a number of milliseconds from 0 to ${maximumTransitionMs}.`
@@ -20613,6 +21181,7 @@ function applyMapStyle(map, style, timeoutMs) {
20613
21181
  const cleanup = () => {
20614
21182
  clearTimeout(timeout);
20615
21183
  map.off("style.load", handleLoad);
21184
+ map.off("render", handleRenderedStyle);
20616
21185
  map.off("error", handleError);
20617
21186
  };
20618
21187
  const settle = (error) => {
@@ -20623,6 +21192,10 @@ function applyMapStyle(map, style, timeoutMs) {
20623
21192
  else resolve();
20624
21193
  };
20625
21194
  const handleLoad = () => settle();
21195
+ const handleRenderedStyle = () => {
21196
+ const isStyleLoaded = map.isStyleLoaded;
21197
+ if (typeof isStyleLoaded === "function" && isStyleLoaded.call(map) === true) settle();
21198
+ };
20626
21199
  const handleError = (event) => settle(
20627
21200
  normalizeThemeTransitionError(
20628
21201
  isRecordWithError(event) ? event.error : event,
@@ -20634,6 +21207,7 @@ function applyMapStyle(map, style, timeoutMs) {
20634
21207
  timeoutMs
20635
21208
  );
20636
21209
  map.on("style.load", handleLoad);
21210
+ map.on("render", handleRenderedStyle);
20637
21211
  map.on("error", handleError);
20638
21212
  try {
20639
21213
  if (typeof map.setStyle !== "function") {
@@ -20641,6 +21215,7 @@ function applyMapStyle(map, style, timeoutMs) {
20641
21215
  }
20642
21216
  const setStyle = map.setStyle;
20643
21217
  setStyle.call(map, style, { diff: true, validate: false });
21218
+ handleRenderedStyle();
20644
21219
  } catch (error) {
20645
21220
  settle(normalizeThemeTransitionError(error, "MapLibre rejected the Tileflow theme."));
20646
21221
  }
@@ -20985,6 +21560,7 @@ function isPromiseLike(value) {
20985
21560
  export {
20986
21561
  attachTileflowAtmosphere,
20987
21562
  attachTileflowFairUseNotice,
21563
+ attachTileflowLabelPlacement,
20988
21564
  attachTileflowMap3D,
20989
21565
  attachTileflowMapLifecycle,
20990
21566
  attachTileflowNauticalLights,