@woosh/meep-engine 3.29.0 → 3.30.0

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 (226) hide show
  1. package/build/bundle-worker-image-decoder.js +1 -1
  2. package/build/bundle-worker-terrain.js +1 -1
  3. package/package.json +1 -1
  4. package/src/core/binary/BinaryBuffer.d.ts.map +1 -1
  5. package/src/core/binary/BinaryBuffer.js +14 -2
  6. package/src/core/bvh2/bvh3/BVH.d.ts.map +1 -1
  7. package/src/core/bvh2/bvh3/BVH.js +14 -1
  8. package/src/core/cache/FrequencySketch.d.ts +3 -1
  9. package/src/core/cache/FrequencySketch.d.ts.map +1 -1
  10. package/src/core/cache/FrequencySketch.js +10 -4
  11. package/src/core/cache/wtinylfu/CacheWTinylfu.d.ts.map +1 -1
  12. package/src/core/cache/wtinylfu/CacheWTinylfu.js +24 -2
  13. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadrics.d.ts +20 -0
  14. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadrics.d.ts.map +1 -1
  15. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadrics.js +69 -4
  16. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.d.ts +48 -18
  17. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.d.ts.map +1 -1
  18. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.js +262 -70
  19. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_fold_limit.d.ts +25 -0
  20. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_fold_limit.d.ts.map +1 -0
  21. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_fold_limit.js +228 -0
  22. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_would_fold.d.ts +13 -0
  23. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_would_fold.d.ts.map +1 -1
  24. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_would_fold.js +10 -128
  25. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_build_face_bvh.d.ts.map +1 -1
  26. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_build_face_bvh.js +11 -1
  27. package/src/core/graph/mn_graph_collapse_weighted_edge.js +6 -6
  28. package/src/core/math/lookup/ParameterLookupTable.d.ts.map +1 -1
  29. package/src/core/math/lookup/ParameterLookupTable.js +10 -5
  30. package/src/core/math/noise/sdnoise.d.ts.map +1 -1
  31. package/src/core/math/noise/sdnoise.js +16 -10
  32. package/src/core/model/object/ImmutableObjectPool.d.ts.map +1 -1
  33. package/src/core/model/object/ImmutableObjectPool.js +17 -7
  34. package/src/core/process/executor/ConcurrentExecutor.d.ts +1 -5
  35. package/src/core/process/executor/ConcurrentExecutor.d.ts.map +1 -1
  36. package/src/core/process/executor/ConcurrentExecutor.js +95 -1
  37. package/src/core/process/task/task_find_dependency_cycle.d.ts +17 -0
  38. package/src/core/process/task/task_find_dependency_cycle.d.ts.map +1 -0
  39. package/src/core/process/task/task_find_dependency_cycle.js +81 -0
  40. package/src/core/wfc/WFCCellChoice.d.ts +17 -0
  41. package/src/core/wfc/WFCCellChoice.d.ts.map +1 -0
  42. package/src/core/wfc/WFCCellChoice.js +36 -0
  43. package/src/core/wfc/WFCLattice.d.ts +105 -0
  44. package/src/core/wfc/WFCLattice.d.ts.map +1 -0
  45. package/src/core/wfc/WFCLattice.js +235 -0
  46. package/src/core/wfc/WFCRuleTable.d.ts +172 -0
  47. package/src/core/wfc/WFCRuleTable.d.ts.map +1 -0
  48. package/src/core/wfc/WFCRuleTable.js +334 -0
  49. package/src/core/wfc/WFCState.d.ts +273 -0
  50. package/src/core/wfc/WFCState.d.ts.map +1 -0
  51. package/src/core/wfc/WFCState.js +552 -0
  52. package/src/core/wfc/WFCStatus.d.ts +11 -0
  53. package/src/core/wfc/WFCStatus.d.ts.map +1 -0
  54. package/src/core/wfc/WFCStatus.js +28 -0
  55. package/src/core/wfc/WFCTileWeights.d.ts +48 -0
  56. package/src/core/wfc/WFCTileWeights.d.ts.map +1 -0
  57. package/src/core/wfc/WFCTileWeights.js +86 -0
  58. package/src/core/wfc/WFC_UNRESOLVED.d.ts +12 -0
  59. package/src/core/wfc/WFC_UNRESOLVED.d.ts.map +1 -0
  60. package/src/core/wfc/WFC_UNRESOLVED.js +11 -0
  61. package/src/core/wfc/wfc_estimate_bytes.d.ts +24 -0
  62. package/src/core/wfc/wfc_estimate_bytes.d.ts.map +1 -0
  63. package/src/core/wfc/wfc_estimate_bytes.js +47 -0
  64. package/src/core/wfc/wfc_rule_table_tile_components.d.ts +27 -0
  65. package/src/core/wfc/wfc_rule_table_tile_components.d.ts.map +1 -0
  66. package/src/core/wfc/wfc_rule_table_tile_components.js +80 -0
  67. package/src/core/wfc/wfc_solve.d.ts +21 -0
  68. package/src/core/wfc/wfc_solve.d.ts.map +1 -0
  69. package/src/core/wfc/wfc_solve.js +154 -0
  70. package/src/core/wfc/wfc_state_apply_boundary.d.ts +18 -0
  71. package/src/core/wfc/wfc_state_apply_boundary.d.ts.map +1 -0
  72. package/src/core/wfc/wfc_state_apply_boundary.js +61 -0
  73. package/src/core/wfc/wfc_state_assign.d.ts +11 -0
  74. package/src/core/wfc/wfc_state_assign.d.ts.map +1 -0
  75. package/src/core/wfc/wfc_state_assign.js +36 -0
  76. package/src/core/wfc/wfc_state_ban_bits.d.ts +17 -0
  77. package/src/core/wfc/wfc_state_ban_bits.d.ts.map +1 -0
  78. package/src/core/wfc/wfc_state_ban_bits.js +81 -0
  79. package/src/core/wfc/wfc_state_collapse.d.ts +12 -0
  80. package/src/core/wfc/wfc_state_collapse.d.ts.map +1 -0
  81. package/src/core/wfc/wfc_state_collapse.js +73 -0
  82. package/src/core/wfc/wfc_state_flush_dirty.d.ts +12 -0
  83. package/src/core/wfc/wfc_state_flush_dirty.d.ts.map +1 -0
  84. package/src/core/wfc/wfc_state_flush_dirty.js +39 -0
  85. package/src/core/wfc/wfc_state_propagate.d.ts +14 -0
  86. package/src/core/wfc/wfc_state_propagate.d.ts.map +1 -0
  87. package/src/core/wfc/wfc_state_propagate.js +155 -0
  88. package/src/core/wfc/wfc_state_read.d.ts +11 -0
  89. package/src/core/wfc/wfc_state_read.d.ts.map +1 -0
  90. package/src/core/wfc/wfc_state_read.js +38 -0
  91. package/src/core/wfc/wfc_state_restrict.d.ts +18 -0
  92. package/src/core/wfc/wfc_state_restrict.d.ts.map +1 -0
  93. package/src/core/wfc/wfc_state_restrict.js +39 -0
  94. package/src/core/wfc/wfc_state_set_eligible.d.ts +24 -0
  95. package/src/core/wfc/wfc_state_set_eligible.d.ts.map +1 -0
  96. package/src/core/wfc/wfc_state_set_eligible.js +49 -0
  97. package/src/core/wfc/wfc_state_undo_to.d.ts +13 -0
  98. package/src/core/wfc/wfc_state_undo_to.d.ts.map +1 -0
  99. package/src/core/wfc/wfc_state_undo_to.js +84 -0
  100. package/src/core/wfc/wfc_words_per_cell.d.ts +11 -0
  101. package/src/core/wfc/wfc_words_per_cell.d.ts.map +1 -0
  102. package/src/core/wfc/wfc_words_per_cell.js +16 -0
  103. package/src/engine/ecs/EntityComponentDataset.d.ts +8 -0
  104. package/src/engine/ecs/EntityComponentDataset.d.ts.map +1 -1
  105. package/src/engine/ecs/EntityComponentDataset.js +37 -14
  106. package/src/engine/ecs/fow/FogOfWarRevealerSystem.d.ts +8 -1
  107. package/src/engine/ecs/fow/FogOfWarRevealerSystem.d.ts.map +1 -1
  108. package/src/engine/ecs/fow/FogOfWarRevealerSystem.js +37 -2
  109. package/src/engine/ecs/guid/UUID.d.ts.map +1 -1
  110. package/src/engine/ecs/guid/UUID.js +45 -17
  111. package/src/engine/ecs/ik/OneBoneSurfaceAlignmentSolver.d.ts.map +1 -1
  112. package/src/engine/ecs/ik/OneBoneSurfaceAlignmentSolver.js +3 -1
  113. package/src/engine/ecs/terrain/ecs/cling/ClingToTerrainSystem.d.ts.map +1 -1
  114. package/src/engine/ecs/terrain/ecs/cling/ClingToTerrainSystem.js +366 -360
  115. package/src/engine/graphics/texture/sampler/resize/sampler2d_scale_down_linear.d.ts.map +1 -1
  116. package/src/engine/graphics/texture/sampler/resize/sampler2d_scale_down_linear.js +24 -10
  117. package/src/engine/grid/grid2transform/GridPosition2TransformSystem.d.ts.map +1 -1
  118. package/src/engine/grid/grid2transform/GridPosition2TransformSystem.js +24 -5
  119. package/src/engine/interpolation/Interpoland.d.ts +7 -1
  120. package/src/engine/interpolation/Interpoland.d.ts.map +1 -1
  121. package/src/engine/interpolation/Interpoland.js +8 -1
  122. package/src/engine/interpolation/InterpolationSystem.d.ts.map +1 -1
  123. package/src/engine/interpolation/InterpolationSystem.js +3 -0
  124. package/src/engine/interpolation/TransformPoseSerializationAdapter.d.ts +5 -3
  125. package/src/engine/interpolation/TransformPoseSerializationAdapter.d.ts.map +1 -1
  126. package/src/engine/interpolation/TransformPoseSerializationAdapter.js +14 -3
  127. package/src/engine/interpolation/pose_interpoland.d.ts.map +1 -1
  128. package/src/engine/interpolation/pose_interpoland.js +2 -0
  129. package/src/engine/network/orchestrator/NetworkPeer.d.ts.map +1 -1
  130. package/src/engine/network/orchestrator/NetworkPeer.js +15 -10
  131. package/src/engine/physics/cloth/ecs/ClothWorld.d.ts.map +1 -1
  132. package/src/engine/physics/cloth/ecs/ClothWorld.js +17 -0
  133. package/src/engine/physics/mls-mpm/MLS_MPM.d.ts.map +1 -1
  134. package/src/engine/physics/mls-mpm/MLS_MPM.js +14 -0
  135. package/src/engine/sound/sopra/definition/clip/AbstractAudioClip.d.ts +2 -1
  136. package/src/engine/sound/sopra/definition/clip/AbstractAudioClip.d.ts.map +1 -1
  137. package/src/engine/sound/sopra/definition/clip/AbstractAudioClip.js +1 -1
  138. package/src/engine/sound/sopra/definition/clip/BlendContainerAudioClip.d.ts +1 -0
  139. package/src/engine/sound/sopra/definition/clip/BlendContainerAudioClip.d.ts.map +1 -1
  140. package/src/engine/sound/sopra/definition/clip/RandomContainerAudioClip.d.ts +1 -0
  141. package/src/engine/sound/sopra/definition/clip/RandomContainerAudioClip.d.ts.map +1 -1
  142. package/src/engine/sound/sopra/definition/clip/SampleAudioClip.d.ts +2 -1
  143. package/src/engine/sound/sopra/definition/clip/SampleAudioClip.d.ts.map +1 -1
  144. package/src/engine/sound/sopra/definition/clip/SampleAudioClip.js +12 -3
  145. package/src/engine/sound/sopra/definition/clip/SequenceContainerAudioClip.d.ts +1 -0
  146. package/src/engine/sound/sopra/definition/clip/SequenceContainerAudioClip.d.ts.map +1 -1
  147. package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClip.d.ts +1 -0
  148. package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClip.d.ts.map +1 -1
  149. package/src/engine/sound/sopra/runtime/EventInstance.d.ts.map +1 -1
  150. package/src/engine/sound/sopra/runtime/EventInstance.js +4 -1
  151. package/src/format/image/avif/av1/decode/decode_coefficients.d.ts.map +1 -1
  152. package/src/format/image/avif/av1/decode/decode_coefficients.js +248 -259
  153. package/src/format/image/avif/av1/decode/read_golomb.d.ts +21 -0
  154. package/src/format/image/avif/av1/decode/read_golomb.d.ts.map +1 -0
  155. package/src/format/image/avif/av1/decode/read_golomb.js +49 -0
  156. package/src/format/image/avif/av1/filter/loop_restoration.js +461 -451
  157. package/src/format/image/avif/av1/util/round2.d.ts +19 -2
  158. package/src/format/image/avif/av1/util/round2.d.ts.map +1 -1
  159. package/src/format/image/avif/av1/util/round2.js +51 -27
  160. package/src/format/image/avif/heif/parse_avif_file.js +24 -0
  161. package/src/shade/renderer/buffer/table/GPUTypedTable.d.ts.map +1 -1
  162. package/src/shade/renderer/buffer/table/GPUTypedTable.js +14 -0
  163. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md +46 -3
  164. package/src/shade/renderer/geometry/virtual/WEDGE_PLAN_2026_09_18.md +91 -1
  165. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts +0 -13
  166. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts.map +1 -1
  167. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.js +0 -15
  168. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_group_step.js +5 -5
  169. package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_DEFAULT_ATTRIBUTE_WEIGHT_RATIOS.d.ts +11 -1
  170. package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_DEFAULT_ATTRIBUTE_WEIGHT_RATIOS.d.ts.map +1 -1
  171. package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_DEFAULT_ATTRIBUTE_WEIGHT_RATIOS.js +11 -1
  172. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_normals.d.ts +18 -9
  173. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_normals.d.ts.map +1 -1
  174. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_normals.js +20 -26
  175. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_normalize_source.d.ts +1 -3
  176. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_normalize_source.d.ts.map +1 -1
  177. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_normalize_source.js +2 -5
  178. package/src/shade/renderer/geometry/virtual/build/vgeo_build.js +1 -1
  179. package/src/shade/renderer/geometry/virtual/runtime/VGeoResidency.d.ts.map +1 -1
  180. package/src/shade/renderer/geometry/virtual/runtime/VGeoResidency.js +14 -1
  181. package/src/shade/renderer/global_illumination/probe/octahedral/GPUProbeAtlas.d.ts.map +1 -1
  182. package/src/shade/renderer/global_illumination/probe/octahedral/GPUProbeAtlas.js +12 -3
  183. package/src/shade/renderer/light/environment/rgbe/RGBE_ReadPixels_RLE.d.ts.map +1 -1
  184. package/src/shade/renderer/light/environment/rgbe/RGBE_ReadPixels_RLE.js +7 -1
  185. package/src/shade/renderer/lightmap/GPULightMap.d.ts.map +1 -1
  186. package/src/shade/renderer/lightmap/GPULightMap.js +349 -336
  187. package/src/shade/renderer/loader/gltf/load_gltf.d.ts.map +1 -1
  188. package/src/shade/renderer/loader/gltf/load_gltf.js +1137 -1128
  189. package/src/shade/renderer/particles/DESIGN.md +14 -5
  190. package/src/shade/renderer/particles/GPUParticleSystem.d.ts +25 -10
  191. package/src/shade/renderer/particles/GPUParticleSystem.d.ts.map +1 -1
  192. package/src/shade/renderer/particles/GPUParticleSystem.js +182 -38
  193. package/src/shade/renderer/particles/graph/groups/simplex_reference.d.ts.map +1 -1
  194. package/src/shade/renderer/particles/graph/groups/simplex_reference.js +16 -10
  195. package/src/shade/renderer/particles/graph_particles.d.ts +4 -2
  196. package/src/shade/renderer/particles/graph_particles.d.ts.map +1 -1
  197. package/src/shade/renderer/particles/graph_particles.js +8 -2
  198. package/src/shade/renderer/particles/optimizer/particle_vm_semantics.d.ts.map +1 -1
  199. package/src/shade/renderer/particles/optimizer/particle_vm_semantics.js +8 -2
  200. package/src/shade/renderer/particles/optimizer/pass_fold_constants.d.ts.map +1 -1
  201. package/src/shade/renderer/particles/optimizer/pass_fold_constants.js +10 -4
  202. package/src/shade/renderer/particles/shaders/shader_particle_init_free_list.d.ts +31 -0
  203. package/src/shade/renderer/particles/shaders/shader_particle_init_free_list.d.ts.map +1 -0
  204. package/src/shade/renderer/particles/shaders/shader_particle_init_free_list.js +62 -0
  205. package/src/shade/renderer/particles/vm/ParticleVMReference.d.ts +13 -0
  206. package/src/shade/renderer/particles/vm/ParticleVMReference.d.ts.map +1 -1
  207. package/src/shade/renderer/particles/vm/ParticleVMReference.js +95 -17
  208. package/src/shade/renderer/rasterize/bucket/rasterization_has_opaque_bucket.d.ts +21 -0
  209. package/src/shade/renderer/rasterize/bucket/rasterization_has_opaque_bucket.d.ts.map +1 -0
  210. package/src/shade/renderer/rasterize/bucket/rasterization_has_opaque_bucket.js +28 -0
  211. package/src/shade/renderer/rasterize/fast/graph_rasterize_scene_fast.d.ts.map +1 -1
  212. package/src/shade/renderer/rasterize/fast/graph_rasterize_scene_fast.js +19 -2
  213. package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.d.ts.map +1 -1
  214. package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.js +19 -2
  215. package/src/shade/renderer/shader/type/WebGPUStruct.d.ts.map +1 -1
  216. package/src/shade/renderer/shader/type/WebGPUStruct.js +12 -0
  217. package/src/shade/renderer/texture/mipmaps/WebGPUMipmapGenerator.d.ts +8 -2
  218. package/src/shade/renderer/texture/mipmaps/WebGPUMipmapGenerator.d.ts.map +1 -1
  219. package/src/shade/renderer/texture/mipmaps/WebGPUMipmapGenerator.js +41 -6
  220. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +2383 -2356
  221. package/src/view/tooltip/DomTooltipManager.d.ts +7 -0
  222. package/src/view/tooltip/DomTooltipManager.d.ts.map +1 -1
  223. package/src/view/tooltip/DomTooltipManager.js +22 -0
  224. package/src/view/tooltip/DomTooltipObserver.d.ts.map +1 -1
  225. package/src/view/tooltip/DomTooltipObserver.js +13 -3
  226. package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_CREASE_ANGLE.js +0 -45
