@woosh/meep-engine 2.163.2 → 2.163.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/package.json +1 -1
  2. package/src/core/geom/3d/equirectangular/equirectangular_direction_to_uv.d.ts +12 -0
  3. package/src/core/geom/3d/equirectangular/equirectangular_direction_to_uv.d.ts.map +1 -0
  4. package/src/core/geom/3d/equirectangular/equirectangular_direction_to_uv.js +18 -0
  5. package/src/core/geom/3d/equirectangular/equirectangular_uv_to_direction.d.ts +14 -0
  6. package/src/core/geom/3d/equirectangular/equirectangular_uv_to_direction.d.ts.map +1 -0
  7. package/src/core/geom/3d/equirectangular/equirectangular_uv_to_direction.js +24 -0
  8. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_face_island_erode.d.ts.map +1 -1
  9. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_face_island_erode.js +368 -290
  10. package/src/core/geom/vec3/v3_uniform_sample_cone.d.ts +11 -0
  11. package/src/core/geom/vec3/v3_uniform_sample_cone.d.ts.map +1 -0
  12. package/src/core/geom/vec3/v3_uniform_sample_cone.js +21 -0
  13. package/src/core/math/physics/brdf/cone_cosine_from_roughness.d.ts +13 -0
  14. package/src/core/math/physics/brdf/cone_cosine_from_roughness.d.ts.map +1 -0
  15. package/src/core/math/physics/brdf/cone_cosine_from_roughness.js +28 -0
  16. package/src/core/math/physics/brdf/reflection_sample_weight.d.ts +18 -0
  17. package/src/core/math/physics/brdf/reflection_sample_weight.d.ts.map +1 -0
  18. package/src/core/math/physics/brdf/reflection_sample_weight.js +48 -0
  19. package/src/engine/graphics/GraphicsEngine.d.ts.map +1 -1
  20. package/src/engine/graphics/GraphicsEngine.js +52 -0
  21. package/src/engine/graphics/sh3/sky/hosek/make_environment_sky_hosek.d.ts +26 -0
  22. package/src/engine/graphics/sh3/sky/hosek/make_environment_sky_hosek.d.ts.map +1 -0
  23. package/src/engine/graphics/sh3/sky/hosek/make_environment_sky_hosek.js +49 -0
  24. package/src/engine/graphics/sh3/sky/hosek/render_hosek_sky_to_equirectangular.d.ts +26 -0
  25. package/src/engine/graphics/sh3/sky/hosek/render_hosek_sky_to_equirectangular.d.ts.map +1 -0
  26. package/src/engine/graphics/sh3/sky/hosek/render_hosek_sky_to_equirectangular.js +70 -0
  27. package/src/engine/graphics/sh3/sky/hosek/setup_environment_sky_from_ecd.d.ts +24 -0
  28. package/src/engine/graphics/sh3/sky/hosek/setup_environment_sky_from_ecd.d.ts.map +1 -0
  29. package/src/engine/graphics/sh3/sky/hosek/setup_environment_sky_from_ecd.js +51 -0
  30. package/src/engine/graphics/texture/EnvironmentTextureProjection.d.ts +9 -0
  31. package/src/engine/graphics/texture/EnvironmentTextureProjection.d.ts.map +1 -0
  32. package/src/engine/graphics/texture/EnvironmentTextureProjection.js +15 -0
  33. package/src/engine/graphics/texture/reflection/convolve_equirectangular_reflection.d.ts +44 -0
  34. package/src/engine/graphics/texture/reflection/convolve_equirectangular_reflection.d.ts.map +1 -0
  35. package/src/engine/graphics/texture/reflection/convolve_equirectangular_reflection.js +189 -0
  36. package/src/engine/graphics/texture/reflection/equirectangular_reflection_roughness.d.ts +25 -0
  37. package/src/engine/graphics/texture/reflection/equirectangular_reflection_roughness.d.ts.map +1 -0
  38. package/src/engine/graphics/texture/reflection/equirectangular_reflection_roughness.js +51 -0
  39. package/src/engine/graphics/texture/sampler/sampler2d_sample_equirectangular_direction.d.ts +15 -0
  40. package/src/engine/graphics/texture/sampler/sampler2d_sample_equirectangular_direction.d.ts.map +1 -0
  41. package/src/engine/graphics/texture/sampler/sampler2d_sample_equirectangular_direction.js +63 -0
  42. package/src/engine/navigation/mesh/build/bt_mesh_carve_height_clearance.d.ts +28 -0
  43. package/src/engine/navigation/mesh/build/bt_mesh_carve_height_clearance.d.ts.map +1 -0
  44. package/src/engine/navigation/mesh/build/bt_mesh_carve_height_clearance.js +359 -0
  45. package/src/engine/navigation/mesh/build/navmesh_build_topology.d.ts.map +1 -1
  46. package/src/engine/navigation/mesh/build/navmesh_build_topology.js +224 -226
  47. package/src/engine/.fuse_hidden0000001500000001 +0 -581
