@woosh/meep-engine 2.168.0 → 2.169.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 (295) hide show
  1. package/README.md +2 -2
  2. package/build/bundle-worker-image-decoder.js +1 -1
  3. package/package.json +1 -1
  4. package/src/REVIEW_2026_08_06/adv-core.md +511 -0
  5. package/src/REVIEW_2026_08_06/adv-gfx.md +480 -0
  6. package/src/REVIEW_2026_08_06/adv-view.md +446 -0
  7. package/src/REVIEW_2026_08_06/api-core.md +296 -0
  8. package/src/REVIEW_2026_08_06/api-engine.md +195 -0
  9. package/src/REVIEW_2026_08_06/bvh-phys-sound-net.md +507 -0
  10. package/src/REVIEW_2026_08_06/core-binary.md +348 -0
  11. package/src/REVIEW_2026_08_06/core-collection.md +376 -0
  12. package/src/REVIEW_2026_08_06/core-math.md +221 -0
  13. package/src/REVIEW_2026_08_06/core-process.md +266 -0
  14. package/src/REVIEW_2026_08_06/core-science.md +223 -0
  15. package/src/REVIEW_2026_08_06/engine-ai-nav.md +279 -0
  16. package/src/REVIEW_2026_08_06/engine-animation.md +167 -0
  17. package/src/REVIEW_2026_08_06/engine-asset.md +166 -0
  18. package/src/REVIEW_2026_08_06/engine-ecs.md +920 -0
  19. package/src/REVIEW_2026_08_06/engine-input.md +197 -0
  20. package/src/REVIEW_2026_08_06/engine-misc.md +248 -0
  21. package/src/REVIEW_2026_08_06/engine-terrain.md +52 -0
  22. package/src/REVIEW_2026_08_06/generation.md +176 -0
  23. package/src/REVIEW_2026_08_06/geom-2d.md +434 -0
  24. package/src/REVIEW_2026_08_06/geom-3d.md +117 -0
  25. package/src/REVIEW_2026_08_06/gfx-gi.md +143 -0
  26. package/src/REVIEW_2026_08_06/gfx-render.md +740 -0
  27. package/src/REVIEW_2026_08_06/gfx-texture.md +690 -0
  28. package/src/REVIEW_2026_08_06/prior-criticals.md +49 -0
  29. package/src/REVIEW_2026_08_06/prior-highs.md +138 -0
  30. package/src/REVIEW_2026_08_06/test-gaps.md +364 -0
  31. package/src/REVIEW_2026_08_06/view.md +667 -0
  32. package/src/REVIEW_2026_08_06.md +571 -0
  33. package/src/core/binary/BinaryBuffer.d.ts.map +1 -1
  34. package/src/core/binary/BinaryBuffer.js +12 -1
  35. package/src/core/binary/BitImage2.d.ts +5 -1
  36. package/src/core/binary/BitImage2.d.ts.map +1 -1
  37. package/src/core/binary/BitImage2.js +5 -1
  38. package/src/core/bvh8/build/NodeProxy.d.ts.map +1 -1
  39. package/src/core/bvh8/build/NodeProxy.js +314 -308
  40. package/src/core/collection/list/List.d.ts +15 -0
  41. package/src/core/collection/list/List.d.ts.map +1 -1
  42. package/src/core/collection/list/List.js +34 -0
  43. package/src/core/collection/list/SortedListProjection.d.ts.map +1 -1
  44. package/src/core/collection/list/SortedListProjection.js +4 -1
  45. package/src/core/collection/map/BiMap.d.ts +25 -2
  46. package/src/core/collection/map/BiMap.d.ts.map +1 -1
  47. package/src/core/collection/map/BiMap.js +57 -3
  48. package/src/core/debug/matchers/IsAnything.d.ts.map +1 -1
  49. package/src/core/debug/matchers/IsAnything.js +5 -1
  50. package/src/core/events/signal/Signal.d.ts.map +1 -1
  51. package/src/core/events/signal/Signal.js +3 -1
  52. package/src/core/geom/2d/polygon/TRIANGULATION_DESIGN.md +433 -0
  53. package/src/core/geom/2d/polygon/polygon2_is_counter_clockwise.d.ts +31 -0
  54. package/src/core/geom/2d/polygon/polygon2_is_counter_clockwise.d.ts.map +1 -0
  55. package/src/core/geom/2d/polygon/polygon2_is_counter_clockwise.js +84 -0
  56. package/src/core/geom/2d/polygon/polygon2_signed_area.d.ts +24 -2
  57. package/src/core/geom/2d/polygon/polygon2_signed_area.d.ts.map +1 -1
  58. package/src/core/geom/2d/polygon/polygon2_signed_area.js +52 -34
  59. package/src/core/geom/2d/polygon/polygon2_triangulate.corpus.d.ts +28 -0
  60. package/src/core/geom/2d/polygon/polygon2_triangulate.corpus.d.ts.map +1 -0
  61. package/src/core/geom/2d/polygon/polygon2_triangulate.corpus.js +86 -0
  62. package/src/core/geom/2d/polygon/polygon2_triangulate.d.ts +40 -0
  63. package/src/core/geom/2d/polygon/polygon2_triangulate.d.ts.map +1 -0
  64. package/src/core/geom/2d/polygon/polygon2_triangulate.js +1280 -0
  65. package/src/core/geom/2d/polygon/polygon2_triangulation_deviation.d.ts +28 -0
  66. package/src/core/geom/2d/polygon/polygon2_triangulation_deviation.d.ts.map +1 -0
  67. package/src/core/geom/2d/polygon/polygon2_triangulation_deviation.js +77 -0
  68. package/src/core/geom/2d/triangle/tri2_rasterize_conservative.d.ts +6 -3
  69. package/src/core/geom/2d/triangle/tri2_rasterize_conservative.d.ts.map +1 -1
  70. package/src/core/geom/2d/triangle/tri2_rasterize_conservative.js +26 -13
  71. package/src/core/geom/2d/triangle/tri2_signed_area.d.ts +17 -1
  72. package/src/core/geom/2d/triangle/tri2_signed_area.d.ts.map +1 -1
  73. package/src/core/geom/2d/triangle/tri2_signed_area.js +35 -23
  74. package/src/core/geom/2d/v2_morton_encode.d.ts +20 -0
  75. package/src/core/geom/2d/v2_morton_encode.d.ts.map +1 -0
  76. package/src/core/geom/2d/v2_morton_encode.js +23 -0
  77. package/src/core/geom/3d/atlas/segment/atlas_merge_charts.d.ts.map +1 -1
  78. package/src/core/geom/3d/atlas/segment/atlas_merge_charts.js +4 -1
  79. package/src/core/geom/3d/polygon/polygon3_compute_normal.d.ts +27 -0
  80. package/src/core/geom/3d/polygon/polygon3_compute_normal.d.ts.map +1 -0
  81. package/src/core/geom/3d/polygon/polygon3_compute_normal.js +60 -0
  82. package/src/core/geom/3d/polygon/polygon3_triangulate.d.ts +34 -0
  83. package/src/core/geom/3d/polygon/polygon3_triangulate.d.ts.map +1 -0
  84. package/src/core/geom/3d/polygon/polygon3_triangulate.js +94 -0
  85. package/src/core/geom/3d/quaternion/quat3_multiply.d.ts +8 -2
  86. package/src/core/geom/3d/quaternion/quat3_multiply.d.ts.map +1 -1
  87. package/src/core/geom/3d/quaternion/quat3_multiply.js +8 -2
  88. package/src/core/geom/3d/shape/ConvexHullShape3D.d.ts.map +1 -1
  89. package/src/core/geom/3d/shape/ConvexHullShape3D.js +32 -2
  90. package/src/core/geom/3d/topology/struct/binary/io/face/bt_face_triangulate.d.ts +23 -6
  91. package/src/core/geom/3d/topology/struct/binary/io/face/bt_face_triangulate.d.ts.map +1 -1
  92. package/src/core/geom/3d/topology/struct/binary/io/face/bt_face_triangulate.js +268 -124
  93. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_assert_valid.d.ts +17 -0
  94. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_assert_valid.d.ts.map +1 -0
  95. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_assert_valid.js +44 -0
  96. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_count_edge_faces.d.ts +20 -0
  97. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_count_edge_faces.d.ts.map +1 -0
  98. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_count_edge_faces.js +40 -0
  99. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_is_closed.d.ts +19 -0
  100. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_is_closed.d.ts.map +1 -0
  101. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_is_closed.js +34 -0
  102. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_is_manifold.d.ts +22 -0
  103. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_is_manifold.d.ts.map +1 -0
  104. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_is_manifold.js +37 -0
  105. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_validate.d.ts +87 -0
  106. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_validate.d.ts.map +1 -0
  107. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_validate.js +599 -0
  108. package/src/core/geom/3d/triangle/tri3_compute_signed_volume.d.ts +32 -0
  109. package/src/core/geom/3d/triangle/tri3_compute_signed_volume.d.ts.map +1 -1
  110. package/src/core/geom/3d/triangle/tri3_compute_signed_volume.js +66 -7
  111. package/src/core/geom/3d/triangle/tri3_mesh_compute_signed_volume.d.ts +22 -1
  112. package/src/core/geom/3d/triangle/tri3_mesh_compute_signed_volume.d.ts.map +1 -1
  113. package/src/core/geom/3d/triangle/tri3_mesh_compute_signed_volume.js +83 -38
  114. package/src/core/geom/MANIFOLD_COMPARISON_2026_08_01.md +554 -0
  115. package/src/core/geom/vec3/v3_cotangent.d.ts +6 -2
  116. package/src/core/geom/vec3/v3_cotangent.d.ts.map +1 -1
  117. package/src/core/geom/vec3/v3_cotangent.js +6 -2
  118. package/src/core/geom/vec3/v3_cross.d.ts +6 -2
  119. package/src/core/geom/vec3/v3_cross.d.ts.map +1 -1
  120. package/src/core/geom/vec3/v3_cross.js +6 -2
  121. package/src/core/geom/vec3/v3_multiply.d.ts +6 -2
  122. package/src/core/geom/vec3/v3_multiply.d.ts.map +1 -1
  123. package/src/core/geom/vec3/v3_multiply.js +6 -2
  124. package/src/core/geom/vec3/v3_subtract.d.ts +6 -2
  125. package/src/core/geom/vec3/v3_subtract.d.ts.map +1 -1
  126. package/src/core/geom/vec3/v3_subtract.js +6 -2
  127. package/src/core/localization/Localization.js +1 -1
  128. package/src/core/math/random/randomSeed.d.ts +13 -0
  129. package/src/core/math/random/randomSeed.d.ts.map +1 -0
  130. package/src/core/math/random/randomSeed.js +16 -0
  131. package/src/core/math/spline/spline3_hermite_apply_transform.d.ts +50 -0
  132. package/src/core/math/spline/spline3_hermite_apply_transform.d.ts.map +1 -0
  133. package/src/core/math/spline/spline3_hermite_apply_transform.js +107 -0
  134. package/src/core/math/spline/spline3_hermite_reverse.d.ts +34 -0
  135. package/src/core/math/spline/spline3_hermite_reverse.d.ts.map +1 -0
  136. package/src/core/math/spline/spline3_hermite_reverse.js +49 -0
  137. package/src/core/math/statistics/hammersley_sequence.d.ts +17 -4
  138. package/src/core/math/statistics/hammersley_sequence.d.ts.map +1 -1
  139. package/src/core/math/statistics/hammersley_sequence.js +25 -16
  140. package/src/core/process/Future.d.ts.map +1 -1
  141. package/src/core/process/Future.js +12 -0
  142. package/src/core/process/PromiseWatcher.d.ts.map +1 -1
  143. package/src/core/process/PromiseWatcher.js +9 -2
  144. package/src/core/process/executor/ConcurrentExecutor.d.ts.map +1 -1
  145. package/src/core/process/executor/ConcurrentExecutor.js +12 -2
  146. package/src/core/process/worker/WorkerProxy.d.ts.map +1 -1
  147. package/src/core/process/worker/WorkerProxy.js +5 -2
  148. package/src/core/process/worker/extractTransferables.d.ts.map +1 -1
  149. package/src/core/process/worker/extractTransferables.js +4 -1
  150. package/src/engine/Engine.d.ts +12 -12
  151. package/src/engine/Engine.d.ts.map +1 -1
  152. package/src/engine/Engine.js +149 -10
  153. package/src/engine/EngineHarness.d.ts.map +1 -1
  154. package/src/engine/EngineHarness.js +4 -1
  155. package/src/engine/asset/loaders/ArrayBufferLoader.d.ts.map +1 -1
  156. package/src/engine/asset/loaders/ArrayBufferLoader.js +7 -0
  157. package/src/engine/ecs/speaker/lines/sets/LineSetDescription.d.ts.map +1 -1
  158. package/src/engine/ecs/speaker/lines/sets/LineSetDescription.js +3 -1
  159. package/src/engine/ecs/terrain/ecs/TerrainSystem.d.ts.map +1 -1
  160. package/src/engine/ecs/terrain/ecs/TerrainSystem.js +4 -1
  161. package/src/engine/ecs/terrain/tiles/TerrainTileManager.d.ts +29 -0
  162. package/src/engine/ecs/terrain/tiles/TerrainTileManager.d.ts.map +1 -1
  163. package/src/engine/ecs/terrain/tiles/TerrainTileManager.js +84 -23
  164. package/src/engine/graphics/CONTEXT_LOSS_RECOVERY_PLAN.md +446 -0
  165. package/src/engine/graphics/GraphicsEngine.d.ts +56 -7
  166. package/src/engine/graphics/GraphicsEngine.d.ts.map +1 -1
  167. package/src/engine/graphics/GraphicsEngine.js +196 -24
  168. package/src/engine/graphics/context/WebGLContextFailureReason.d.ts +9 -0
  169. package/src/engine/graphics/context/WebGLContextFailureReason.d.ts.map +1 -0
  170. package/src/engine/graphics/context/WebGLContextFailureReason.js +17 -0
  171. package/src/engine/graphics/context/WebGLContextMonitor.d.ts +106 -0
  172. package/src/engine/graphics/context/WebGLContextMonitor.d.ts.map +1 -0
  173. package/src/engine/graphics/context/WebGLContextMonitor.js +341 -0
  174. package/src/engine/graphics/context/WebGLContextState.d.ts +14 -0
  175. package/src/engine/graphics/context/WebGLContextState.d.ts.map +1 -0
  176. package/src/engine/graphics/context/WebGLContextState.js +24 -0
  177. package/src/engine/graphics/context/testWebGLContextLoss.d.ts +2 -0
  178. package/src/engine/graphics/context/testWebGLContextLoss.d.ts.map +1 -0
  179. package/src/engine/graphics/context/testWebGLContextLoss.js +696 -0
  180. package/src/engine/graphics/ecs/camera/serialization/CameraSerializationAdapter.d.ts.map +1 -1
  181. package/src/engine/graphics/ecs/camera/serialization/CameraSerializationAdapter.js +68 -32
  182. package/src/engine/graphics/ecs/camera/serialization/CameraSerializationUpgrader_0_1.d.ts +14 -0
  183. package/src/engine/graphics/ecs/camera/serialization/CameraSerializationUpgrader_0_1.d.ts.map +1 -0
  184. package/src/engine/graphics/ecs/camera/serialization/CameraSerializationUpgrader_0_1.js +41 -0
  185. package/src/engine/graphics/ecs/decal/v2/FPDecalSystem.js +1 -1
  186. package/src/engine/graphics/ecs/mesh-v2/ShadedGeometrySystem.d.ts.map +1 -1
  187. package/src/engine/graphics/ecs/mesh-v2/ShadedGeometrySystem.js +5 -0
  188. package/src/engine/graphics/ecs/trail2d/Trail2D.d.ts +5 -1
  189. package/src/engine/graphics/ecs/trail2d/Trail2D.d.ts.map +1 -1
  190. package/src/engine/graphics/ecs/trail2d/Trail2D.js +15 -0
  191. package/src/engine/graphics/ecs/trail2d/Trail2DSystem.d.ts +1 -1
  192. package/src/engine/graphics/ecs/trail2d/Trail2DSystem.d.ts.map +1 -1
  193. package/src/engine/graphics/ecs/trail2d/Trail2DSystem.js +2 -1
  194. package/src/engine/graphics/ecs/trail3d/Trail3D.d.ts +4 -1
  195. package/src/engine/graphics/ecs/trail3d/Trail3D.d.ts.map +1 -1
  196. package/src/engine/graphics/ecs/trail3d/Trail3D.js +488 -476
  197. package/src/engine/graphics/ecs/trail3d/Trail3DSystem.d.ts +1 -1
  198. package/src/engine/graphics/ecs/trail3d/Trail3DSystem.d.ts.map +1 -1
  199. package/src/engine/graphics/ecs/trail3d/Trail3DSystem.js +280 -253
  200. package/src/engine/graphics/geometry/MikkT/BuildNeighborsFast.d.ts.map +1 -1
  201. package/src/engine/graphics/geometry/MikkT/BuildNeighborsFast.js +3 -2
  202. package/src/engine/graphics/geometry/MikkT/GenerateSharedVerticesIndexList.d.ts.map +1 -1
  203. package/src/engine/graphics/geometry/MikkT/GenerateSharedVerticesIndexList.js +3 -1
  204. package/src/engine/graphics/geometry/computeMeshSurfaceArea.js +1 -1
  205. package/src/engine/graphics/load_and_set_cubemap_v0.d.ts +5 -0
  206. package/src/engine/graphics/load_and_set_cubemap_v0.d.ts.map +1 -1
  207. package/src/engine/graphics/load_and_set_cubemap_v0.js +26 -21
  208. package/src/engine/graphics/particles/particular/group/ParticleGroup.d.ts.map +1 -1
  209. package/src/engine/graphics/particles/particular/group/ParticleGroup.js +19 -8
  210. package/src/engine/graphics/particles/particular/group/optimizeCommandQueue.js +1 -1
  211. package/src/engine/graphics/texture/atlas/AtlasLookupTexture.d.ts.map +1 -1
  212. package/src/engine/graphics/texture/atlas/AtlasLookupTexture.js +10 -3
  213. package/src/engine/graphics/texture/atlas/TextureAtlas.d.ts.map +1 -1
  214. package/src/engine/graphics/texture/atlas/TextureAtlas.js +4 -1
  215. package/src/engine/graphics/texture/atlas/gpu/WebGLTextureAtlas.d.ts.map +1 -1
  216. package/src/engine/graphics/texture/atlas/gpu/WebGLTextureAtlas.js +11 -0
  217. package/src/engine/graphics/texture/cubemap/load_environment_map.d.ts.map +1 -1
  218. package/src/engine/graphics/texture/cubemap/load_environment_map.js +5 -2
  219. package/src/engine/graphics/texture/sampler/distance/computeSignedDistanceField_Chamfer.d.ts.map +1 -1
  220. package/src/engine/graphics/texture/sampler/distance/computeSignedDistanceField_Chamfer.js +26 -18
  221. package/src/engine/graphics/texture/sampler/filter/sampler2d_blur_gaussian.d.ts +15 -2
  222. package/src/engine/graphics/texture/sampler/filter/sampler2d_blur_gaussian.d.ts.map +1 -1
  223. package/src/engine/graphics/texture/sampler/filter/sampler2d_blur_gaussian.js +29 -3
  224. package/src/engine/graphics/texture/sampler/resize/sampler2d_scale_down_lanczos.d.ts +11 -1
  225. package/src/engine/graphics/texture/sampler/resize/sampler2d_scale_down_lanczos.d.ts.map +1 -1
  226. package/src/engine/graphics/texture/sampler/resize/sampler2d_scale_down_lanczos.js +158 -171
  227. package/src/engine/graphics/texture/sampler/sampler2d_paint.js +1 -1
  228. package/src/engine/graphics/texture/sampler/util/bitSet2Sampler2D.js +2 -2
  229. package/src/engine/input/ecs/util/TopDownCameraControllerHelper.d.ts.map +1 -1
  230. package/src/engine/input/ecs/util/TopDownCameraControllerHelper.js +10 -3
  231. package/src/engine/navigation/ecs/components/PathSerializationUpgrader_2_3.d.ts +14 -0
  232. package/src/engine/navigation/ecs/components/PathSerializationUpgrader_2_3.d.ts.map +1 -0
  233. package/src/engine/navigation/ecs/components/PathSerializationUpgrader_2_3.js +38 -0
  234. package/src/engine/network/orchestrator/ServerAuthoritativeClient.d.ts.map +1 -1
  235. package/src/engine/network/orchestrator/ServerAuthoritativeClient.js +433 -425
  236. package/src/engine/physics/constraint/solve_constraints.d.ts +4 -1
  237. package/src/engine/physics/constraint/solve_constraints.d.ts.map +1 -1
  238. package/src/engine/physics/constraint/solve_constraints.js +38 -13
  239. package/src/engine/physics/contact/ManifoldStore.d.ts +15 -3
  240. package/src/engine/physics/contact/ManifoldStore.d.ts.map +1 -1
  241. package/src/engine/physics/contact/ManifoldStore.js +15 -3
  242. package/src/engine/physics/ecs/Joint.d.ts +7 -4
  243. package/src/engine/physics/ecs/Joint.d.ts.map +1 -1
  244. package/src/engine/physics/ecs/Joint.js +7 -4
  245. package/src/engine/physics/ecs/PhysicsSystem.d.ts +14 -0
  246. package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
  247. package/src/engine/physics/ecs/PhysicsSystem.js +16 -0
  248. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  249. package/src/engine/physics/fluid/ecs/FluidSystem.d.ts +3 -3
  250. package/src/engine/physics/narrowphase/convex_convex_manifold.d.ts +15 -7
  251. package/src/engine/physics/narrowphase/convex_convex_manifold.d.ts.map +1 -1
  252. package/src/engine/physics/narrowphase/convex_convex_manifold.js +33 -10
  253. package/src/engine/physics/narrowphase/refine_ray_concave.d.ts +6 -2
  254. package/src/engine/physics/narrowphase/refine_ray_concave.d.ts.map +1 -1
  255. package/src/engine/physics/narrowphase/refine_ray_concave.js +6 -2
  256. package/src/engine/physics/narrowphase/refine_ray_hit.d.ts +6 -2
  257. package/src/engine/physics/narrowphase/refine_ray_hit.d.ts.map +1 -1
  258. package/src/engine/physics/narrowphase/refine_ray_hit.js +6 -2
  259. package/src/engine/physics/queries/raycast.d.ts.map +1 -1
  260. package/src/engine/physics/queries/raycast.js +11 -4
  261. package/src/engine/save/storage/IndexedDBStorage.d.ts.map +1 -1
  262. package/src/engine/save/storage/IndexedDBStorage.js +21 -3
  263. package/src/engine/simulation/Ticker.d.ts +12 -0
  264. package/src/engine/simulation/Ticker.d.ts.map +1 -1
  265. package/src/engine/simulation/Ticker.js +18 -0
  266. package/src/engine/sound/simulation/AcousticSimulator.d.ts.map +1 -1
  267. package/src/engine/sound/simulation/AcousticSimulator.js +9 -1
  268. package/src/engine/sound/simulation/core/VolumeField.d.ts +6 -2
  269. package/src/engine/sound/simulation/core/VolumeField.d.ts.map +1 -1
  270. package/src/engine/sound/simulation/core/VolumeField.js +6 -2
  271. package/src/engine/sound/simulation/probe/AcousticProbeField.d.ts +6 -2
  272. package/src/engine/sound/simulation/probe/AcousticProbeField.d.ts.map +1 -1
  273. package/src/engine/sound/simulation/probe/AcousticProbeField.js +6 -2
  274. package/src/engine/sound/simulation/probe/acoustic_probe_transfer.d.ts +6 -2
  275. package/src/engine/sound/simulation/probe/acoustic_probe_transfer.d.ts.map +1 -1
  276. package/src/engine/sound/simulation/probe/acoustic_probe_transfer.js +6 -2
  277. package/src/engine/sound/simulation/probe/bakeProbeReflectors.d.ts +3 -1
  278. package/src/engine/sound/simulation/probe/bakeProbeReflectors.d.ts.map +1 -1
  279. package/src/engine/sound/simulation/probe/bakeProbeReflectors.js +3 -1
  280. package/src/engine/ui/GUIEngine.d.ts.map +1 -1
  281. package/src/engine/ui/GUIEngine.js +8 -1
  282. package/src/generation/theme/TerrainTheme.d.ts.map +1 -1
  283. package/src/generation/theme/TerrainTheme.js +2 -1
  284. package/src/generation/theme/ThemeEngine.d.ts.map +1 -1
  285. package/src/generation/theme/ThemeEngine.js +6 -5
  286. package/src/view/ViewGroup.d.ts.map +1 -1
  287. package/src/view/ViewGroup.js +9 -7
  288. package/src/view/graphics/WebGLContextFailureView.d.ts +19 -0
  289. package/src/view/graphics/WebGLContextFailureView.d.ts.map +1 -0
  290. package/src/view/graphics/WebGLContextFailureView.js +76 -0
  291. package/src/view/minimap/Minimap.d.ts +8 -0
  292. package/src/view/minimap/Minimap.d.ts.map +1 -1
  293. package/src/view/minimap/Minimap.js +16 -3
  294. package/src/view/minimap/dom/MinimapMarkerView.d.ts.map +1 -1
  295. package/src/view/minimap/dom/MinimapMarkerView.js +3 -1