@@ -4,6 +4,7 @@ import { IllegalStateException } from "../../fsm/exceptions/IllegalStateExceptio
4
4
  import { objectKeyByValue } from "../../model/object/objectKeyByValue.js";
5
5
  import { TaskSignal } from "../task/TaskSignal.js";
6
6
  import TaskState from "../task/TaskState.js";
7
+ import { task_find_dependency_cycle } from "../task/task_find_dependency_cycle.js";
7
8
 
8
9
  /**
9
10
  * @typedef {import("../task/Task.js").Task} Task
@@ -294,7 +295,14 @@ class ConcurrentExecutor {
294
295
  // Dropping it from the queue is not enough: the task still
295
296
  // has to reach a terminal state, or its promise never
296
297
  // settles and everything awaiting it waits forever.
297
- unresolvedTask.state.set(TaskState.FAILED);
298
+ //
299
+ // Nor is the state enough on its own. `Task.join` reads the
300
+ // state only at the moment it is called and otherwise
301
+ // subscribes to `on.failed`, so a caller that takes the
302
+ // promise before submitting the task was left waiting on a
303
+ // signal nothing sent. The executor's other two terminal
304
+ // transitions both dispatch; this one used not to.
305
+ this.#fail_unresolved_task(unresolvedTask);
298
306
 
299
307
  // its own dependants are now resolvable too, and they may
300
308
  // sit earlier in the queue, so rescan from the start the
@@ -368,6 +376,38 @@ class ConcurrentExecutor {
368
376
 
369
377
  }
370
378
 
379
+ /**
380
+ * Fail a task that never got as far as the ready queue, because one of its dependencies failed.
381
+ * @param {Task} task
382
+ * @private
383
+ */
384
+ #fail_unresolved_task(task) {
385
+ const dependencies = task.dependencies;
386
+
387
+ let culprit = undefined;
388
+
389
+ for (let i = 0; i < dependencies.length; i++) {
390
+ if (dependencies[i].state.getValue() === TaskState.FAILED) {
391
+ culprit = dependencies[i];
392
+ break;
393
+ }
394
+ }
395
+
396
+ const reason = new Error(
397
+ `Task '${task.name}' failed because its dependency '${culprit === undefined ? '?' : culprit.name}' failed`
398
+ );
399
+
400
+ task.state.set(TaskState.FAILED);
401
+ task.on.failed.send1(reason);
402
+
403
+ if (!task.on.failed.hasHandlers()) {
404
+ // no one is watching for task failure
405
+ console.warn(`Task '${task.name}' failed.`, reason);
406
+ }
407
+
408
+ this.on.task_completed.send1(task);
409
+ }
410
+
371
411
  /**
372
412
  *
373
413
  * @param {Task} task
@@ -510,9 +550,63 @@ class ConcurrentExecutor {
510
550
  * kicks the scheduler into action, this is an internal method and should not be called from outside
511
551
  * @private
512
552
  */
