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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -3802,19 +3802,19 @@ function deriveGlyph(glyph, metrics) {
3802
3802
  const bitmap = new Uint8Array(width * rows);
3803
3803
  for (let row = 0; row < rows; row++) {
3804
3804
  const y = y0 + row + 0.5;
3805
- for (let column = 0; column < width; column++) {
3806
- const x = x0 + column + 0.5;
3805
+ for (let column2 = 0; column2 < width; column2++) {
3806
+ const x = x0 + column2 + 0.5;
3807
3807
  const distance = Math.min(x - cell.x0, cell.x1 - x, y - cell.y0, cell.y1 - y);
3808
3808
  const background = Math.min(CELL_VALUE, Math.max(0, CELL_EDGE + CELL_SLOPE * distance));
3809
3809
  let letter = 0;
3810
3810
  if (hasBitmap) {
3811
- const sourceColumn = x0 + column - sourceX;
3811
+ const sourceColumn = x0 + column2 - sourceX;
3812
3812
  const sourceRow = y0 + row - sourceY;
3813
3813
  if (sourceColumn >= 0 && sourceColumn < sourceWidth && sourceRow >= 0 && sourceRow < sourceHeight) {
3814
3814
  letter = glyph.bitmap[sourceRow * sourceWidth + sourceColumn];
3815
3815
  }
3816
3816
  }
3817
- bitmap[row * width + column] = Math.round(Math.max(letter, background));
3817
+ bitmap[row * width + column2] = Math.round(Math.max(letter, background));
3818
3818
  }
3819
3819
  }
3820
3820
  return {
@@ -13573,6 +13573,12 @@ var tileflowModelParts = Object.freeze({
13573
13573
  accent: 3,
13574
13574
  roof: 4
13575
13575
  });
13576
+ var tileflowModelArchitecturalPartNames = Object.freeze(
13577
+ Object.keys(tileflowModelParts)
13578
+ );
13579
+ function isTileflowModelPartName(value) {
13580
+ return typeof value === "string" && value.length <= 32 && /^[a-z][a-z0-9]*(?:[-_][a-z0-9]+)*$/u.test(value);
13581
+ }
13576
13582
  var tileflowModelLightingRoles = Object.freeze({
13577
13583
  unclassified: 0,
13578
13584
  wall: 1,
@@ -13582,7 +13588,16 @@ var tileflowModelLightingRoles = Object.freeze({
13582
13588
  lamp: 5,
13583
13589
  logo: 6
13584
13590
  });
13585
- var tileflowModelDefaultLightingRoles = Object.freeze([1, 1, 4, 1, 3]);
13591
+ var architecturalRoles = {
13592
+ surface: 1,
13593
+ secondary: 1,
13594
+ glass: 4,
13595
+ accent: 1,
13596
+ roof: 3
13597
+ };
13598
+ function tileflowModelDefaultLightingRole(part) {
13599
+ return Object.hasOwn(architecturalRoles, part) ? architecturalRoles[part] : tileflowModelLightingRoles.unclassified;
13600
+ }
13586
13601
  var tileflowModelLimits = Object.freeze({
13587
13602
  /** Levels of detail, nearest first. */
13588
13603
  levels: 3,
@@ -13599,7 +13614,9 @@ var tileflowModelLimits = Object.freeze({
13599
13614
  /** Models in one prepared file, as a landmark tile holds them. */
13600
13615
  models: 512,
13601
13616
  /** Bytes of one prepared file. */
13602
- bytes: 16 * 1024 * 1024
13617
+ bytes: 16 * 1024 * 1024,
13618
+ /** Differently named parts of one level. */
13619
+ parts: 16
13603
13620
  });
13604
13621
  var tileflowModelVertexBytes = 16;
13605
13622
  function tileflowInsideRings(rings, px, py) {
@@ -13887,8 +13904,8 @@ function modelsOf(value) {
13887
13904
  function modelColorsOf(value) {
13888
13905
  if (!isRecord7(value)) return {};
13889
13906
  const colors = {};
13890
- for (const part of Object.keys(tileflowModelParts))
13891
- if (typeof value[part] === "string") colors[part] = value[part];
13907
+ for (const [part, color3] of Object.entries(value))
13908
+ if (isTileflowModelPartName(part) && typeof color3 === "string") colors[part] = color3;
13892
13909
  return Object.keys(colors).length > 0 ? { modelColors: colors } : {};
13893
13910
  }
13894
13911
  function landmarksOf(value) {
@@ -14317,7 +14334,7 @@ function limitError(message) {
14317
14334
  return new Error(site ? `${message} Called at ${site}.` : message);
14318
14335
  }
14319
14336
  function authoringCallSite(stack) {
14320
- const locations = (stack ?? "").split("\n").slice(1).map((line) => /\(?([^()\s]+?):(\d+):(\d+)\)?$/.exec(line.trim())).filter((match3) => match3 !== null).map(([, file, line, column]) => ({ file: file.replace(/^file:\/\//, ""), line, column }));
14337
+ const locations = (stack ?? "").split("\n").slice(1).map((line) => /\(?([^()\s]+?):(\d+):(\d+)\)?$/.exec(line.trim())).filter((match3) => match3 !== null).map(([, file, line, column2]) => ({ file: file.replace(/^file:\/\//, ""), line, column: column2 }));
14321
14338
  const own = locations[0]?.file;
14322
14339
  const site = locations.find(({ file }) => file !== own && !file.startsWith("node:"));
14323
14340
  return site ? `${site.file}:${site.line}:${site.column}` : void 0;
@@ -17392,13 +17409,14 @@ var buildingsModuleSchema = z7.object({
17392
17409
  }).optional()
17393
17410
  }).strict()
17394
17411
  ).max(256).optional(),
17395
- modelColors: z7.object({
17396
- surface: themeColorValueSchema.optional(),
17397
- secondary: themeColorValueSchema.optional(),
17398
- glass: themeColorValueSchema.optional(),
17399
- accent: themeColorValueSchema.optional(),
17400
- roof: themeColorValueSchema.optional()
17401
- }).strict().optional(),
17412
+ modelColors: z7.record(
17413
+ z7.string().refine(isTileflowModelPartName, {
17414
+ message: "A model part is named in lower-case words joined by hyphens or underscores, at most 32 characters."
17415
+ }),
17416
+ themeColorValueSchema
17417
+ ).refine((colors) => Object.keys(colors).length <= 64, {
17418
+ message: "A map colours at most 64 model parts."
17419
+ }).optional(),
17402
17420
  landmarks: z7.union([
17403
17421
  z7.boolean(),
17404
17422
  z7.object({
@@ -20622,7 +20640,7 @@ function placedModels(value, served) {
20622
20640
  throw new Error(
20623
20641
  `The buildings module places missing 3D models: ${missing.join(", ")}. Add ${missing.map((id2) => `${id2}.glb`).join(
20624
20642
  ", "
20625
- )} to a map.models directory, with materials named surface, secondary, glass, accent or roof, and run the Node build so the directories are prepared.`
20643
+ )} to a map.models directory, with each material named after its part, such as surface, glass, roof or water, and run the Node build so the directories are prepared.`
20626
20644
  );
20627
20645
  return {
20628
20646
  models: placements.map((entry) => ({
@@ -22949,17 +22967,17 @@ function parseBoundaryLookupCsv(text) {
22949
22967
  );
22950
22968
  }
22951
22969
  const row = {};
22952
- header.forEach((column, position) => {
22970
+ header.forEach((column2, position) => {
22953
22971
  const cell = record4[position];
22954
- if (cell === "" || !lookupColumns.has(column)) return;
22955
- if (numericLookupColumns.has(column)) {
22972
+ if (cell === "" || !lookupColumns.has(column2)) return;
22973
+ if (numericLookupColumns.has(column2)) {
22956
22974
  const number = Number(cell);
22957
22975
  if (!Number.isSafeInteger(number)) {
22958
- throw new Error(`Boundaries lookup CSV row ${index + 2} has a non-integer ${column}.`);
22976
+ throw new Error(`Boundaries lookup CSV row ${index + 2} has a non-integer ${column2}.`);
22959
22977
  }
22960
- row[column] = number;
22978
+ row[column2] = number;
22961
22979
  } else {
22962
- row[column] = cell;
22980
+ row[column2] = cell;
22963
22981
  }
22964
22982
  });
22965
22983
  if (row.class_tier !== void 0 && !isClassTier(row.class_tier)) {
@@ -25196,6 +25214,7 @@ function checkTileflowModelSurface(surface, vertices, indices) {
25196
25214
  const value = attributes[i];
25197
25215
  if (!Number.isFinite(value) || Math.abs(value) > 65536) fail("unbounded vertex attributes");
25198
25216
  if (i % 8 >= 4 && (value < 0 || value > 1)) fail("vertex RGBA must be zero to one");
25217
+ if ((i % 8 === 2 || i % 8 === 3) && (value < 0 || value > 1)) fail("UV1 must be zero to one");
25199
25218
  }
25200
25219
  if (!Array.isArray(materials) || materials.length < 1 || materials.length > tileflowModelSurfaceLimits.materials)
25201
25220
  fail("material count exceeds the limit");
@@ -25277,7 +25296,7 @@ function checkTileflowModelSurface(surface, vertices, indices) {
25277
25296
  fail("emitter count exceeds the limit");
25278
25297
  for (const emitter of emitters) {
25279
25298
  if (!emitter || typeof emitter !== "object") fail("invalid area emitter");
25280
- if (!tuple(emitter.start, 3, -2e3, 2e3) || !tuple(emitter.end, 3, -2e3, 2e3) || !number(emitter.height, 0.01, 1e3) || emitter.depth !== void 0 && !number(emitter.depth, 0, 100) || !Object.hasOwn(tileflowModelLightingRoles, emitter.role) || !Object.hasOwn(tileflowModelParts, emitter.part))
25299
+ if (!tuple(emitter.start, 3, -2e3, 2e3) || !tuple(emitter.end, 3, -2e3, 2e3) || !number(emitter.height, 0.01, 1e3) || emitter.depth !== void 0 && !number(emitter.depth, 0, 100) || !Object.hasOwn(tileflowModelLightingRoles, emitter.role) || !isTileflowModelPartName(emitter.part))
25281
25300
  fail("invalid area emitter");
25282
25301
  if (Math.hypot(emitter.end[0] - emitter.start[0], emitter.end[1] - emitter.start[1]) < 1e-3 || Math.abs(emitter.end[2] - emitter.start[2]) > 0.01)
25283
25302
  fail("an area emitter needs a horizontal lower edge");
@@ -25320,7 +25339,6 @@ var levelNames = ["near", "mid", "far"];
25320
25339
  var meshopt = "EXT_meshopt_compression";
25321
25340
  var quantisation = "KHR_mesh_quantization";
25322
25341
  var steps = 32767;
25323
- var partCount2 = Object.keys(tileflowModelParts).length;
25324
25342
  var roleCount = Object.keys(tileflowModelLightingRoles).length;
25325
25343
  var modelId2 = /^[a-z0-9]+(?:-[a-z0-9]+)*$/u;
25326
25344
  var [glbMagic, jsonChunk, binChunk] = [1179937895, 1313821514, 5130562];
@@ -25459,20 +25477,33 @@ function encodeTileflowModels(models, compressor) {
25459
25477
  let surface;
25460
25478
  if (mesh.surface && level.attributes) {
25461
25479
  const attributes = level.attributes;
25462
- const data = new Uint8Array(
25463
- attributes.buffer,
25464
- attributes.byteOffset,
25465
- attributes.byteLength
25466
- );
25467
- const view = addView(data, level.count, 32, true);
25468
25480
  const uv = accessors.length;
25481
+ const rest = new Float32Array(level.count * 6);
25482
+ const second = new Uint16Array(level.count * 2);
25483
+ for (let vertex = 0; vertex < level.count; vertex++) {
25484
+ const at = vertex * 8;
25485
+ rest.set([attributes[at], attributes[at + 1]], vertex * 6);
25486
+ rest.set(attributes.subarray(at + 4, at + 8), vertex * 6 + 2);
25487
+ second[vertex * 2] = Math.round(attributes[at + 2] * 65535);
25488
+ second[vertex * 2 + 1] = Math.round(attributes[at + 3] * 65535);
25489
+ }
25490
+ const view = addView(new Uint8Array(rest.buffer), level.count, 24, true);
25491
+ const lightmap = addView(new Uint8Array(second.buffer), level.count, 4, true);
25469
25492
  accessors.push(
25470
- { bufferView: view, byteOffset: 0, componentType: 5126, count: level.count, type: "VEC4" },
25471
- { bufferView: view, byteOffset: 16, componentType: 5126, count: level.count, type: "VEC4" }
25493
+ { bufferView: view, byteOffset: 0, componentType: 5126, count: level.count, type: "VEC2" },
25494
+ {
25495
+ bufferView: lightmap,
25496
+ byteOffset: 0,
25497
+ componentType: 5123,
25498
+ normalized: true,
25499
+ count: level.count,
25500
+ type: "VEC2"
25501
+ },
25502
+ { bufferView: view, byteOffset: 8, componentType: 5126, count: level.count, type: "VEC4" }
25472
25503
  );
25473
25504
  surface = {
25474
- version: 1,
25475
- attributes: [uv, uv + 1],
25505
+ version: 2,
25506
+ attributes: [uv, uv + 1, uv + 2],
25476
25507
  materials: mesh.surface.materials,
25477
25508
  textures: mesh.surface.textures.map(({ bytes, ...texture }) => ({
25478
25509
  ...texture,
@@ -25489,7 +25520,7 @@ function encodeTileflowModels(models, compressor) {
25489
25520
  mesh: meshes.length - 1,
25490
25521
  translation: [...level.centre],
25491
25522
  scale: [level.step, level.step, level.step],
25492
- ...surface ? { extras: { tileflow: { surface } } } : {}
25523
+ extras: { tileflow: { parts: [...partNamesOf(mesh)], ...surface ? { surface } : {} } }
25493
25524
  });
25494
25525
  }
25495
25526
  roots.push(nodes.length);
@@ -25559,7 +25590,7 @@ async function decodeTileflowModels(buffer, decompressor) {
25559
25590
  if (source !== 0 || byteStride !== stride || count * byteStride !== length)
25560
25591
  throw new Error();
25561
25592
  if (filter !== void 0 && filter !== "NONE") throw new Error();
25562
- if (mode !== (stride > 4 ? "ATTRIBUTES" : "TRIANGLES")) throw new Error();
25593
+ if (mode !== (view.target === 34963 ? "TRIANGLES" : "ATTRIBUTES")) throw new Error();
25563
25594
  out = new Uint8Array(length);
25564
25595
  decoder.decodeGltfBuffer(out, count, byteStride, slice(bin, byteOffset, byteLength), mode);
25565
25596
  } else {
@@ -25598,6 +25629,7 @@ async function decodeTileflowModels(buffer, decompressor) {
25598
25629
  }
25599
25630
  levels.push({
25600
25631
  vertices: level.vertices,
25632
+ partNames: level.partNames,
25601
25633
  indices: level.indices,
25602
25634
  centre: level.centre,
25603
25635
  step: level.step,
@@ -25752,6 +25784,7 @@ function quantise(mesh, compressor) {
25752
25784
  ...low.map((value, axis) => Math.max(centre[axis] - value, high[axis] - centre[axis]))
25753
25785
  );
25754
25786
  const step2 = Math.max(reach, 1e-3) / steps;
25787
+ const names = partNamesOf(mesh);
25755
25788
  const raw = new Uint8Array(count * tileflowModelVertexBytes);
25756
25789
  const view = new DataView(raw.buffer);
25757
25790
  for (let vertex = 0; vertex < count; vertex += 1) {
@@ -25773,12 +25806,12 @@ function quantise(mesh, compressor) {
25773
25806
  for (let axis = 0; axis < 3; axis += 1)
25774
25807
  view.setInt8(at + 8 + axis, clamp3(Math.round(normal[axis] * 127), -127, 127));
25775
25808
  const part = mesh.parts[vertex];
25776
- if (!Number.isInteger(part) || part < 0 || part >= partCount2)
25809
+ if (!Number.isInteger(part) || part < 0 || part >= names.length)
25777
25810
  throw new RangeError(`Vertex ${vertex} has no part.`);
25778
25811
  raw[at + 12] = part;
25779
25812
  raw[at + 13] = Math.round((clamp3(mesh.shades[vertex], -1, 1) + 1) / 2 * 255);
25780
25813
  raw[at + 14] = Math.round(clamp3(mesh.occlusion[vertex], 0, 1) * 255);
25781
- const role = mesh.lightingRoles?.[vertex] ?? tileflowModelDefaultLightingRoles[part];
25814
+ const role = mesh.lightingRoles?.[vertex] ?? tileflowModelDefaultLightingRole(names[part]);
25782
25815
  if (!Number.isInteger(role) || role < 0 || role >= roleCount)
25783
25816
  throw new RangeError(`Vertex ${vertex} has no lighting role.`);
25784
25817
  raw[at + 15] = role;
@@ -25861,6 +25894,10 @@ function checkModel(model) {
25861
25894
  throw new RangeError(`Every vertex of level ${at} needs a part, a shade and a light.`);
25862
25895
  if (level.lightingRoles && level.lightingRoles.length !== count)
25863
25896
  throw new RangeError(`Every vertex of level ${at} needs a lighting role.`);
25897
+ if (!isPartNames(partNamesOf(level)))
25898
+ throw new RangeError(
25899
+ `Level ${at} names 1 to ${tileflowModelLimits.parts} different parts, each in lower-case words joined by hyphens or underscores.`
25900
+ );
25864
25901
  if (level.surface) checkTileflowModelSurface(level.surface, count, level.indices.length);
25865
25902
  for (let index = 0; index < count; index += 1)
25866
25903
  for (let axis = 0; axis < 3; axis += 1) {
@@ -25949,6 +25986,9 @@ function readLevelNode(json, node2, name, viewBytes, hasLightingRoles) {
25949
25986
  const indexCount = index?.count;
25950
25987
  if (!width || index.type !== "SCALAR" || (index.byteOffset ?? 0) !== 0 || !Number.isInteger(indexCount) || indexCount < 3 || indexCount % 3 !== 0 || indexCount / 3 > tileflowModelLimits.triangles)
25951
25988
  throw new Error();
25989
+ const own = node2.extras?.tileflow?.parts;
25990
+ const partNames = own === void 0 ? tileflowModelArchitecturalPartNames : own;
25991
+ if (!isPartNames(partNames)) throw new Error();
25952
25992
  const vertices = viewBytes(
25953
25993
  position.bufferView,
25954
25994
  tileflowModelVertexBytes,
@@ -25957,8 +25997,8 @@ function readLevelNode(json, node2, name, viewBytes, hasLightingRoles) {
25957
25997
  for (let vertex = 0; vertex < count; vertex += 1) {
25958
25998
  const at = vertex * tileflowModelVertexBytes;
25959
25999
  const part = vertices[at + 12];
25960
- if (part >= partCount2) throw new Error();
25961
- if (!hasLightingRoles) vertices[at + 15] = tileflowModelDefaultLightingRoles[part];
26000
+ if (part >= partNames.length) throw new Error();
26001
+ if (!hasLightingRoles) vertices[at + 15] = tileflowModelDefaultLightingRole(partNames[part]);
25962
26002
  else if (vertices[at + 15] >= roleCount) throw new Error();
25963
26003
  }
25964
26004
  const indexBytes = viewBytes(index.bufferView, width, indexCount * width);
@@ -25967,18 +26007,30 @@ function readLevelNode(json, node2, name, viewBytes, hasLightingRoles) {
25967
26007
  const physical = node2.extras?.tileflow?.surface;
25968
26008
  let surface;
25969
26009
  if (physical !== void 0) {
25970
- if (physical?.version !== 1 || !Array.isArray(physical.attributes) || physical.attributes.length !== 2)
26010
+ if (physical?.version !== 2 || !Array.isArray(physical.attributes) || physical.attributes.length !== 3)
25971
26011
  throw new Error();
25972
- const uv = accessor(physical.attributes[0]);
25973
- const colour = accessor(physical.attributes[1]);
25974
- if (!uv || !colour || (uv.byteOffset ?? 0) !== 0 || colour.byteOffset !== 16 || uv.bufferView !== colour.bufferView || [uv, colour].some(
25975
- (value) => value.componentType !== 5126 || value.type !== "VEC4" || value.count !== count || value.normalized === true
25976
- ))
26012
+ const [uv, lightmap, colour] = physical.attributes.map(accessor);
26013
+ if (!uv || !lightmap || !colour || (uv.byteOffset ?? 0) !== 0 || colour.byteOffset !== 8 || (lightmap.byteOffset ?? 0) !== 0 || uv.bufferView !== colour.bufferView || uv.bufferView === lightmap.bufferView || uv.componentType !== 5126 || uv.type !== "VEC2" || colour.componentType !== 5126 || colour.type !== "VEC4" || lightmap.componentType !== 5123 || lightmap.type !== "VEC2" || lightmap.normalized !== true || [uv, lightmap, colour].some((value) => value.count !== count))
25977
26014
  throw new Error();
25978
- const attributeBytes = viewBytes(uv.bufferView, 32, count * 32);
26015
+ const restBytes = viewBytes(uv.bufferView, 24, count * 24);
26016
+ const lightmapBytes = viewBytes(lightmap.bufferView, 4, count * 4);
26017
+ const rest = new Float32Array(
26018
+ restBytes.buffer.slice(restBytes.byteOffset, restBytes.byteOffset + count * 24)
26019
+ );
26020
+ const second = new Uint16Array(
26021
+ lightmapBytes.buffer.slice(lightmapBytes.byteOffset, lightmapBytes.byteOffset + count * 4)
26022
+ );
26023
+ const attributes = new Float32Array(count * 8);
26024
+ for (let vertex = 0; vertex < count; vertex++) {
26025
+ const at = vertex * 8;
26026
+ attributes[at] = rest[vertex * 6];
26027
+ attributes[at + 1] = rest[vertex * 6 + 1];
26028
+ attributes[at + 2] = second[vertex * 2] / 65535;
26029
+ attributes[at + 3] = second[vertex * 2 + 1] / 65535;
26030
+ attributes.set(rest.subarray(vertex * 6 + 2, vertex * 6 + 6), at + 4);
26031
+ }
25979
26032
  if (!Array.isArray(physical.textures) || physical.textures.length > 32) throw new Error();
25980
- surface = {
25981
- attributes: new Float32Array(attributeBytes.buffer, attributeBytes.byteOffset, count * 8),
26033
+ const read = {
25982
26034
  materials: physical.materials,
25983
26035
  ranges: physical.ranges,
25984
26036
  textures: physical.textures.map((texture) => {
@@ -25989,10 +26041,12 @@ function readLevelNode(json, node2, name, viewBytes, hasLightingRoles) {
25989
26041
  }),
25990
26042
  ...physical.emitters === void 0 ? {} : { emitters: physical.emitters }
25991
26043
  };
25992
- checkTileflowModelSurface(surface, count, indexCount);
26044
+ checkTileflowModelSurface({ ...read, attributes }, count, indexCount);
26045
+ surface = { ...read, uv: column(attributes, 0), rgba: column(attributes, 4) };
25993
26046
  }
25994
26047
  return {
25995
26048
  vertices,
26049
+ partNames: [...partNames],
25996
26050
  indices,
25997
26051
  centre: [centre[0], centre[1], centre[2]],
25998
26052
  step: scale[0],
@@ -26001,6 +26055,24 @@ function readLevelNode(json, node2, name, viewBytes, hasLightingRoles) {
26001
26055
  surface
26002
26056
  };
26003
26057
  }
26058
+ function column(attributes, first) {
26059
+ const out = attributes.slice(first, first + 4);
26060
+ for (let at = 8 + first; at < attributes.length; at += 8)
26061
+ for (let component = 0; component < 4; component += 1)
26062
+ if (attributes[at + component] !== out[component]) {
26063
+ const all2 = new Float32Array(attributes.length / 2);
26064
+ for (let vertex = 0; vertex < all2.length / 4; vertex += 1)
26065
+ all2.set(attributes.subarray(vertex * 8 + first, vertex * 8 + first + 4), vertex * 4);
26066
+ return all2;
26067
+ }
26068
+ return out;
26069
+ }
26070
+ function partNamesOf(mesh) {
26071
+ return mesh.partNames ?? tileflowModelArchitecturalPartNames;
26072
+ }
26073
+ function isPartNames(names) {
26074
+ return Array.isArray(names) && names.length >= 1 && names.length <= tileflowModelLimits.parts && names.every(isTileflowModelPartName) && new Set(names).size === names.length;
26075
+ }
26004
26076
  function readGlb(bytes) {
26005
26077
  if (bytes.byteLength < 20 || bytes.byteLength > tileflowModelLimits.bytes) throw new Error();
26006
26078
  const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
@@ -26150,8 +26222,7 @@ function validFootprint(footprint) {
26150
26222
  }
26151
26223
  function readTileflowLandmarkRegion(json) {
26152
26224
  if (!isRecord18(json)) return void 0;
26153
- const named = json.format === "tileflow-landmark-region-v2";
26154
- if (!named && json.format !== "tileflow-landmark-region-v1") return void 0;
26225
+ if (json.format !== "tileflow-landmark-region-v2") return void 0;
26155
26226
  const region = json.region;
26156
26227
  if (json.zoom !== tileflowLandmarkTileZoom || !Array.isArray(region) || region.length !== 3 || region[0] !== tileflowLandmarkRegionZoom || !Array.isArray(json.tiles))
26157
26228
  return void 0;
@@ -26159,17 +26230,13 @@ function readTileflowLandmarkRegion(json) {
26159
26230
  if (!Number.isInteger(x) || !Number.isInteger(y)) return void 0;
26160
26231
  const tiles = [];
26161
26232
  for (const tile of json.tiles) {
26162
- if (!Array.isArray(tile) || tile.length !== (named ? 4 : 3)) return void 0;
26233
+ if (!Array.isArray(tile) || tile.length !== 4) return void 0;
26163
26234
  const [tx, ty, hash, listed] = tile;
26164
26235
  if (!Number.isInteger(tx) || !Number.isInteger(ty) || typeof hash !== "string")
26165
26236
  return void 0;
26166
26237
  if (!sha256.test(hash)) return void 0;
26167
26238
  const [rx, ry] = tileflowLandmarkRegionOf([tx, ty]);
26168
26239
  if (rx !== x || ry !== y) return void 0;
26169
- if (!named) {
26170
- tiles.push([tx, ty, hash]);
26171
- continue;
26172
- }
26173
26240
  const landmarks = readLandmarks(listed, tx, ty);
26174
26241
  if (!landmarks) return void 0;
26175
26242
  tiles.push([tx, ty, hash, landmarks]);
@@ -26298,6 +26365,7 @@ export {
26298
26365
  isTileflowCompilationPhase,
26299
26366
  isTileflowIconSetSource,
26300
26367
  isTileflowLocalDirectory,
26368
+ isTileflowModelPartName,
26301
26369
  isTileflowPortableId,
26302
26370
  isTileflowThemeName,
26303
26371
  isTileflowTimeOfDay,
@@ -26473,8 +26541,9 @@ export {
26473
26541
  tileflowMapDefaultMaxDepth,
26474
26542
  tileflowMapIdSchema,
26475
26543
  tileflowMaxPitch,
26544
+ tileflowModelArchitecturalPartNames,
26476
26545
  tileflowModelContentType,
26477
- tileflowModelDefaultLightingRoles,
26546
+ tileflowModelDefaultLightingRole,
26478
26547
  tileflowModelFileName,
26479
26548
  tileflowModelImageSize,
26480
26549
  tileflowModelLightingRoles,