@@ -0,0 +1,359 @@
1
+ import { NULL_NODE } from "../../../../core/bvh2/bvh3/BVH.js";
2
+ import {
3
+ bvh_query_leaves_ray_segment
4
+ } from "../../../../core/bvh2/bvh3/query/bvh_query_leaves_ray_segment.js";
5
+ import {
6
+ bvh_query_user_data_overlaps_aabb
7
+ } from "../../../../core/bvh2/bvh3/query/bvh_query_user_data_overlaps_aabb.js";
8
+ import { NULL_POINTER } from "../../../../core/geom/3d/topology/struct/binary/BinaryTopology.js";
9
+ import {
10
+ bt_mesh_cleanup_faceless_references
11
+ } from "../../../../core/geom/3d/topology/struct/binary/io/bt_mesh_cleanup_faceless_references.js";
12
+ import { bt_edge_split } from "../../../../core/geom/3d/topology/struct/binary/io/edge/bt_edge_split.js";
13
+ import { bt_face_kill } from "../../../../core/geom/3d/topology/struct/binary/io/face/bt_face_kill.js";
14
+ import {
15
+ computeTriangleRayIntersectionBarycentric
16
+ } from "../../../../core/geom/3d/triangle/computeTriangleRayIntersectionBarycentric.js";
17
+
18
+ /** Lift a ray origin off the surface so the upward clearance ray does not re-hit the floor. */
19
+ const SURFACE_EPSILON = 1e-4;
20
+
21
+ /** Safety cap on the face count during refinement. */
22
+ const MAX_FACES = 200000;
23
+
24
+ // reused scratch
25
+ const ray_leaf_buffer = [];
26
+ const intersection_result = new Float32Array(6);
27
+ const tri_a = new Float32Array(3);
28
+ const tri_b = new Float32Array(3);
29
+ const tri_c = new Float32Array(3);
30
+
31
+ const va = new Float32Array(3);
32
+ const vb = new Float32Array(3);
33
+ const vc = new Float32Array(3);
34
+
35
+ const overhead_hits = [];
36
+ const query_aabb = new Float32Array(6);
37
+ const scratch_normal = new Float32Array(3);
38
+
39
+ /** True if nothing in `source` sits directly above the point within `agent_height` (exact ray test). */
40
+ function point_has_clearance(source_bvh, source, px, py, pz, up_x, up_y, up_z, agent_height) {
41
+ const origin_x = px + up_x * SURFACE_EPSILON;
42
+ const origin_y = py + up_y * SURFACE_EPSILON;
43
+ const origin_z = pz + up_z * SURFACE_EPSILON;
44
+
45
+ const leaf_count = bvh_query_leaves_ray_segment(
46
+ source_bvh, source_bvh.root,
47
+ ray_leaf_buffer, 0,
48
+ origin_x, origin_y, origin_z,
49
+ up_x, up_y, up_z,
50
+ 0, agent_height
51
+ );
52
+
53
+ for (let i = 0; i < leaf_count; i++) {
54
+ const node = ray_leaf_buffer[i];
55
+ const face_id = source_bvh.node_get_user_data(node);
56
+
57
+ const loop_a = source.face_read_loop(face_id);
58
+ if (loop_a === NULL_POINTER) continue;
59
+
60
+ // Only DOWNWARD-facing geometry (a ceiling / overhang underside) can obstruct head clearance.
61
+ // Up-facing walkable floors above (a higher tier, a step the agent climbs) must NOT block.
62
+ source.face_read_normal(scratch_normal, 0, face_id);
63
+ if (scratch_normal[0] * up_x + scratch_normal[1] * up_y + scratch_normal[2] * up_z >= -1e-3) {
64
+ continue;
65
+ }
66
+
67
+ const loop_b = source.loop_read_next(loop_a);
68
+ const loop_c = source.loop_read_next(loop_b);
69
+
70
+ source.vertex_read_coordinate(tri_a, 0, source.loop_read_vertex(loop_a));
71
+ source.vertex_read_coordinate(tri_b, 0, source.loop_read_vertex(loop_b));
72
+ source.vertex_read_coordinate(tri_c, 0, source.loop_read_vertex(loop_c));
73
+
74
+ const hit = computeTriangleRayIntersectionBarycentric(
75
+ intersection_result,
76
+ origin_x, origin_y, origin_z,
77
+ up_x, up_y, up_z,
78
+ tri_a[0], tri_a[1], tri_a[2],
79
+ tri_b[0], tri_b[1], tri_b[2],
80
+ tri_c[0], tri_c[1], tri_c[2]
81
+ );
82
+ if (!hit) continue;
83
+
84
+ const t = intersection_result[0];
85
+ if (t > 0 && t <= agent_height) return false;
86
+ }
87
+
88
+ return true;
89
+ }
90
+
91
+ /**
92
+ * True if any source geometry sits above the point within `agent_height`, anywhere inside a horizontal
93
+ * disc of radius `r` (approximated by an axis-aligned box). Used to dilate the obstacle footprint by
94
+ * the agent radius - the agent's body cannot occupy a spot whose `r`-neighbourhood is overhung.
95
+ */
96
+ function overhead_within_radius(source_bvh, source, px, py, pz, up_x, up_y, up_z, agent_height, r) {
97
+ const p_along_up = px * up_x + py * up_y + pz * up_z;
98
+
99
+ // expand on the axes perpendicular to up by r, then sweep up by agent_height
100
+ const ex = r * (1 - Math.abs(up_x));
101
+ const ey = r * (1 - Math.abs(up_y));
102
+ const ez = r * (1 - Math.abs(up_z));
103
+
104
+ let min_x = px - ex, min_y = py - ey, min_z = pz - ez;
105
+ let max_x = px + ex, max_y = py + ey, max_z = pz + ez;
106
+
107
+ const dx = up_x * agent_height, dy = up_y * agent_height, dz = up_z * agent_height;
108
+ if (dx > 0) max_x += dx; else min_x += dx;
109
+ if (dy > 0) max_y += dy; else min_y += dy;
110
+ if (dz > 0) max_z += dz; else min_z += dz;
111
+
112
+ query_aabb[0] = min_x; query_aabb[1] = min_y; query_aabb[2] = min_z;
113
+ query_aabb[3] = max_x; query_aabb[4] = max_y; query_aabb[5] = max_z;
114
+
115
+ const count = bvh_query_user_data_overlaps_aabb(overhead_hits, 0, source_bvh, query_aabb);
116
+
117
+ for (let i = 0; i < count; i++) {
118
+ const fid = overhead_hits[i];
119
+ const la = source.face_read_loop(fid);
120
+ if (la === NULL_POINTER) continue;
121
+
122
+ // only downward-facing geometry counts as an overhang (see point_has_clearance)
123
+ source.face_read_normal(scratch_normal, 0, fid);
124
+ if (scratch_normal[0] * up_x + scratch_normal[1] * up_y + scratch_normal[2] * up_z >= -1e-3) {
125
+ continue;
126
+ }
127
+
128
+ const lb = source.loop_read_next(la);
129
+ const lc = source.loop_read_next(lb);
130
+
131
+ source.vertex_read_coordinate(tri_a, 0, source.loop_read_vertex(la));
132
+ source.vertex_read_coordinate(tri_b, 0, source.loop_read_vertex(lb));
133
+ source.vertex_read_coordinate(tri_c, 0, source.loop_read_vertex(lc));
134
+
135
+ const cand_min_along_up = Math.min(
136
+ tri_a[0] * up_x + tri_a[1] * up_y + tri_a[2] * up_z,
137
+ tri_b[0] * up_x + tri_b[1] * up_y + tri_b[2] * up_z,
138
+ tri_c[0] * up_x + tri_c[1] * up_y + tri_c[2] * up_z
139
+ );
140
+
141
+ if (cand_min_along_up > p_along_up + 1e-3 && cand_min_along_up <= p_along_up + agent_height + 1e-3) {
142
+ return true;
143
+ }
144
+ }
145
+
146
+ return false;
147
+ }
148
+
149
+ /**
150
+ * Does the column over this face's footprint (inflated horizontally by `pad`) contain any DOWNWARD-
151
+ * facing geometry above it within `agent_height`? Footprint-wide (not just the centroid), so an
152
+ * obstacle sitting anywhere under a large face is detected and the face is refined toward it.
153
+ */
154
+ function footprint_has_overhead(source_bvh, source, up_x, up_y, up_z, agent_height, pad) {
155
+ const face_max_along_up = Math.max(
156
+ va[0] * up_x + va[1] * up_y + va[2] * up_z,
157
+ vb[0] * up_x + vb[1] * up_y + vb[2] * up_z,
158
+ vc[0] * up_x + vc[1] * up_y + vc[2] * up_z
159
+ );
160
+
161
+ let min_x = Math.min(va[0], vb[0], vc[0]) - pad;
162
+ let min_y = Math.min(va[1], vb[1], vc[1]) - pad;
163
+ let min_z = Math.min(va[2], vb[2], vc[2]) - pad;
164
+ let max_x = Math.max(va[0], vb[0], vc[0]) + pad;
165
+ let max_y = Math.max(va[1], vb[1], vc[1]) + pad;
166
+ let max_z = Math.max(va[2], vb[2], vc[2]) + pad;
167
+
168
+ const dx = up_x * agent_height, dy = up_y * agent_height, dz = up_z * agent_height;
169
+ if (dx > 0) max_x += dx; else min_x += dx;
170
+ if (dy > 0) max_y += dy; else min_y += dy;
171
+ if (dz > 0) max_z += dz; else min_z += dz;
172
+
173
+ query_aabb[0] = min_x; query_aabb[1] = min_y; query_aabb[2] = min_z;
174
+ query_aabb[3] = max_x; query_aabb[4] = max_y; query_aabb[5] = max_z;
175
+
176
+ const count = bvh_query_user_data_overlaps_aabb(overhead_hits, 0, source_bvh, query_aabb);
177
+
178
+ for (let i = 0; i < count; i++) {
179
+ const fid = overhead_hits[i];
180
+ const la = source.face_read_loop(fid);
181
+ if (la === NULL_POINTER) continue;
182
+
183
+ source.face_read_normal(scratch_normal, 0, fid);
184
+ if (scratch_normal[0] * up_x + scratch_normal[1] * up_y + scratch_normal[2] * up_z >= -1e-3) {
185
+ continue;
186
+ }
187
+
188
+ const lb = source.loop_read_next(la);
189
+ const lc = source.loop_read_next(lb);
190
+ source.vertex_read_coordinate(tri_a, 0, source.loop_read_vertex(la));
191
+ source.vertex_read_coordinate(tri_b, 0, source.loop_read_vertex(lb));
192
+ source.vertex_read_coordinate(tri_c, 0, source.loop_read_vertex(lc));
193
+
194
+ const cand_min_along_up = Math.min(
195
+ tri_a[0] * up_x + tri_a[1] * up_y + tri_a[2] * up_z,
196
+ tri_b[0] * up_x + tri_b[1] * up_y + tri_b[2] * up_z,
197
+ tri_c[0] * up_x + tri_c[1] * up_y + tri_c[2] * up_z
198
+ );
199
+
200
+ if (cand_min_along_up > face_max_along_up + 1e-3) {
201
+ return true;
202
+ }
203
+ }
204
+
205
+ return false;
206
+ }
207
+
208
+ function read_face_triangle(mesh, face_id) {
209
+ const la = mesh.face_read_loop(face_id);
210
+ const lb = mesh.loop_read_next(la);
211
+ const lc = mesh.loop_read_next(lb);
212
+
213
+ mesh.vertex_read_coordinate(va, 0, mesh.loop_read_vertex(la));
214
+ mesh.vertex_read_coordinate(vb, 0, mesh.loop_read_vertex(lb));
215
+ mesh.vertex_read_coordinate(vc, 0, mesh.loop_read_vertex(lc));
216
+
217
+ return { la, lb, lc };
218
+ }
219
+
220
+ /**
221
+ * Carve holes into a (welded) walkable topology wherever an agent of the given height+radius would not
222
+ * fit under overhead geometry. INTENDED TO RUN AFTER the agent-radius boundary erosion: the boundary is
223
+ * already handled, so this only removes the obstacle footprints (dilated by the agent radius).
224
+ *
225
+ * All subdivision is conformal ({@link bt_edge_split} re-triangulates every face around a split edge),
226
+ * and culling whole faces ({@link bt_face_kill}) never cracks neighbours - so this cannot disconnect a
227
+ * passable region. Refinement is tight: faces straddling the (dilated) obstacle outline are refined to
228
+ * `resolution`; a still-large all-clear face whose column has overhead is refined down to a coarse
229
+ * guard so a small obstacle cannot hide unsampled; everything else stays coarse.
230
+ *
231
+ * @param {object} params
232
+ * @param {BinaryTopology} params.mesh walkable topology to carve (modified in place)
233
+ * @param {BinaryTopology} params.source original source mesh (walkable + overhead geometry)
234
+ * @param {BVH} params.source_bvh BVH over `source`
235
+ * @param {number} params.agent_height
236
+ * @param {number} params.agent_radius
237
+ * @param {Vector3} params.up world up direction
238
+ */
239
+ export function bt_mesh_carve_height_clearance({
240
+ mesh,
241
+ source,
242
+ source_bvh,
243
+ agent_height,
244
+ agent_radius,
245
+ up,
246
+ }) {
247
+
248
+ if (agent_height <= 0 || source_bvh.root === NULL_NODE) return;
249
+
250
+ let up_x = up.x, up_y = up.y, up_z = up.z;
251
+ const up_len = Math.sqrt(up_x * up_x + up_y * up_y + up_z * up_z);
252
+ if (up_len === 0) return;
253
+ up_x /= up_len; up_y /= up_len; up_z /= up_len;
254
+
255
+ const r = Math.max(agent_radius, 0);
256
+ const resolution = Math.max(agent_radius > 0 ? agent_radius : agent_height / 4, 0.3);
257
+ const coarse_guard = Math.max(2 * agent_radius, agent_height / 2, 0.8);
258
+ const res_sq = resolution * resolution;
259
+ const guard_sq = coarse_guard * coarse_guard;
260
+
261
+ // The agent fits at p iff nothing overhangs directly above it AND nothing overhangs within its body
262
+ // radius. (For r == 0 this is just the exact overhead ray.)
263
+ function agent_fits(px, py, pz) {
264
+ if (!point_has_clearance(source_bvh, source, px, py, pz, up_x, up_y, up_z, agent_height)) {
265
+ return false;
266
+ }
267
+ if (r > 0 && overhead_within_radius(source_bvh, source, px, py, pz, up_x, up_y, up_z, agent_height, r)) {
268
+ return false;
269
+ }
270
+ return true;
271
+ }
272
+
273
+ // ---- Phase 1: tight, conformal refinement around the (dilated) obstacle outline ----
274
+ let changed = true;
275
+ let guard = 0;
276
+
277
+ while (changed && guard < 64) {
278
+ changed = false;
279
+ guard++;
280
+
281
+ const face_count = mesh.faces.size;
282
+
283
+ for (let f = 0; f < face_count; f++) {
284
+ if (!mesh.faces.is_allocated(f)) continue;
285
+
286
+ read_face_triangle(mesh, f);
287
+
288
+ const ab = (va[0] - vb[0]) ** 2 + (va[1] - vb[1]) ** 2 + (va[2] - vb[2]) ** 2;
289
+ const bc = (vb[0] - vc[0]) ** 2 + (vb[1] - vc[1]) ** 2 + (vb[2] - vc[2]) ** 2;
290
+ const ca = (vc[0] - va[0]) ** 2 + (vc[1] - va[1]) ** 2 + (vc[2] - va[2]) ** 2;
291
+ const longest_sq = Math.max(ab, bc, ca);
292
+
293
+ if (longest_sq <= res_sq) continue;
294
+
295
+ const mab_x = (va[0] + vb[0]) * 0.5, mab_y = (va[1] + vb[1]) * 0.5, mab_z = (va[2] + vb[2]) * 0.5;
296
+ const mbc_x = (vb[0] + vc[0]) * 0.5, mbc_y = (vb[1] + vc[1]) * 0.5, mbc_z = (vb[2] + vc[2]) * 0.5;
297
+ const mca_x = (vc[0] + va[0]) * 0.5, mca_y = (vc[1] + va[1]) * 0.5, mca_z = (vc[2] + va[2]) * 0.5;
298
+ const cx = (va[0] + vb[0] + vc[0]) / 3, cy = (va[1] + vb[1] + vc[1]) / 3, cz = (va[2] + vb[2] + vc[2]) / 3;
299
+
300
+ const samples = [
301
+ va[0], va[1], va[2], vb[0], vb[1], vb[2], vc[0], vc[1], vc[2],
302
+ mab_x, mab_y, mab_z, mbc_x, mbc_y, mbc_z, mca_x, mca_y, mca_z,
303
+ cx, cy, cz,
304
+ ];
305
+ let n_clear = 0, n_block = 0;
306
+ for (let s = 0; s < samples.length; s += 3) {
307
+ if (agent_fits(samples[s], samples[s + 1], samples[s + 2])) n_clear++; else n_block++;
308
+ }
309
+
310
+ let refine = false;
311
+ if (n_block > 0 && n_clear > 0) {
312
+ refine = true; // (dilated) outline crosses this face -> hug it at `resolution`
313
+ } else if (n_block === 0 && longest_sq > guard_sq) {
314
+ // all clear by sampling, but still large enough to hide an obstacle between samples:
315
+ // refine if any downward-facing overhang sits under the whole face footprint (+ radius)
316
+ if (footprint_has_overhead(source_bvh, source, up_x, up_y, up_z, agent_height, r)) {
317
+ refine = true;
318
+ }
319
+ }
320
+ // n_clear === 0 (fully blocked): leave it for the cull phase
321
+
322
+ if (!refine) continue;
323
+
324
+ const { la, lb, lc } = read_face_triangle(mesh, f);
325
+ let split_loop;
326
+ if (longest_sq === ab) split_loop = la;
327
+ else if (longest_sq === bc) split_loop = lb;
328
+ else split_loop = lc;
329
+
330
+ bt_edge_split(mesh, mesh.loop_read_edge(split_loop), 0.5);
331
+ changed = true;
332
+ }
333
+
334
+ if (mesh.faces.size > MAX_FACES) break;
335
+ }
336
+
337
+ // ---- Phase 2: cull blocked faces (whole-face, conformal) ----
338
+ const faces_to_kill = [];
339
+ const face_count = mesh.faces.size;
340
+
341
+ for (let f = 0; f < face_count; f++) {
342
+ if (!mesh.faces.is_allocated(f)) continue;
343
+
344
+ read_face_triangle(mesh, f);
345
+ const cx = (va[0] + vb[0] + vc[0]) / 3;
346
+ const cy = (va[1] + vb[1] + vc[1]) / 3;
347
+ const cz = (va[2] + vb[2] + vc[2]) / 3;
348
+
349
+ if (!agent_fits(cx, cy, cz)) faces_to_kill.push(f);
350
+ }
351
+
352
+ for (let i = 0; i < faces_to_kill.length; i++) {
353
+ bt_face_kill(mesh, faces_to_kill[i]);
354
+ }
355
+
356
+ if (faces_to_kill.length > 0) {
357
+ bt_mesh_cleanup_faceless_references(mesh);
358
+ }
359
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"navmesh_build_topology.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/navigation/mesh/build/navmesh_build_topology.js"],"names":[],"mappings":"AA2CA;;;;;;;;;;GAUG;AACH,wKATW,cAAc,QAoLxB;+BA/N8B,mEAAmE"}
1
+ {"version":3,"file":"navmesh_build_topology.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/navigation/mesh/build/navmesh_build_topology.js"],"names":[],"mappings":"AA2CA;;;;;;;;;;GAUG;AACH,wKATW,cAAc,QAkLxB;+BA7N8B,mEAAmE"}