553
+ /**
554
+ * Fail every task sitting on a dependency cycle, and then everything that depended on one.
555
+ *
556
+ * A cycle is the one form of "nothing can run" that no later `run` can rescue — an unsubmitted
557
+ * dependency is the other, and that one is a legal pattern here, so idleness alone is not the
558
+ * test. Left alone a cycle stopped the executor with no signal at all: `queueReady` never grows,
559
+ * `#executeTimeSlice` is the only place `on.completed` is sent and is never entered, so `join`
560
+ * subscribes to a signal that cannot fire and the task promises never settle.
561
+ * @private
562
+ */
563
+ #fail_dependency_cycles() {
564
+ for (
565
+ let cycle = task_find_dependency_cycle(this.queueUnresolved);
566
+ cycle !== null;
567
+ cycle = task_find_dependency_cycle(this.queueUnresolved)
568
+ ) {
569
+ const description = cycle.map(t => t.name).join(' -> ');
570
+
571
+ const reason = new Error(`Task dependency cycle: ${description} -> ${cycle[0].name}`);
572
+
573
+ console.error(reason.message, cycle.slice());
574
+
575
+ for (let i = 0; i < cycle.length; i++) {
576
+ const task = cycle[i];
577
+
578
+ const index = this.queueUnresolved.indexOf(task);
579
+
580
+ if (index !== -1) {
581
+ this.queueUnresolved.splice(index, 1);
582
+ }
583
+
584
+ // as with any other failure, the task still has to reach a terminal state or its
585
+ // promise never settles and everything awaiting it waits forever
586
+ task.state.set(TaskState.FAILED);
587
+ task.on.failed.send1(reason);
588
+
589
+ this.on.task_completed.send1(task);
590
+ }
591
+
592
+ // the dependants of what just failed are resolvable now, as failures
593
+ this.resolveTasks();
594
+ }
595
+
596
+ if (this.queueReady.length === 0 && this.queueUnresolved.length === 0) {
597
+ // nothing is left to run, and `#executeTimeSlice` — which is what normally announces
598
+ // that — was never entered, so anything waiting on `join` would wait forever
599
+ this.on.completed.send0();
600
+ }
601
+ }
602
+
513
603
  prod() {
514
604
  this.resolveTasks();
515
605
 
606
+ if (!this.busy && this.queueReady.length === 0 && this.queueUnresolved.length > 0) {
607
+ this.#fail_dependency_cycles();
608
+ }
609
+
516
610
  if (!this.busy && this.queueReady.length > 0) {
517
611
  this.busy = true;
518
612
  this.#executeTimeSlice();
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Find one dependency cycle reachable from `roots`, following {@link Task#dependencies}.
3
+ *
4
+ * A cycle can never resolve: every task on it waits for a task that is waiting for it, so all of them
5
+ * stay INITIAL forever. Unlike a dependency that simply has not been submitted yet, no later `run`
6
+ * can rescue it — which is what makes this, and not "the executor is idle with work outstanding", the
7
+ * safe test for a deadlock.
8
+ *
9
+ * Iterative rather than recursive: task graphs are authored by hand but are not bounded in depth, and
10
+ * a stack overflow while diagnosing a hang is not an improvement on the hang.
11
+ *
12
+ * @param {Task[]} roots
13
+ * @returns {Task[]|null} the tasks on a cycle, in dependency order, or null if there is none. The
14
+ * first element depends on the last.
15
+ */
16
+ export function task_find_dependency_cycle(roots: Task[]): Task[] | null;
17
+ //# sourceMappingURL=task_find_dependency_cycle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task_find_dependency_cycle.d.ts","sourceRoot":"","sources":["../../../../../src/core/process/task/task_find_dependency_cycle.js"],"names":[],"mappings":"AAkBA;;;;;;;;;;;;;;GAcG;AACH,kDAJW,MAAM,GACJ,MAAM,GAAC,IAAI,CAkDvB"}
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Not yet visited. Absent from the map, in practice — named for the comparison below.
3
+ * @type {number}
4
+ */
5
+ const UNVISITED = 0;
6
+
7
+ /**
8
+ * On the current DFS path. An edge back to one of these is a cycle.
9
+ * @type {number}
10
+ */
11
+ const ON_PATH = 1;
12
+
13
+ /**
14
+ * Fully explored, and no cycle was found through it.
15
+ * @type {number}
16
+ */
17
+ const EXPLORED = 2;
18
+
19
+ /**
20
+ * Find one dependency cycle reachable from `roots`, following {@link Task#dependencies}.
21
+ *
22
+ * A cycle can never resolve: every task on it waits for a task that is waiting for it, so all of them
23
+ * stay INITIAL forever. Unlike a dependency that simply has not been submitted yet, no later `run`
24
+ * can rescue it — which is what makes this, and not "the executor is idle with work outstanding", the
25
+ * safe test for a deadlock.
26
+ *
27
+ * Iterative rather than recursive: task graphs are authored by hand but are not bounded in depth, and
28
+ * a stack overflow while diagnosing a hang is not an improvement on the hang.
29
+ *
30
+ * @param {Task[]} roots
31
+ * @returns {Task[]|null} the tasks on a cycle, in dependency order, or null if there is none. The
32
+ * first element depends on the last.
33
+ */
34
+ export function task_find_dependency_cycle(roots) {
35
+ const states = new Map();
36
+
37
+ const root_count = roots.length;
38
+
39
+ for (let r = 0; r < root_count; r++) {
40
+ const root = roots[r];
41
+
42
+ if (states.get(root) === EXPLORED) {
43
+ continue;
44
+ }
45
+
46
+ const path = [root];
47
+
48
+ //frame `i` holds how many of `path[i]`'s dependencies have been taken
49
+ const cursors = [0];
50
+
51
+ states.set(root, ON_PATH);
52
+
53
+ while (path.length > 0) {
54
+ const depth = path.length - 1;
55
+ const task = path[depth];
56
+ const dependencies = task.dependencies;
57
+
58
+ if (cursors[depth] < dependencies.length) {
59
+ const dependency = dependencies[cursors[depth]];
60
+
61
+ cursors[depth]++;
62
+
63
+ const state = states.get(dependency) ?? UNVISITED;
64
+
65
+ if (state === ON_PATH) {
66
+ return path.slice(path.indexOf(dependency));
67
+ } else if (state === UNVISITED) {
68
+ states.set(dependency, ON_PATH);
69
+ path.push(dependency);
70
+ cursors.push(0);
71
+ }
72
+ } else {
73
+ states.set(task, EXPLORED);
74
+ path.pop();
75
+ cursors.pop();
76
+ }
77
+ }
78
+ }
79
+
80
+ return null;
81
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Which cell the solver collapses next.
3
+ *
4
+ * Affects how reliably a solve finishes and how the output looks. It never affects *which* tile a
5
+ * cell ends up with — that is always a weighted draw — only the order cells are decided in.
6
+ *
7
+ * {@link SCANLINE } is the default and solves rule sets the other two fail on. Reach for
8
+ * {@link ENTROPY } when the character of the output matters more than first-time success.
9
+ * `WFC_DESIGN.md` §4.4 carries the measurements behind that.
10
+ */
11
+ export type WFCCellChoice = number;
12
+ export namespace WFCCellChoice {
13
+ let ENTROPY: number;
14
+ let MINIMUM_REMAINING: number;
15
+ let SCANLINE: number;
16
+ }
17
+ //# sourceMappingURL=WFCCellChoice.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WFCCellChoice.d.ts","sourceRoot":"","sources":["../../../../src/core/wfc/WFCCellChoice.js"],"names":[],"mappings":";;;;;;;;;;4BAWU,MAAM"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Which cell the solver collapses next.
3
+ *
4
+ * Affects how reliably a solve finishes and how the output looks. It never affects *which* tile a
5
+ * cell ends up with — that is always a weighted draw — only the order cells are decided in.
6
+ *
7
+ * {@link SCANLINE} is the default and solves rule sets the other two fail on. Reach for
8
+ * {@link ENTROPY} when the character of the output matters more than first-time success.
9
+ * `WFC_DESIGN.md` §4.4 carries the measurements behind that.
10
+ *
11
+ * @readonly
12
+ * @enum {number}
13
+ */
14
+ export const WFCCellChoice = {
15
+ /**
16
+ * Lowest Shannon entropy over the remaining weights. The only policy in which weights affect
17
+ * the order cells are decided in, which is what gives its output an organic look; it is what
18
+ * Gumin's original and DeBroglie both default to.
19
+ *
20
+ * Needs a priority queue, and fails on rule sets the other two solve.
21
+ */
22
+ ENTROPY: 0,
23
+ /**
24
+ * Fewest remaining possibilities. Identical to {@link ENTROPY} when every weight is equal, and
25
+ * an integer comparison rather than a logarithm. Needs the same priority queue.
26
+ */
27
+ MINIMUM_REMAINING: 1,
28
+ /**
29
+ * Ascending cell index, skipping cells already decided. The default: no priority structure,
30
+ * and the policy most likely to solve a given rule set.
31
+ *
32
+ * Its cost is a directional bias in the output. Solving in blocks
33
+ * (see {@link wfc_state_set_eligible}) confines that bias to a block.
34
+ */
35
+ SCANLINE: 2
36
+ };
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Largest number of axes an {@link WFCLattice} can have.
3
+ *
4
+ * {@link WFCLattice#edge_flags} spends two bits per axis — one per side — in a `u32`.
5
+ * @type {number}
6
+ */
7
+ export const WFC_MAX_DIMENSION_COUNT: number;
8
+ /**
9
+ * An N-dimensional box of cells with per-axis wrapping. The topology the solver ships with, and
10
+ * the reason dimensionality is a number rather than three separate implementations.
11
+ *
12
+ * `WFCLattice.from_shape([64])` is 1-D, `[16, 16, 16]` is 3-D, `[8, 8, 8, 8]` is 4-D. Cells are
13
+ * numbered row-major — the last axis varies fastest — and {@link index_of} / {@link coordinate_of}
14
+ * convert between a cell index and coordinates.
15
+ *
16
+ * Direction `d` is `axis = d >> 1`, `side = d & 1` (0 toward the lower coordinate), and `d ^ 1` is
17
+ * the opposite direction. There are `2 × dimension_count` of them.
18
+ *
19
+ * At most {@link WFC_MAX_DIMENSION_COUNT} axes, which is what {@link edge_flags} can describe.
20
+ *
21
+ * @author Alex Goldring
22
+ * @copyright Company Named Limited (c) 2026
23
+ */
24
+ export class WFCLattice {
25
+ /**
26
+ * @param {number[]|Uint32Array} shape
27
+ * @param {boolean[]|Uint8Array} [wrap]
28
+ * @returns {WFCLattice}
29
+ */
30
+ static from_shape(shape: number[] | Uint32Array, wrap?: boolean[] | Uint8Array): WFCLattice;
31
+ /**
32
+ * Prefer {@link WFCLattice.from_shape}.
33
+ *
34
+ * @param {number[]|Uint32Array} shape extent along each axis, every entry at least 1
35
+ * @param {boolean[]|Uint8Array} [wrap] per axis; defaults to no wrapping
36
+ */
37
+ constructor(shape: number[] | Uint32Array, wrap?: boolean[] | Uint8Array);
38
+ /** @type {number} */
39
+ dimension_count: number;
40
+ /** @type {number} */
41
+ direction_count: number;
42
+ /** @type {Uint32Array} */
43
+ shape: Uint32Array;
44
+ /** @type {Uint8Array} */
45
+ wrap: Uint8Array;
46
+ /** @type {number} */
47
+ cell_count: number;
48
+ /**
49
+ * Row-major: the last axis is the fastest-varying.
50
+ * @type {Uint32Array}
51
+ */
52
+ strides: Uint32Array;
53
+ /**
54
+ * `neighbour_offsets[d]` — what to add to a cell index to step in direction `d`, valid
55
+ * only when the cell is not on the face `d` points off.
56
+ * @type {Int32Array}
57
+ */
58
+ neighbour_offsets: Int32Array;
59
+ /**
60
+ * `wrap_offsets[d]` — what to add instead when the cell *is* on the face `d` points off
61
+ * and that axis wraps.
62
+ *
63
+ * An axis of extent 1 gives an offset of zero, making the cell its own neighbour. That is
64
+ * correct — stepping off a one-cell ring lands back where it started — and it means such a
65
+ * tile must be compatible with itself along that axis.
66
+ * @type {Int32Array}
67
+ */
68
+ wrap_offsets: Int32Array;
69
+ /**
70
+ * Bit `d` set means the neighbour in direction `d` is outside the lattice.
71
+ * @type {Uint32Array}
72
+ */
73
+ edge_flags: Uint32Array;
74
+ /**
75
+ * Mark the two faces of every axis.
76
+ *
77
+ * @private
78
+ */
79
+ private __build_edge_flags;
80
+ /**
81
+ * Cell index of a coordinate — how a caller turns its own coordinates into the cell ids this
82
+ * module speaks in.
83
+ *
84
+ * @param {number[]|Uint32Array} coordinate one entry per axis
85
+ * @returns {number}
86
+ */
87
+ index_of(coordinate: number[] | Uint32Array): number;
88
+ /**
89
+ * Inverse of {@link index_of}, written into `out`.
90
+ *
91
+ * @param {number[]|Uint32Array} out at least `dimension_count` long
92
+ * @param {number} index
93
+ */
94
+ coordinate_of(out: number[] | Uint32Array, index: number): void;
95
+ /**
96
+ * The neighbour of `cell` in direction `direction`, or `-1` when there is none — off a
97
+ * non-wrapping face.
98
+ *
99
+ * @param {number} cell
100
+ * @param {number} direction
101
+ * @returns {number} neighbour cell index, or -1
102
+ */
103
+ neighbour_of(cell: number, direction: number): number;
104
+ }
105
+ //# sourceMappingURL=WFCLattice.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WFCLattice.d.ts","sourceRoot":"","sources":["../../../../src/core/wfc/WFCLattice.js"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,sCAFU,MAAM,CAE0B;AAE1C;;;;;;;;;;;;;;;GAeG;AACH;IAwMI;;;;OAIG;IACH,yBAJW,MAAM,EAAE,GAAC,WAAW,SACpB,OAAO,EAAE,GAAC,UAAU,GAClB,UAAU,CAItB;IA9MD;;;;;OAKG;IACH,mBAHW,MAAM,EAAE,GAAC,WAAW,SACpB,OAAO,EAAE,GAAC,UAAU,EAgG9B;IA9EG,qBAAqB;IACrB,iBADW,MAAM,CACqB;IACtC,qBAAqB;IACrB,iBADW,MAAM,CACyB;IAE1C,0BAA0B;IAC1B,OADW,WAAW,CACuB;IAC7C,yBAAyB;IACzB,MADW,UAAU,CACsB;IAmB3C,qBAAqB;IACrB,YADW,MAAM,CACW;IAE5B;;;OAGG;IACH,SAFU,WAAW,CAE0B;IAQ/C;;;;OAIG;IACH,mBAFU,UAAU,CAEyC;IAE7D;;;;;;;;OAQG;IACH,cAFU,UAAU,CAEoC;IAaxD;;;OAGG;IACH,YAFU,WAAW,CAEwB;IAKjD;;;;OAIG;IACH,2BAmBC;IAED;;;;;;OAMG;IACH,qBAHW,MAAM,EAAE,GAAC,WAAW,GAClB,MAAM,CAiBlB;IAED;;;;;OAKG;IACH,mBAHW,MAAM,EAAE,GAAC,WAAW,SACpB,MAAM,QAgBhB;IAED;;;;;;;OAOG;IACH,mBAJW,MAAM,aACN,MAAM,GACJ,MAAM,CAiBlB;CAUJ"}
@@ -0,0 +1,235 @@
1
+ import { assert } from "../assert.js";
2
+
3
+ /**
4
+ * Largest number of axes an {@link WFCLattice} can have.
5
+ *
6
+ * {@link WFCLattice#edge_flags} spends two bits per axis — one per side — in a `u32`.
7
+ * @type {number}
8
+ */
9
+ export const WFC_MAX_DIMENSION_COUNT = 16;
10
+
11
+ /**
12
+ * An N-dimensional box of cells with per-axis wrapping. The topology the solver ships with, and
13
+ * the reason dimensionality is a number rather than three separate implementations.
14
+ *
15
+ * `WFCLattice.from_shape([64])` is 1-D, `[16, 16, 16]` is 3-D, `[8, 8, 8, 8]` is 4-D. Cells are
16
+ * numbered row-major — the last axis varies fastest — and {@link index_of} / {@link coordinate_of}
17
+ * convert between a cell index and coordinates.
18
+ *
19
+ * Direction `d` is `axis = d >> 1`, `side = d & 1` (0 toward the lower coordinate), and `d ^ 1` is
20
+ * the opposite direction. There are `2 × dimension_count` of them.
21
+ *
22
+ * At most {@link WFC_MAX_DIMENSION_COUNT} axes, which is what {@link edge_flags} can describe.
23
+ *
24
+ * @author Alex Goldring
25
+ * @copyright Company Named Limited (c) 2026
26
+ */
27
+ export class WFCLattice {
28
+ /**
29
+ * Prefer {@link WFCLattice.from_shape}.
30
+ *
31
+ * @param {number[]|Uint32Array} shape extent along each axis, every entry at least 1
32
+ * @param {boolean[]|Uint8Array} [wrap] per axis; defaults to no wrapping
33
+ */
34
+ constructor(shape, wrap) {
35
+ assert.isArrayLike(shape, 'shape');
36
+
37
+ if (wrap !== undefined) {
38
+ assert.isArrayLike(wrap, 'wrap');
39
+ assert.greaterThanOrEqual(wrap.length, shape.length, 'wrap.length >= shape.length');
40
+ }
41
+
42
+ const dimension_count = shape.length;
43
+
44
+ assert.isPositiveInteger(dimension_count, 'shape.length');
45
+
46
+ if (dimension_count > WFC_MAX_DIMENSION_COUNT) {
47
+ throw new Error(`dimension_count(=${dimension_count}) exceeds ${WFC_MAX_DIMENSION_COUNT}; edge_flags holds two bits per axis`);
48
+ }
49
+
50
+ /** @type {number} */
51
+ this.dimension_count = dimension_count;
52
+ /** @type {number} */
53
+ this.direction_count = dimension_count * 2;
54
+
55
+ /** @type {Uint32Array} */
56
+ this.shape = new Uint32Array(dimension_count);
57
+ /** @type {Uint8Array} */
58
+ this.wrap = new Uint8Array(dimension_count);
59
+
60
+ let cell_count = 1;
61
+
62
+ for (let axis = 0; axis < dimension_count; axis++) {
63
+ const extent = shape[axis];
64
+
65
+ assert.isPositiveInteger(extent, 'shape[axis]');
66
+
67
+ this.shape[axis] = extent;
68
+ this.wrap[axis] = (wrap !== undefined && wrap[axis]) ? 1 : 0;
69
+
70
+ cell_count *= extent;
71
+ }
72
+
73
+ if (!Number.isSafeInteger(cell_count)) {
74
+ throw new Error(`cell count overflows: shape ${Array.from(shape).join('x')}`);
75
+ }
76
+
77
+ /** @type {number} */
78
+ this.cell_count = cell_count;
79
+
80
+ /**
81
+ * Row-major: the last axis is the fastest-varying.
82
+ * @type {Uint32Array}
83
+ */
84
+ this.strides = new Uint32Array(dimension_count);
85
+
86
+ this.strides[dimension_count - 1] = 1;
87
+
88
+ for (let axis = dimension_count - 2; axis >= 0; axis--) {
89
+ this.strides[axis] = this.strides[axis + 1] * this.shape[axis + 1];
90
+ }
91
+
92
+ /**
93
+ * `neighbour_offsets[d]` — what to add to a cell index to step in direction `d`, valid
94
+ * only when the cell is not on the face `d` points off.
95
+ * @type {Int32Array}
96
+ */
97
+ this.neighbour_offsets = new Int32Array(this.direction_count);
98
+
99
+ /**
100
+ * `wrap_offsets[d]` — what to add instead when the cell *is* on the face `d` points off
101
+ * and that axis wraps.
102
+ *
103
+ * An axis of extent 1 gives an offset of zero, making the cell its own neighbour. That is
104
+ * correct — stepping off a one-cell ring lands back where it started — and it means such a
105
+ * tile must be compatible with itself along that axis.
106
+ * @type {Int32Array}
107
+ */
108
+ this.wrap_offsets = new Int32Array(this.direction_count);
109
+
110
+ for (let axis = 0; axis < dimension_count; axis++) {
111
+ const stride = this.strides[axis];
112
+ const span = stride * (this.shape[axis] - 1);
113
+
114
+ this.neighbour_offsets[axis * 2] = -stride;
115
+ this.neighbour_offsets[axis * 2 + 1] = stride;
116
+
117
+ this.wrap_offsets[axis * 2] = span;
118
+ this.wrap_offsets[axis * 2 + 1] = -span;
119
+ }
120
+
121
+ /**
122
+ * Bit `d` set means the neighbour in direction `d` is outside the lattice.
123
+ * @type {Uint32Array}
124
+ */
125
+ this.edge_flags = new Uint32Array(cell_count);
126
+
127
+ this.__build_edge_flags();
128
+ }
129
+
130
+ /**
131
+ * Mark the two faces of every axis.
132
+ *
133
+ * @private
134
+ */
135
+ __build_edge_flags() {
136
+ const { cell_count, dimension_count, edge_flags, shape, strides } = this;
137
+
138
+ for (let axis = 0; axis < dimension_count; axis++) {
139
+ const stride = strides[axis];
140
+ const extent = shape[axis];
141
+ const block = stride * extent;
142
+ const high_offset = stride * (extent - 1);
143
+
144
+ const low_bit = 1 << (axis * 2);
145
+ const high_bit = 1 << (axis * 2 + 1);
146
+
147
+ for (let block_start = 0; block_start < cell_count; block_start += block) {
148
+ for (let k = 0; k < stride; k++) {
149
+ edge_flags[block_start + k] |= low_bit;
150
+ edge_flags[block_start + high_offset + k] |= high_bit;
151
+ }
152
+ }
153
+ }
154
+ }
155
+
156
+ /**
157
+ * Cell index of a coordinate — how a caller turns its own coordinates into the cell ids this
158
+ * module speaks in.
159
+ *
160
+ * @param {number[]|Uint32Array} coordinate one entry per axis
161
+ * @returns {number}
162
+ */
163
+ index_of(coordinate) {
164
+ assert.equal(coordinate.length, this.dimension_count, 'coordinate.length === dimension_count');
165
+
166
+ let index = 0;
167
+
168
+ for (let axis = 0; axis < this.dimension_count; axis++) {
169
+ const value = coordinate[axis];
170
+
171
+ assert.isNonNegativeInteger(value, 'coordinate[axis]');
172
+ assert.lessThan(value, this.shape[axis], 'coordinate[axis] < shape[axis]');
173
+
174
+ index += value * this.strides[axis];
175
+ }
176
+
177
+ return index;
178
+ }
179
+
180
+ /**
181
+ * Inverse of {@link index_of}, written into `out`.
182
+ *
183
+ * @param {number[]|Uint32Array} out at least `dimension_count` long
184
+ * @param {number} index
185
+ */
186
+ coordinate_of(out, index) {
187
+ assert.isArrayLike(out, 'out');
188
+ assert.greaterThanOrEqual(out.length, this.dimension_count, 'out.length >= dimension_count');
189
+ assert.isNonNegativeInteger(index, 'index');
190
+ assert.lessThan(index, this.cell_count, 'index < cell_count');
191
+
192
+ let rest = index;
193
+
194
+ for (let axis = 0; axis < this.dimension_count; axis++) {
195
+ const stride = this.strides[axis];
196
+
197
+ out[axis] = (rest / stride) | 0;
198
+ rest = rest % stride;
199
+ }
200
+ }
201
+
202
+ /**
203
+ * The neighbour of `cell` in direction `direction`, or `-1` when there is none — off a
204
+ * non-wrapping face.
205
+ *
206
+ * @param {number} cell
207
+ * @param {number} direction
208
+ * @returns {number} neighbour cell index, or -1
209
+ */
210
+ neighbour_of(cell, direction) {
211
+ assert.isNonNegativeInteger(cell, 'cell');
212
+ assert.isNonNegativeInteger(direction, 'direction');
213
+ assert.lessThan(cell, this.cell_count, 'cell < cell_count');
214
+ assert.lessThan(direction, this.direction_count, 'direction < direction_count');
215
+
216
+ if (((this.edge_flags[cell] >> direction) & 1) === 1) {
217
+ if (this.wrap[direction >> 1] === 0) {
218
+ return -1;
219
+ }
220
+
221
+ return cell + this.wrap_offsets[direction];
222
+ }
223
+
224
+ return cell + this.neighbour_offsets[direction];
225
+ }
226
+
227
+ /**
228
+ * @param {number[]|Uint32Array} shape
229
+ * @param {boolean[]|Uint8Array} [wrap]
230
+ * @returns {WFCLattice}
231
+ */
232
+ static from_shape(shape, wrap) {
233
+ return new WFCLattice(shape, wrap);
234
+ }
235
+ }