@@ -1,476 +1,488 @@
1
- import { assert } from "../../../../core/assert.js";
2
- import { FLOAT32_MAX } from "../../../../core/binary/FLOAT32_MAX.js";
3
- import { BvhClient } from "../../../../core/bvh2/bvh3/BvhClient.js";
4
- import { Color } from "../../../../core/color/Color.js";
5
- import Vector3 from "../../../../core/geom/Vector3.js";
6
- import { v3_distance } from "../../../../core/geom/vec3/v3_distance.js";
7
- import { v3_length } from "../../../../core/geom/vec3/v3_length.js";
8
- import { clamp01 } from "../../../../core/math/clamp01.js";
9
- import { EPSILON } from "../../../../core/math/EPSILON.js";
10
- import ThreeFactory from "../../three/ThreeFactory.js";
11
- import { TrailSpawnMode } from "../../trail/TrailSpawnMode.js";
12
- import { TUBE_ATTRIBUTE_ADDRESS_AGE } from "../../trail/tube/tube_attributes_spec.js";
13
- import { tube_frame_transport } from "../../trail/tube/tube_frame.js";
14
- import { TubeX } from "../../trail/tube/TubeX.js";
15
- import { TubeXMaterialSpec } from "../../trail/tube/TubeXMaterialSpec.js";
16
- import { Trail3DFlags } from "./Trail3DFlags.js";
17
-
18
- const DEFAULT_FLAGS = Trail3DFlags.Spawning | Trail3DFlags.Aging | Trail3DFlags.BoundsNeedUpdate;
19
-
20
- const DEFAULT_MAX_AGE = 5;
21
-
22
- const DEFAULT_WIDTH = 1;
23
-
24
- const DEFAULT_RADIAL_SEGMENTS = 8;
25
-
26
- const DEFAULT_SPAWN_DISTANCE = 1;
27
-
28
- // module-static scratch — keeps updateHead allocation-free
29
- const v3_head_pos = new Float64Array(3);
30
- const v3_pred_pos = new Float64Array(3);
31
- const v3_pred_n = new Float64Array(3);
32
- const frame_out = new Float32Array(6);
33
-
34
- /**
35
- * Tube-based 3D trail — the volumetric counterpart of {@link Trail2D}. Where
36
- * Trail2D extrudes a screen-facing ribbon in the shader, Trail3D lays down a tube
37
- * of {@link TubeX} knots, each carrying a tangent frame so the ring can be
38
- * extruded around the centre-line in world space.
39
- */
40
- class Trail3D {
41
-
42
- /**
43
- * Age at which a trail knot disappears, in seconds.
44
- * @type {number}
45
- */
46
- maxAge = DEFAULT_MAX_AGE;
47
-
48
- /**
49
- * Tube diameter.
50
- * @type {number}
51
- */
52
- width = DEFAULT_WIDTH;
53
-
54
- /**
55
- * Number of radial subdivisions around the tube. Higher = rounder tube. This is
56
- * a build-time parameter; changing it after build has no effect until rebuilt.
57
- * @type {number}
58
- */
59
- radialSegments = DEFAULT_RADIAL_SEGMENTS;
60
-
61
- /**
62
- * How new knots are committed behind the head.
63
- * @type {TrailSpawnMode|number}
64
- */
65
- spawnMode = TrailSpawnMode.Time;
66
-
67
- /**
68
- * Distance the head must travel before committing a new knot, used only when
69
- * {@link spawnMode} is {@link TrailSpawnMode.Distance}.
70
- * @type {number}
71
- */
72
- spawnDistance = DEFAULT_SPAWN_DISTANCE;
73
-
74
- /**
75
- * Current simulated time since trail birth.
76
- * @type {number}
77
- */
78
- time = 0;
79
-
80
- /**
81
- * @type {number}
82
- */
83
- trailingIndex = 0;
84
-
85
- /**
86
- * Time elapsed since the last knot was committed.
87
- * @type {number}
88
- */
89
- timeSinceLastUpdate = 0;
90
-
91
- /**
92
- * Distance the head has travelled since the last knot was committed.
93
- * @type {number}
94
- */
95
- distanceSinceLastUpdate = 0;
96
-
97
- /**
98
- * RGB tints the tube; alpha is the trail's base opacity, which the
99
- * age-driven fade scales down to zero.
100
- * @readonly
101
- * @type {Color}
102
- */
103
- color = new Color(1, 1, 1, 1);
104
-
105
- /**
106
- * World offset.
107
- * @readonly
108
- * @type {Vector3}
109
- */
110
- offset = new Vector3();
111
-
112
- /**
113
- * transient
114
- * @type {TubeX|null}
115
- */
116
- tube = null;
117
-
118
- /**
119
- * transient
120
- * @type {Mesh|null}
121
- */
122
- mesh = null;
123
-
124
- /**
125
- * transient
126
- * @type {TubeXMaterialSpec}
127
- */
128
- material = new TubeXMaterialSpec();
129
-
130
- /**
131
- * @readonly
132
- * @type {BvhClient}
133
- */
134
- bvh = new BvhClient();
135
-
136
- /**
137
- * @private
138
- * @type {Trail3DFlags|number}
139
- */
140
- flags = DEFAULT_FLAGS;
141
-
142
- dispose() {
143
- if (this.tube === null) {
144
- // nothing to dispose
145
- return;
146
- }
147
-
148
- this.tube.dispose();
149
- this.tube = null;
150
- }
151
-
152
- get textureURL() {
153
- return this.material.diffuse;
154
- }
155
-
156
- set textureURL(v) {
157
- this.material.diffuse = v;
158
- }
159
-
160
- get depthWrite() {
161
- return this.material.depthWrite;
162
- }
163
-
164
- set depthWrite(v) {
165
- this.material.depthWrite = v;
166
- }
167
-
168
- /**
169
- * Whether the trail's tube processes standard scene lighting. When enabled the
170
- * tube shades as a matte (Lambert) surface under the scene's ambient /
171
- * hemisphere / light-probe / directional / point / spot lights and receives
172
- * shadows; it never casts them. Under the Forward+ pipeline the material is
173
- * additionally rewritten by the renderer's material manager, so clustered
174
- * point lights and decals apply as well. When disabled (default) the tube
175
- * renders unlit.
176
- *
177
- * Stored in {@link Trail3DFlags.Lit}. This is a build-time option — it selects
178
- * the compiled material and the mesh's shadow settings — so it must be set
179
- * before the trail is built / registered with the system, and cannot change
180
- * afterwards.
181
- *
182
- * @returns {boolean}
183
- */
184
- get lightingEnabled() {
185
- return this.getFlag(Trail3DFlags.Lit);
186
- }
187
-
188
- /**
189
- * @param {boolean} v
190
- */
191
- set lightingEnabled(v) {
192
- if (v === this.lightingEnabled) {
193
- return;
194
- }
195
-
196
- assert.notOk(this.getFlag(Trail3DFlags.Built), "lightingEnabled cannot change after the trail is built");
197
-
198
- this.writeFlag(Trail3DFlags.Lit, v);
199
- }
200
-
201
- /**
202
- * @param {number|Trail3DFlags} flag
203
- * @returns {void}
204
- */
205
- setFlag(flag) {
206
- this.flags |= flag;
207
- }
208
-
209
- /**
210
- * @param {number|Trail3DFlags} flag
211
- * @returns {void}
212
- */
213
- clearFlag(flag) {
214
- this.flags &= ~flag;
215
- }
216
-
217
- /**
218
- * @param {number|Trail3DFlags} flag
219
- * @param {boolean} value
220
- */
221
- writeFlag(flag, value) {
222
- if (value) {
223
- this.setFlag(flag);
224
- } else {
225
- this.clearFlag(flag);
226
- }
227
- }
228
-
229
- /**
230
- * @param {number|Trail3DFlags} flag
231
- * @returns {boolean}
232
- */
233
- getFlag(flag) {
234
- return (this.flags & flag) === flag;
235
- }
236
-
237
- /**
238
- * @param {number} segment_count
239
- */
240
- build(segment_count) {
241
-
242
- const tube = new TubeX();
243
-
244
- tube.buildGeometry();
245
- tube.setCount(segment_count, this.radialSegments);
246
-
247
- const geometry = tube.getGeometry();
248
-
249
- const mesh = ThreeFactory.createMesh(geometry, null);
250
-
251
- // receive-only lighting: castShadow stays false. The geometry's `position`
252
- // attribute holds ring CENTRES (the surface is extruded in the material's
253
- // vertex stage), so a stock depth pass would render a degenerate line anyway.
254
- mesh.receiveShadow = this.getFlag(Trail3DFlags.Lit);
255
-
256
- this.tube = tube;
257
- this.mesh = mesh;
258
- }
259
-
260
- /**
261
- * Clear the trail's geometry and reset its state.
262
- */
263
- clear() {
264
- const tube = this.tube;
265
-
266
- if (tube === null) {
267
- // nothing to clear
268
- return;
269
- }
270
-
271
- const n = tube.getCount();
272
-
273
- for (let i = 0; i < n; i++) {
274
- tube.setKnotAttribute_Scalar(i, TUBE_ATTRIBUTE_ADDRESS_AGE, FLOAT32_MAX);
275
- tube.setKnotAlpha(i, 0);
276
- }
277
-
278
- // Ages/alphas alone don't erase the tube: knot POSITIONS still trace the old
279
- // path. Defer a geometry reset to the next updateHead() (the first code to
280
- // know the post-clear position), which collapses the whole tube onto the head.
281
- this.setFlag(Trail3DFlags.Reseed);
282
- }
283
-
284
- static fromJSON(json) {
285
- const r = new Trail3D();
286
-
287
- r.fromJSON(json);
288
-
289
- return r;
290
- }
291
-
292
- fromJSON({
293
- maxAge = DEFAULT_MAX_AGE,
294
- width = DEFAULT_WIDTH,
295
- radialSegments = DEFAULT_RADIAL_SEGMENTS,
296
- spawnMode = TrailSpawnMode.Time,
297
- spawnDistance = DEFAULT_SPAWN_DISTANCE,
298
- textureURL,
299
- depthWrite = false,
300
- lightingEnabled = false,
301
- offset = Vector3.zero,
302
- color = { r: 1, g: 1, b: 1, a: 1 }
303
- }) {
304
-
305
- this.maxAge = maxAge;
306
- this.width = width;
307
- this.radialSegments = radialSegments;
308
- this.spawnMode = spawnMode;
309
- this.spawnDistance = spawnDistance;
310
- this.textureURL = textureURL;
311
- this.depthWrite = depthWrite;
312
- this.lightingEnabled = lightingEnabled;
313
-
314
- this.offset.fromJSON(offset);
315
- this.color.fromJSON(color);
316
- }
317
-
318
- toJSON() {
319
- return {
320
- maxAge: this.maxAge,
321
- width: this.width,
322
- radialSegments: this.radialSegments,
323
- spawnMode: this.spawnMode,
324
- spawnDistance: this.spawnDistance,
325
- color: this.color.toJSON(),
326
- textureURL: this.textureURL,
327
- depthWrite: this.depthWrite,
328
- lightingEnabled: this.lightingEnabled,
329
- offset: this.offset.toJSON()
330
- };
331
- }
332
-
333
- /**
334
- * @param {Trail3D} other
335
- */
336
- equals(other) {
337
- return this.textureURL === other.textureURL
338
- && this.depthWrite === other.depthWrite
339
- && this.lightingEnabled === other.lightingEnabled
340
- && this.width === other.width
341
- && this.radialSegments === other.radialSegments
342
- && this.maxAge === other.maxAge
343
- && this.spawnMode === other.spawnMode
344
- && this.spawnDistance === other.spawnDistance
345
- && this.color.equals(other.color)
346
- && this.offset.equals(other.offset)
347
- ;
348
- }
349
-
350
- /**
351
- * Orient the head knot's ring by parallel-transporting the frame from its
352
- * predecessor (the last committed knot). No-op until the head has separated
353
- * from its predecessor (e.g. right after build), preserving the existing frame.
354
- * @param {number} head_index
355
- * @param {number} x
356
- * @param {number} y
357
- * @param {number} z
358
- * @returns {void}
359
- */
360
- #updateHeadFrame(head_index, x, y, z) {
361
- const tube = this.tube;
362
-
363
- const predecessor_index = (head_index + 1) % tube.getCount();
364
-
365
- tube.getKnotPosition(v3_pred_pos, predecessor_index);
366
-
367
- let tx = x - v3_pred_pos[0];
368
- let ty = y - v3_pred_pos[1];
369
- let tz = z - v3_pred_pos[2];
370
-
371
- const t_length = v3_length(tx, ty, tz);
372
-
373
- if (t_length <= EPSILON) {
374
- // head and predecessor coincide (no direction yet) — keep current frame
375
- return;
376
- }
377
-
378
- const inv = 1 / t_length;
379
- tx *= inv;
380
- ty *= inv;
381
- tz *= inv;
382
-
383
- tube.getKnotNormal(v3_pred_n, predecessor_index);
384
-
385
- tube_frame_transport(
386
- frame_out, 0,
387
- tx, ty, tz,
388
- v3_pred_n[0], v3_pred_n[1], v3_pred_n[2]
389
- );
390
-
391
- tube.setKnotFrame(
392
- head_index,
393
- frame_out[0], frame_out[1], frame_out[2],
394
- frame_out[3], frame_out[4], frame_out[5]
395
- );
396
- }
397
-
398
- /**
399
- * @param {number} x
400
- * @param {number} y
401
- * @param {number} z
402
- * @param {number} head_age
403
- * @returns {boolean} whether the head position changed
404
- */
405
- updateHead(x, y, z, head_age) {
406
- const tube = this.tube;
407
-
408
- const maxAge = this.maxAge;
409
-
410
- if (this.getFlag(Trail3DFlags.Reseed)) {
411
- // post-clear() re-seed: collapse every knot onto the new head position so
412
- // no segment bridges post-clear geometry to pre-clear history.
413
- const n = tube.getCount();
414
- for (let i = 0; i < n; i++) {
415
- tube.setKnotPosition(i, x, y, z);
416
- }
417
- this.timeSinceLastUpdate = 0;
418
- this.distanceSinceLastUpdate = 0;
419
- this.clearFlag(Trail3DFlags.Reseed);
420
- }
421
-
422
- const refitTimeDelta = maxAge / tube.getCount();
423
-
424
- let head_index = tube.getHeadIndex();
425
- tube.getKnotPosition(v3_head_pos, head_index);
426
-
427
- const head_position_changed = x !== v3_head_pos[0]
428
- || y !== v3_head_pos[1]
429
- || z !== v3_head_pos[2];
430
-
431
- if (head_position_changed) {
432
- this.distanceSinceLastUpdate += v3_distance(
433
- v3_head_pos[0], v3_head_pos[1], v3_head_pos[2],
434
- x, y, z
435
- );
436
- }
437
-
438
- const should_spawn = this.spawnMode === TrailSpawnMode.Distance
439
- ? this.distanceSinceLastUpdate >= this.spawnDistance
440
- : this.timeSinceLastUpdate >= refitTimeDelta;
441
-
442
- if (should_spawn && head_position_changed) {
443
- // commit a new knot: both accumulators reset so a mid-life mode switch
444
- // can't carry stale accumulation across.
445
- this.timeSinceLastUpdate = 0;
446
- this.distanceSinceLastUpdate = 0;
447
-
448
- tube.rotate();
449
-
450
- head_index = tube.getHeadIndex();
451
- }
452
-
453
- if (head_position_changed) {
454
- this.#updateHeadFrame(head_index, x, y, z);
455
-
456
- tube.setKnotPosition(head_index, x, y, z);
457
-
458
- this.setFlag(Trail3DFlags.BoundsNeedUpdate);
459
- }
460
-
461
- // set head to fresh value; alpha follows the same fade law the simulator
462
- // applies every tick, so the knot doesn't pop when it stops being the head
463
- tube.setKnotAttribute_Scalar(head_index, TUBE_ATTRIBUTE_ADDRESS_AGE, head_age);
464
- tube.setKnotAlpha(head_index, (1 - clamp01(head_age / maxAge)) * this.color.w);
465
- tube.setKnotThickness(head_index, this.width);
466
-
467
- return head_position_changed;
468
- }
469
-
470
- }
471
-
472
- Trail3D.typeName = "Trail3D";
473
-
474
- Trail3D.serializable = false;
475
-
476
- export default Trail3D;
1
+ import { assert } from "../../../../core/assert.js";
2
+ import { FLOAT32_MAX } from "../../../../core/binary/FLOAT32_MAX.js";
3
+ import { BvhClient } from "../../../../core/bvh2/bvh3/BvhClient.js";
4
+ import { Color } from "../../../../core/color/Color.js";
5
+ import Vector3 from "../../../../core/geom/Vector3.js";
6
+ import { v3_distance } from "../../../../core/geom/vec3/v3_distance.js";
7
+ import { v3_length } from "../../../../core/geom/vec3/v3_length.js";
8
+ import { clamp01 } from "../../../../core/math/clamp01.js";
9
+ import { EPSILON } from "../../../../core/math/EPSILON.js";
10
+ import ThreeFactory from "../../three/ThreeFactory.js";
11
+ import { TrailSpawnMode } from "../../trail/TrailSpawnMode.js";
12
+ import { TUBE_ATTRIBUTE_ADDRESS_AGE } from "../../trail/tube/tube_attributes_spec.js";
13
+ import { tube_frame_transport } from "../../trail/tube/tube_frame.js";
14
+ import { TubeX } from "../../trail/tube/TubeX.js";
15
+ import { TubeXMaterialSpec } from "../../trail/tube/TubeXMaterialSpec.js";
16
+ import { Trail3DFlags } from "./Trail3DFlags.js";
17
+
18
+ const DEFAULT_FLAGS = Trail3DFlags.Spawning | Trail3DFlags.Aging | Trail3DFlags.BoundsNeedUpdate;
19
+
20
+ const DEFAULT_MAX_AGE = 5;
21
+
22
+ const DEFAULT_WIDTH = 1;
23
+
24
+ const DEFAULT_RADIAL_SEGMENTS = 8;
25
+
26
+ const DEFAULT_SPAWN_DISTANCE = 1;
27
+
28
+ // module-static scratch — keeps updateHead allocation-free
29
+ const v3_head_pos = new Float64Array(3);
30
+ const v3_pred_pos = new Float64Array(3);
31
+ const v3_pred_n = new Float64Array(3);
32
+ const frame_out = new Float32Array(6);
33
+
34
+ /**
35
+ * Tube-based 3D trail — the volumetric counterpart of {@link Trail2D}. Where
36
+ * Trail2D extrudes a screen-facing ribbon in the shader, Trail3D lays down a tube
37
+ * of {@link TubeX} knots, each carrying a tangent frame so the ring can be
38
+ * extruded around the centre-line in world space.
39
+ */
40
+ class Trail3D {
41
+
42
+ /**
43
+ * Age at which a trail knot disappears, in seconds.
44
+ * @type {number}
45
+ */
46
+ maxAge = DEFAULT_MAX_AGE;
47
+
48
+ /**
49
+ * Tube diameter.
50
+ * @type {number}
51
+ */
52
+ width = DEFAULT_WIDTH;
53
+
54
+ /**
55
+ * Number of radial subdivisions around the tube. Higher = rounder tube. This is
56
+ * a build-time parameter; changing it after build has no effect until rebuilt.
57
+ * @type {number}
58
+ */
59
+ radialSegments = DEFAULT_RADIAL_SEGMENTS;
60
+
61
+ /**
62
+ * How new knots are committed behind the head.
63
+ * @type {TrailSpawnMode|number}
64
+ */
65
+ spawnMode = TrailSpawnMode.Time;
66
+
67
+ /**
68
+ * Distance the head must travel before committing a new knot, used only when
69
+ * {@link spawnMode} is {@link TrailSpawnMode.Distance}.
70
+ * @type {number}
71
+ */
72
+ spawnDistance = DEFAULT_SPAWN_DISTANCE;
73
+
74
+ /**
75
+ * Current simulated time since trail birth.
76
+ * @type {number}
77
+ */
78
+ time = 0;
79
+
80
+ /**
81
+ * @type {number}
82
+ */
83
+ trailingIndex = 0;
84
+
85
+ /**
86
+ * Time elapsed since the last knot was committed.
87
+ * @type {number}
88
+ */
89
+ timeSinceLastUpdate = 0;
90
+
91
+ /**
92
+ * Distance the head has travelled since the last knot was committed.
93
+ * @type {number}
94
+ */
95
+ distanceSinceLastUpdate = 0;
96
+
97
+ /**
98
+ * RGB tints the tube; alpha is the trail's base opacity, which the
99
+ * age-driven fade scales down to zero.
100
+ * @readonly
101
+ * @type {Color}
102
+ */
103
+ color = new Color(1, 1, 1, 1);
104
+
105
+ /**
106
+ * Where the trail's head sits relative to the entity, in the entity's LOCAL
107
+ * frame: {@link Trail3DSystem} carries it through the entity's transform, so
108
+ * the offset rotates and scales with the entity rather than being a fixed
109
+ * world-space displacement.
110
+ * @readonly
111
+ * @type {Vector3}
112
+ */
113
+ offset = new Vector3();
114
+
115
+ /**
116
+ * transient
117
+ * @type {TubeX|null}
118
+ */
119
+ tube = null;
120
+
121
+ /**
122
+ * transient
123
+ * @type {Mesh|null}
124
+ */
125
+ mesh = null;
126
+
127
+ /**
128
+ * transient
129
+ * @type {TubeXMaterialSpec}
130
+ */
131
+ material = new TubeXMaterialSpec();
132
+
133
+ /**
134
+ * @readonly
135
+ * @type {BvhClient}
136
+ */
137
+ bvh = new BvhClient();
138
+
139
+ /**
140
+ * @private
141
+ * @type {Trail3DFlags|number}
142
+ */
143
+ flags = DEFAULT_FLAGS;
144
+
145
+ dispose() {
146
+ if (this.tube === null) {
147
+ // nothing to dispose
148
+ return;
149
+ }
150
+
151
+ this.tube.dispose();
152
+ this.tube = null;
153
+
154
+ // The mesh's geometry died with the tube, so the component must stop
155
+ // claiming to be built: link() would otherwise take its "already built"
156
+ // branch, hang a material on the dead mesh and leave the tube null, and the
157
+ // first update would hand that null to the simulator. Dropping Built makes a
158
+ // re-link rebuild instead. The material is owned by the tube plugin's cache,
159
+ // so it is not ours to dispose — only to forget.
160
+ this.mesh = null;
161
+ this.clearFlag(Trail3DFlags.Built);
162
+ }
163
+
164
+ get textureURL() {
165
+ return this.material.diffuse;
166
+ }
167
+
168
+ set textureURL(v) {
169
+ this.material.diffuse = v;
170
+ }
171
+
172
+ get depthWrite() {
173
+ return this.material.depthWrite;
174
+ }
175
+
176
+ set depthWrite(v) {
177
+ this.material.depthWrite = v;
178
+ }
179
+
180
+ /**
181
+ * Whether the trail's tube processes standard scene lighting. When enabled the
182
+ * tube shades as a matte (Lambert) surface under the scene's ambient /
183
+ * hemisphere / light-probe / directional / point / spot lights and receives
184
+ * shadows; it never casts them. Under the Forward+ pipeline the material is
185
+ * additionally rewritten by the renderer's material manager, so clustered
186
+ * point lights and decals apply as well. When disabled (default) the tube
187
+ * renders unlit.
188
+ *
189
+ * Stored in {@link Trail3DFlags.Lit}. This is a build-time option — it selects
190
+ * the compiled material and the mesh's shadow settings — so it must be set
191
+ * before the trail is built / registered with the system, and cannot change
192
+ * afterwards.
193
+ *
194
+ * @returns {boolean}
195
+ */
196
+ get lightingEnabled() {
197
+ return this.getFlag(Trail3DFlags.Lit);
198
+ }
199
+
200
+ /**
201
+ * @param {boolean} v
202
+ */
203
+ set lightingEnabled(v) {
204
+ if (v === this.lightingEnabled) {
205
+ return;
206
+ }
207
+
208
+ assert.notOk(this.getFlag(Trail3DFlags.Built), "lightingEnabled cannot change after the trail is built");
209
+
210
+ this.writeFlag(Trail3DFlags.Lit, v);
211
+ }
212
+
213
+ /**
214
+ * @param {number|Trail3DFlags} flag
215
+ * @returns {void}
216
+ */
217
+ setFlag(flag) {
218
+ this.flags |= flag;
219
+ }
220
+
221
+ /**
222
+ * @param {number|Trail3DFlags} flag
223
+ * @returns {void}
224
+ */
225
+ clearFlag(flag) {
226
+ this.flags &= ~flag;
227
+ }
228
+
229
+ /**
230
+ * @param {number|Trail3DFlags} flag
231
+ * @param {boolean} value
232
+ */
233
+ writeFlag(flag, value) {
234
+ if (value) {
235
+ this.setFlag(flag);
236
+ } else {
237
+ this.clearFlag(flag);
238
+ }
239
+ }
240
+
241
+ /**
242
+ * @param {number|Trail3DFlags} flag
243
+ * @returns {boolean}
244
+ */
245
+ getFlag(flag) {
246
+ return (this.flags & flag) === flag;
247
+ }
248
+
249
+ /**
250
+ * @param {number} segment_count
251
+ */
252
+ build(segment_count) {
253
+
254
+ const tube = new TubeX();
255
+
256
+ tube.buildGeometry();
257
+ tube.setCount(segment_count, this.radialSegments);
258
+
259
+ const geometry = tube.getGeometry();
260
+
261
+ const mesh = ThreeFactory.createMesh(geometry, null);
262
+
263
+ // receive-only lighting: castShadow stays false. The geometry's `position`
264
+ // attribute holds ring CENTRES (the surface is extruded in the material's
265
+ // vertex stage), so a stock depth pass would render a degenerate line anyway.
266
+ mesh.receiveShadow = this.getFlag(Trail3DFlags.Lit);
267
+
268
+ this.tube = tube;
269
+ this.mesh = mesh;
270
+ }
271
+
272
+ /**
273
+ * Clear the trail's geometry and reset its state.
274
+ */
275
+ clear() {
276
+ const tube = this.tube;
277
+
278
+ if (tube === null) {
279
+ // nothing to clear
280
+ return;
281
+ }
282
+
283
+ const n = tube.getCount();
284
+
285
+ for (let i = 0; i < n; i++) {
286
+ tube.setKnotAttribute_Scalar(i, TUBE_ATTRIBUTE_ADDRESS_AGE, FLOAT32_MAX);
287
+ tube.setKnotAlpha(i, 0);
288
+ }
289
+
290
+ // Ages/alphas alone don't erase the tube: knot POSITIONS still trace the old
291
+ // path. Defer a geometry reset to the next updateHead() (the first code to
292
+ // know the post-clear position), which collapses the whole tube onto the head.
293
+ this.setFlag(Trail3DFlags.Reseed);
294
+ }
295
+
296
+ static fromJSON(json) {
297
+ const r = new Trail3D();
298
+
299
+ r.fromJSON(json);
300
+
301
+ return r;
302
+ }
303
+
304
+ fromJSON({
305
+ maxAge = DEFAULT_MAX_AGE,
306
+ width = DEFAULT_WIDTH,
307
+ radialSegments = DEFAULT_RADIAL_SEGMENTS,
308
+ spawnMode = TrailSpawnMode.Time,
309
+ spawnDistance = DEFAULT_SPAWN_DISTANCE,
310
+ textureURL,
311
+ depthWrite = false,
312
+ lightingEnabled = false,
313
+ offset = Vector3.zero,
314
+ color = { r: 1, g: 1, b: 1, a: 1 }
315
+ }) {
316
+
317
+ this.maxAge = maxAge;
318
+ this.width = width;
319
+ this.radialSegments = radialSegments;
320
+ this.spawnMode = spawnMode;
321
+ this.spawnDistance = spawnDistance;
322
+ this.textureURL = textureURL;
323
+ this.depthWrite = depthWrite;
324
+ this.lightingEnabled = lightingEnabled;
325
+
326
+ this.offset.fromJSON(offset);
327
+ this.color.fromJSON(color);
328
+ }
329
+
330
+ toJSON() {
331
+ return {
332
+ maxAge: this.maxAge,
333
+ width: this.width,
334
+ radialSegments: this.radialSegments,
335
+ spawnMode: this.spawnMode,
336
+ spawnDistance: this.spawnDistance,
337
+ color: this.color.toJSON(),
338
+ textureURL: this.textureURL,
339
+ depthWrite: this.depthWrite,
340
+ lightingEnabled: this.lightingEnabled,
341
+ offset: this.offset.toJSON()
342
+ };
343
+ }
344
+
345
+ /**
346
+ * @param {Trail3D} other
347
+ */
348
+ equals(other) {
349
+ return this.textureURL === other.textureURL
350
+ && this.depthWrite === other.depthWrite
351
+ && this.lightingEnabled === other.lightingEnabled
352
+ && this.width === other.width
353
+ && this.radialSegments === other.radialSegments
354
+ && this.maxAge === other.maxAge
355
+ && this.spawnMode === other.spawnMode
356
+ && this.spawnDistance === other.spawnDistance
357
+ && this.color.equals(other.color)
358
+ && this.offset.equals(other.offset)
359
+ ;
360
+ }
361
+
362
+ /**
363
+ * Orient the head knot's ring by parallel-transporting the frame from its
364
+ * predecessor (the last committed knot). No-op until the head has separated
365
+ * from its predecessor (e.g. right after build), preserving the existing frame.
366
+ * @param {number} head_index
367
+ * @param {number} x
368
+ * @param {number} y
369
+ * @param {number} z
370
+ * @returns {void}
371
+ */
372
+ #updateHeadFrame(head_index, x, y, z) {
373
+ const tube = this.tube;
374
+
375
+ const predecessor_index = (head_index + 1) % tube.getCount();
376
+
377
+ tube.getKnotPosition(v3_pred_pos, predecessor_index);
378
+
379
+ let tx = x - v3_pred_pos[0];
380
+ let ty = y - v3_pred_pos[1];
381
+ let tz = z - v3_pred_pos[2];
382
+
383
+ const t_length = v3_length(tx, ty, tz);
384
+
385
+ if (t_length <= EPSILON) {
386
+ // head and predecessor coincide (no direction yet) — keep current frame
387
+ return;
388
+ }
389
+
390
+ const inv = 1 / t_length;
391
+ tx *= inv;
392
+ ty *= inv;
393
+ tz *= inv;
394
+
395
+ tube.getKnotNormal(v3_pred_n, predecessor_index);
396
+
397
+ tube_frame_transport(
398
+ frame_out, 0,
399
+ tx, ty, tz,
400
+ v3_pred_n[0], v3_pred_n[1], v3_pred_n[2]
401
+ );
402
+
403
+ tube.setKnotFrame(
404
+ head_index,
405
+ frame_out[0], frame_out[1], frame_out[2],
406
+ frame_out[3], frame_out[4], frame_out[5]
407
+ );
408
+ }
409
+
410
+ /**
411
+ * @param {number} x
412
+ * @param {number} y
413
+ * @param {number} z
414
+ * @param {number} head_age
415
+ * @returns {boolean} whether the head position changed
416
+ */
417
+ updateHead(x, y, z, head_age) {
418
+ const tube = this.tube;
419
+
420
+ const maxAge = this.maxAge;
421
+
422
+ if (this.getFlag(Trail3DFlags.Reseed)) {
423
+ // post-clear() re-seed: collapse every knot onto the new head position so
424
+ // no segment bridges post-clear geometry to pre-clear history.
425
+ const n = tube.getCount();
426
+ for (let i = 0; i < n; i++) {
427
+ tube.setKnotPosition(i, x, y, z);
428
+ }
429
+ this.timeSinceLastUpdate = 0;
430
+ this.distanceSinceLastUpdate = 0;
431
+ this.clearFlag(Trail3DFlags.Reseed);
432
+ }
433
+
434
+ const refitTimeDelta = maxAge / tube.getCount();
435
+
436
+ let head_index = tube.getHeadIndex();
437
+ tube.getKnotPosition(v3_head_pos, head_index);
438
+
439
+ const head_position_changed = x !== v3_head_pos[0]
440
+ || y !== v3_head_pos[1]
441
+ || z !== v3_head_pos[2];
442
+
443
+ if (head_position_changed) {
444
+ this.distanceSinceLastUpdate += v3_distance(
445
+ v3_head_pos[0], v3_head_pos[1], v3_head_pos[2],
446
+ x, y, z
447
+ );
448
+ }
449
+
450
+ const should_spawn = this.spawnMode === TrailSpawnMode.Distance
451
+ ? this.distanceSinceLastUpdate >= this.spawnDistance
452
+ : this.timeSinceLastUpdate >= refitTimeDelta;
453
+
454
+ if (should_spawn && head_position_changed) {
455
+ // commit a new knot: both accumulators reset so a mid-life mode switch
456
+ // can't carry stale accumulation across.
457
+ this.timeSinceLastUpdate = 0;
458
+ this.distanceSinceLastUpdate = 0;
459
+
460
+ tube.rotate();
461
+
462
+ head_index = tube.getHeadIndex();
463
+ }
464
+
465
+ if (head_position_changed) {
466
+ this.#updateHeadFrame(head_index, x, y, z);
467
+
468
+ tube.setKnotPosition(head_index, x, y, z);
469
+
470
+ this.setFlag(Trail3DFlags.BoundsNeedUpdate);
471
+ }
472
+
473
+ // set head to fresh value; alpha follows the same fade law the simulator
474
+ // applies every tick, so the knot doesn't pop when it stops being the head
475
+ tube.setKnotAttribute_Scalar(head_index, TUBE_ATTRIBUTE_ADDRESS_AGE, head_age);
476
+ tube.setKnotAlpha(head_index, (1 - clamp01(head_age / maxAge)) * this.color.w);
477
+ tube.setKnotThickness(head_index, this.width);
478
+
479
+ return head_position_changed;
480
+ }
481
+
482
+ }
483
+
484
+ Trail3D.typeName = "Trail3D";
485
+
486
+ Trail3D.serializable = false;
487
+
488
+ export default Trail3D;