@woosh/meep-engine 2.168.1 → 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 (287) 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/asset/loaders/ArrayBufferLoader.d.ts.map +1 -1
  154. package/src/engine/asset/loaders/ArrayBufferLoader.js +7 -0
  155. package/src/engine/ecs/speaker/lines/sets/LineSetDescription.d.ts.map +1 -1
  156. package/src/engine/ecs/speaker/lines/sets/LineSetDescription.js +3 -1
  157. package/src/engine/ecs/terrain/ecs/TerrainSystem.d.ts.map +1 -1
  158. package/src/engine/ecs/terrain/ecs/TerrainSystem.js +4 -1
  159. package/src/engine/ecs/terrain/tiles/TerrainTileManager.d.ts +29 -0
  160. package/src/engine/ecs/terrain/tiles/TerrainTileManager.d.ts.map +1 -1
  161. package/src/engine/ecs/terrain/tiles/TerrainTileManager.js +84 -23
  162. package/src/engine/graphics/CONTEXT_LOSS_RECOVERY_PLAN.md +446 -0
  163. package/src/engine/graphics/GraphicsEngine.d.ts +56 -7
  164. package/src/engine/graphics/GraphicsEngine.d.ts.map +1 -1
  165. package/src/engine/graphics/GraphicsEngine.js +196 -24
  166. package/src/engine/graphics/context/WebGLContextFailureReason.d.ts +9 -0
  167. package/src/engine/graphics/context/WebGLContextFailureReason.d.ts.map +1 -0
  168. package/src/engine/graphics/context/WebGLContextFailureReason.js +17 -0
  169. package/src/engine/graphics/context/WebGLContextMonitor.d.ts +106 -0
  170. package/src/engine/graphics/context/WebGLContextMonitor.d.ts.map +1 -0
  171. package/src/engine/graphics/context/WebGLContextMonitor.js +341 -0
  172. package/src/engine/graphics/context/WebGLContextState.d.ts +14 -0
  173. package/src/engine/graphics/context/WebGLContextState.d.ts.map +1 -0
  174. package/src/engine/graphics/context/WebGLContextState.js +24 -0
  175. package/src/engine/graphics/context/testWebGLContextLoss.d.ts +2 -0
  176. package/src/engine/graphics/context/testWebGLContextLoss.d.ts.map +1 -0
  177. package/src/engine/graphics/context/testWebGLContextLoss.js +696 -0
  178. package/src/engine/graphics/ecs/camera/serialization/CameraSerializationAdapter.d.ts.map +1 -1
  179. package/src/engine/graphics/ecs/camera/serialization/CameraSerializationAdapter.js +68 -32
  180. package/src/engine/graphics/ecs/camera/serialization/CameraSerializationUpgrader_0_1.d.ts +14 -0
  181. package/src/engine/graphics/ecs/camera/serialization/CameraSerializationUpgrader_0_1.d.ts.map +1 -0
  182. package/src/engine/graphics/ecs/camera/serialization/CameraSerializationUpgrader_0_1.js +41 -0
  183. package/src/engine/graphics/ecs/decal/v2/FPDecalSystem.js +1 -1
  184. package/src/engine/graphics/ecs/mesh-v2/ShadedGeometrySystem.d.ts.map +1 -1
  185. package/src/engine/graphics/ecs/mesh-v2/ShadedGeometrySystem.js +5 -0
  186. package/src/engine/graphics/ecs/trail2d/Trail2DSystem.d.ts +1 -1
  187. package/src/engine/graphics/ecs/trail2d/Trail2DSystem.d.ts.map +1 -1
  188. package/src/engine/graphics/ecs/trail2d/Trail2DSystem.js +2 -1
  189. package/src/engine/graphics/ecs/trail3d/Trail3DSystem.d.ts +1 -1
  190. package/src/engine/graphics/ecs/trail3d/Trail3DSystem.d.ts.map +1 -1
  191. package/src/engine/graphics/ecs/trail3d/Trail3DSystem.js +3 -5
  192. package/src/engine/graphics/geometry/MikkT/BuildNeighborsFast.d.ts.map +1 -1
  193. package/src/engine/graphics/geometry/MikkT/BuildNeighborsFast.js +3 -2
  194. package/src/engine/graphics/geometry/MikkT/GenerateSharedVerticesIndexList.d.ts.map +1 -1
  195. package/src/engine/graphics/geometry/MikkT/GenerateSharedVerticesIndexList.js +3 -1
  196. package/src/engine/graphics/geometry/computeMeshSurfaceArea.js +1 -1
  197. package/src/engine/graphics/load_and_set_cubemap_v0.d.ts +5 -0
  198. package/src/engine/graphics/load_and_set_cubemap_v0.d.ts.map +1 -1
  199. package/src/engine/graphics/load_and_set_cubemap_v0.js +26 -21
  200. package/src/engine/graphics/particles/particular/group/ParticleGroup.d.ts.map +1 -1
  201. package/src/engine/graphics/particles/particular/group/ParticleGroup.js +19 -8
  202. package/src/engine/graphics/particles/particular/group/optimizeCommandQueue.js +1 -1
  203. package/src/engine/graphics/texture/atlas/AtlasLookupTexture.d.ts.map +1 -1
  204. package/src/engine/graphics/texture/atlas/AtlasLookupTexture.js +10 -3
  205. package/src/engine/graphics/texture/atlas/TextureAtlas.d.ts.map +1 -1
  206. package/src/engine/graphics/texture/atlas/TextureAtlas.js +4 -1
  207. package/src/engine/graphics/texture/atlas/gpu/WebGLTextureAtlas.d.ts.map +1 -1
  208. package/src/engine/graphics/texture/atlas/gpu/WebGLTextureAtlas.js +11 -0
  209. package/src/engine/graphics/texture/cubemap/load_environment_map.d.ts.map +1 -1
  210. package/src/engine/graphics/texture/cubemap/load_environment_map.js +5 -2
  211. package/src/engine/graphics/texture/sampler/distance/computeSignedDistanceField_Chamfer.d.ts.map +1 -1
  212. package/src/engine/graphics/texture/sampler/distance/computeSignedDistanceField_Chamfer.js +26 -18
  213. package/src/engine/graphics/texture/sampler/filter/sampler2d_blur_gaussian.d.ts +15 -2
  214. package/src/engine/graphics/texture/sampler/filter/sampler2d_blur_gaussian.d.ts.map +1 -1
  215. package/src/engine/graphics/texture/sampler/filter/sampler2d_blur_gaussian.js +29 -3
  216. package/src/engine/graphics/texture/sampler/resize/sampler2d_scale_down_lanczos.d.ts +11 -1
  217. package/src/engine/graphics/texture/sampler/resize/sampler2d_scale_down_lanczos.d.ts.map +1 -1
  218. package/src/engine/graphics/texture/sampler/resize/sampler2d_scale_down_lanczos.js +158 -171
  219. package/src/engine/graphics/texture/sampler/sampler2d_paint.js +1 -1
  220. package/src/engine/graphics/texture/sampler/util/bitSet2Sampler2D.js +2 -2
  221. package/src/engine/input/ecs/util/TopDownCameraControllerHelper.d.ts.map +1 -1
  222. package/src/engine/input/ecs/util/TopDownCameraControllerHelper.js +10 -3
  223. package/src/engine/navigation/ecs/components/PathSerializationUpgrader_2_3.d.ts +14 -0
  224. package/src/engine/navigation/ecs/components/PathSerializationUpgrader_2_3.d.ts.map +1 -0
  225. package/src/engine/navigation/ecs/components/PathSerializationUpgrader_2_3.js +38 -0
  226. package/src/engine/network/orchestrator/ServerAuthoritativeClient.d.ts.map +1 -1
  227. package/src/engine/network/orchestrator/ServerAuthoritativeClient.js +433 -425
  228. package/src/engine/physics/constraint/solve_constraints.d.ts +4 -1
  229. package/src/engine/physics/constraint/solve_constraints.d.ts.map +1 -1
  230. package/src/engine/physics/constraint/solve_constraints.js +38 -13
  231. package/src/engine/physics/contact/ManifoldStore.d.ts +15 -3
  232. package/src/engine/physics/contact/ManifoldStore.d.ts.map +1 -1
  233. package/src/engine/physics/contact/ManifoldStore.js +15 -3
  234. package/src/engine/physics/ecs/Joint.d.ts +7 -4
  235. package/src/engine/physics/ecs/Joint.d.ts.map +1 -1
  236. package/src/engine/physics/ecs/Joint.js +7 -4
  237. package/src/engine/physics/ecs/PhysicsSystem.d.ts +14 -0
  238. package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
  239. package/src/engine/physics/ecs/PhysicsSystem.js +16 -0
  240. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  241. package/src/engine/physics/fluid/ecs/FluidSystem.d.ts +3 -3
  242. package/src/engine/physics/narrowphase/convex_convex_manifold.d.ts +15 -7
  243. package/src/engine/physics/narrowphase/convex_convex_manifold.d.ts.map +1 -1
  244. package/src/engine/physics/narrowphase/convex_convex_manifold.js +33 -10
  245. package/src/engine/physics/narrowphase/refine_ray_concave.d.ts +6 -2
  246. package/src/engine/physics/narrowphase/refine_ray_concave.d.ts.map +1 -1
  247. package/src/engine/physics/narrowphase/refine_ray_concave.js +6 -2
  248. package/src/engine/physics/narrowphase/refine_ray_hit.d.ts +6 -2
  249. package/src/engine/physics/narrowphase/refine_ray_hit.d.ts.map +1 -1
  250. package/src/engine/physics/narrowphase/refine_ray_hit.js +6 -2
  251. package/src/engine/physics/queries/raycast.d.ts.map +1 -1
  252. package/src/engine/physics/queries/raycast.js +11 -4
  253. package/src/engine/save/storage/IndexedDBStorage.d.ts.map +1 -1
  254. package/src/engine/save/storage/IndexedDBStorage.js +21 -3
  255. package/src/engine/simulation/Ticker.d.ts +12 -0
  256. package/src/engine/simulation/Ticker.d.ts.map +1 -1
  257. package/src/engine/simulation/Ticker.js +18 -0
  258. package/src/engine/sound/simulation/AcousticSimulator.d.ts.map +1 -1
  259. package/src/engine/sound/simulation/AcousticSimulator.js +9 -1
  260. package/src/engine/sound/simulation/core/VolumeField.d.ts +6 -2
  261. package/src/engine/sound/simulation/core/VolumeField.d.ts.map +1 -1
  262. package/src/engine/sound/simulation/core/VolumeField.js +6 -2
  263. package/src/engine/sound/simulation/probe/AcousticProbeField.d.ts +6 -2
  264. package/src/engine/sound/simulation/probe/AcousticProbeField.d.ts.map +1 -1
  265. package/src/engine/sound/simulation/probe/AcousticProbeField.js +6 -2
  266. package/src/engine/sound/simulation/probe/acoustic_probe_transfer.d.ts +6 -2
  267. package/src/engine/sound/simulation/probe/acoustic_probe_transfer.d.ts.map +1 -1
  268. package/src/engine/sound/simulation/probe/acoustic_probe_transfer.js +6 -2
  269. package/src/engine/sound/simulation/probe/bakeProbeReflectors.d.ts +3 -1
  270. package/src/engine/sound/simulation/probe/bakeProbeReflectors.d.ts.map +1 -1
  271. package/src/engine/sound/simulation/probe/bakeProbeReflectors.js +3 -1
  272. package/src/engine/ui/GUIEngine.d.ts.map +1 -1
  273. package/src/engine/ui/GUIEngine.js +8 -1
  274. package/src/generation/theme/TerrainTheme.d.ts.map +1 -1
  275. package/src/generation/theme/TerrainTheme.js +2 -1
  276. package/src/generation/theme/ThemeEngine.d.ts.map +1 -1
  277. package/src/generation/theme/ThemeEngine.js +6 -5
  278. package/src/view/ViewGroup.d.ts.map +1 -1
  279. package/src/view/ViewGroup.js +9 -7
  280. package/src/view/graphics/WebGLContextFailureView.d.ts +19 -0
  281. package/src/view/graphics/WebGLContextFailureView.d.ts.map +1 -0
  282. package/src/view/graphics/WebGLContextFailureView.js +76 -0
  283. package/src/view/minimap/Minimap.d.ts +8 -0
  284. package/src/view/minimap/Minimap.d.ts.map +1 -1
  285. package/src/view/minimap/Minimap.js +16 -3
  286. package/src/view/minimap/dom/MinimapMarkerView.d.ts.map +1 -1
  287. package/src/view/minimap/dom/MinimapMarkerView.js +3 -1
@@ -0,0 +1,696 @@
1
+ import { Color as ThreeColor, Mesh, MeshStandardMaterial, SphereGeometry, WebGLRenderer } from "three";
2
+ import Vector3 from "../../../core/geom/Vector3.js";
3
+ import Entity from "../../ecs/Entity.js";
4
+ import Renderable from "../../ecs/renderable/Renderable.js";
5
+ import RenderSystem from "../../ecs/renderable/RenderSystem.js";
6
+ import { Transform } from "../../ecs/transform/Transform.js";
7
+ import { EngineHarness } from "../../EngineHarness.js";
8
+ import { configureThreeRenderer } from "../GraphicsEngine.js";
9
+ import { load_and_set_cubemap_v0 } from "../load_and_set_cubemap_v0.js";
10
+ import { WebGLContextState } from "./WebGLContextState.js";
11
+
12
+ /**
13
+ * WebGL context loss / restore harness.
14
+ *
15
+ * Drives the engine by hand (no rAF, so it works in a hidden tab), forces context loss through
16
+ * `WEBGL_lose_context`, and compares the framebuffer before and after restore. Read the report from
17
+ * the console or from `window.__context_loss_report`.
18
+ *
19
+ * Scenarios:
20
+ * - `window.__context_loss_test.run()` single loss/restore cycle with a full pixel A/B
21
+ * - `window.__context_loss_test.repeat(n)` n cycles, watching `renderer.info.memory` for leaks
22
+ *
23
+ * The scene is deliberately static (no water, no behaviours) so that two consecutive frames are
24
+ * pixel-identical; the noise floor between two pre-loss captures is reported so the post-restore
25
+ * difference is interpretable.
26
+ */
27
+
28
+ const harness = new EngineHarness();
29
+
30
+ const SPHERE_POSITION = new Vector3(0, 2, 0);
31
+
32
+ /**
33
+ * Grid resolution for the per-region luminance breakdown
34
+ * @type {number}
35
+ */
36
+ const REGION_GRID = 4;
37
+
38
+ const scratch_color = new ThreeColor();
39
+
40
+ const VIEWPORT_WIDTH = 800;
41
+ const VIEWPORT_HEIGHT = 600;
42
+
43
+ /**
44
+ *
45
+ * @param {Engine} engine
46
+ * @returns {WebGLRenderer}
47
+ */
48
+ function get_renderer(engine) {
49
+ return engine.graphics.renderer;
50
+ }
51
+
52
+ /**
53
+ * Advance the simulation and draw one frame
54
+ * @param {Engine} engine
55
+ * @param {number} [dt]
56
+ * @returns {number} frame duration in milliseconds
57
+ */
58
+ function frame(engine, dt = 1 / 60) {
59
+ const t0 = performance.now();
60
+
61
+ engine.ticker.onTick.send1(dt);
62
+ engine.render();
63
+
64
+ return performance.now() - t0;
65
+ }
66
+
67
+ /**
68
+ * Reads the default framebuffer. Must run in the same task as the draw, the drawing buffer is not
69
+ * preserved across a compositor frame.
70
+ * @param {Engine} engine
71
+ * @returns {{width:number, height:number, mean:number[], luminance:number, regions:number[], hash:number, nonzero:number}}
72
+ */
73
+ function capture(engine) {
74
+ const renderer = get_renderer(engine);
75
+ const gl = renderer.getContext();
76
+
77
+ renderer.setRenderTarget(null);
78
+
79
+ const width = gl.drawingBufferWidth;
80
+ const height = gl.drawingBufferHeight;
81
+
82
+ const pixels = new Uint8Array(width * height * 4);
83
+
84
+ gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
85
+
86
+ const mean = [0, 0, 0, 0];
87
+ const regions = new Array(REGION_GRID * REGION_GRID).fill(0);
88
+ const region_counts = new Array(REGION_GRID * REGION_GRID).fill(0);
89
+
90
+ let nonzero = 0;
91
+ let hash = 0x811c9dc5;
92
+
93
+ for (let y = 0; y < height; y++) {
94
+ const region_y = Math.min(REGION_GRID - 1, Math.floor((y / height) * REGION_GRID));
95
+
96
+ for (let x = 0; x < width; x++) {
97
+ const address = (y * width + x) * 4;
98
+
99
+ const r = pixels[address];
100
+ const g = pixels[address + 1];
101
+ const b = pixels[address + 2];
102
+ const a = pixels[address + 3];
103
+
104
+ mean[0] += r;
105
+ mean[1] += g;
106
+ mean[2] += b;
107
+ mean[3] += a;
108
+
109
+ if (r !== 0 || g !== 0 || b !== 0) {
110
+ nonzero++;
111
+ }
112
+
113
+ // Rec.709 luma, close enough for an A/B
114
+ const luma = 0.2126 * r + 0.7152 * g + 0.0722 * b;
115
+
116
+ const region_x = Math.min(REGION_GRID - 1, Math.floor((x / width) * REGION_GRID));
117
+ const region = region_y * REGION_GRID + region_x;
118
+
119
+ regions[region] += luma;
120
+ region_counts[region]++;
121
+
122
+ hash = ((hash ^ r) * 0x01000193) >>> 0;
123
+ hash = ((hash ^ g) * 0x01000193) >>> 0;
124
+ hash = ((hash ^ b) * 0x01000193) >>> 0;
125
+ }
126
+ }
127
+
128
+ const pixel_count = width * height;
129
+
130
+ for (let i = 0; i < 4; i++) {
131
+ mean[i] = mean[i] / pixel_count;
132
+ }
133
+
134
+ for (let i = 0; i < regions.length; i++) {
135
+ regions[i] = region_counts[i] === 0 ? 0 : regions[i] / region_counts[i];
136
+ }
137
+
138
+ return {
139
+ width,
140
+ height,
141
+ mean: mean.map(v => Number(v.toFixed(3))),
142
+ luminance: Number((0.2126 * mean[0] + 0.7152 * mean[1] + 0.0722 * mean[2]).toFixed(3)),
143
+ regions: regions.map(v => Number(v.toFixed(2))),
144
+ hash,
145
+ nonzero: Number((nonzero / pixel_count).toFixed(4))
146
+ };
147
+ }
148
+
149
+ /**
150
+ *
151
+ * @param {{luminance:number, regions:number[], hash:number, mean:number[]}} a
152
+ * @param {{luminance:number, regions:number[], hash:number, mean:number[]}} b
153
+ */
154
+ function compare(a, b) {
155
+ let region_max = 0;
156
+ let region_total = 0;
157
+
158
+ for (let i = 0; i < a.regions.length; i++) {
159
+ const d = Math.abs(a.regions[i] - b.regions[i]);
160
+
161
+ region_total += d;
162
+
163
+ if (d > region_max) {
164
+ region_max = d;
165
+ }
166
+ }
167
+
168
+ return {
169
+ identical: a.hash === b.hash,
170
+ luminance_delta: Number((b.luminance - a.luminance).toFixed(3)),
171
+ region_delta_max: Number(region_max.toFixed(3)),
172
+ region_delta_mean: Number((region_total / a.regions.length).toFixed(3))
173
+ };
174
+ }
175
+
176
+ /**
177
+ * Coarse luminance map of the framebuffer, printable in a console. The harness is expected to run in a
178
+ * hidden tab, where screenshots are not available, and an aggregate number does not tell you *what* went
179
+ * missing.
180
+ * @param {Engine} engine
181
+ * @returns {string}
182
+ */
183
+ function ascii_image(engine, columns = 40, rows = 20) {
184
+ const RAMP = ' .:-=+*#%@';
185
+
186
+ const renderer = get_renderer(engine);
187
+ const gl = renderer.getContext();
188
+
189
+ renderer.setRenderTarget(null);
190
+
191
+ const width = gl.drawingBufferWidth;
192
+ const height = gl.drawingBufferHeight;
193
+
194
+ const pixels = new Uint8Array(width * height * 4);
195
+
196
+ gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
197
+
198
+ const lines = [];
199
+
200
+ // readPixels returns rows bottom-up
201
+ for (let row = rows - 1; row >= 0; row--) {
202
+ let line = '';
203
+
204
+ for (let column = 0; column < columns; column++) {
205
+ const x0 = Math.floor(column * width / columns);
206
+ const x1 = Math.floor((column + 1) * width / columns);
207
+ const y0 = Math.floor(row * height / rows);
208
+ const y1 = Math.floor((row + 1) * height / rows);
209
+
210
+ let sum = 0;
211
+ let count = 0;
212
+
213
+ for (let y = y0; y < y1; y += 3) {
214
+ for (let x = x0; x < x1; x += 3) {
215
+ const address = (y * width + x) * 4;
216
+
217
+ sum += 0.2126 * pixels[address] + 0.7152 * pixels[address + 1] + 0.0722 * pixels[address + 2];
218
+ count++;
219
+ }
220
+ }
221
+
222
+ const luma = sum / count;
223
+
224
+ line += RAMP[Math.min(RAMP.length - 1, Math.floor((luma / 255) * RAMP.length))];
225
+ }
226
+
227
+ lines.push(line);
228
+ }
229
+
230
+ return lines.join('\n');
231
+ }
232
+
233
+ /**
234
+ *
235
+ * @param {Engine} engine
236
+ */
237
+ function snapshot_renderer_state(engine) {
238
+ const renderer = get_renderer(engine);
239
+ const gl = renderer.getContext();
240
+ const info = renderer.info;
241
+
242
+ const clear_color = renderer.getClearColor(scratch_color);
243
+
244
+ return {
245
+ context_lost: gl.isContextLost(),
246
+ monitor_state: engine.graphics.context.state,
247
+ monitor_generation: engine.graphics.context.generation,
248
+ monitor_loss_count: engine.graphics.context.loss_count,
249
+ programs: info.programs === null ? -1 : info.programs.length,
250
+ textures: info.memory.textures,
251
+ geometries: info.memory.geometries,
252
+ clear_color: [
253
+ Number(clear_color.r.toFixed(4)),
254
+ Number(clear_color.g.toFixed(4)),
255
+ Number(clear_color.b.toFixed(4))
256
+ ],
257
+ clear_alpha: renderer.getClearAlpha(),
258
+ environment_set: engine.graphics.scene.environment !== null
259
+ && engine.graphics.scene.environment !== undefined,
260
+ gl_error: gl.getError()
261
+ };
262
+ }
263
+
264
+ /**
265
+ * Waits for a single event on the canvas
266
+ * @param {HTMLCanvasElement} canvas
267
+ * @param {string} name
268
+ * @param {number} timeout milliseconds
269
+ * @returns {Promise<number>} milliseconds waited, or -1 on timeout
270
+ */
271
+ function wait_for_canvas_event(canvas, name, timeout) {
272
+ return new Promise(resolve => {
273
+ const t0 = performance.now();
274
+
275
+ let timeout_handle = -1;
276
+
277
+ const handler = () => {
278
+ clearTimeout(timeout_handle);
279
+ canvas.removeEventListener(name, handler);
280
+ resolve(performance.now() - t0);
281
+ };
282
+
283
+ canvas.addEventListener(name, handler, false);
284
+
285
+ timeout_handle = setTimeout(() => {
286
+ canvas.removeEventListener(name, handler);
287
+ resolve(-1);
288
+ }, timeout);
289
+ });
290
+ }
291
+
292
+ /**
293
+ * One loss/restore cycle
294
+ * @param {Engine} engine
295
+ * @param {number} [warmup_frames]
296
+ * @param {number} [lost_frames] frames driven while the context is lost
297
+ * @param {number} [settle_frames] frames driven after restore before the second capture
298
+ */
299
+ async function run_cycle(engine, { warmup_frames = 30, lost_frames = 5, settle_frames = 20 } = {}) {
300
+ const renderer = get_renderer(engine);
301
+ const canvas = renderer.domElement;
302
+
303
+ const report = {};
304
+
305
+ // ---- baseline -------------------------------------------------------------------------------
306
+ for (let i = 0; i < warmup_frames; i++) {
307
+ frame(engine);
308
+ }
309
+
310
+ frame(engine);
311
+ const baseline = capture(engine);
312
+
313
+ frame(engine);
314
+ const baseline_2 = capture(engine);
315
+
316
+ report.baseline = baseline;
317
+ report.noise_floor = compare(baseline, baseline_2);
318
+ report.before = snapshot_renderer_state(engine);
319
+
320
+ // ---- lose ---------------------------------------------------------------------------------
321
+ const lost_promise = wait_for_canvas_event(canvas, 'webglcontextlost', 5000);
322
+
323
+ renderer.forceContextLoss();
324
+
325
+ report.lost_event_delay_ms = Number((await lost_promise).toFixed(2));
326
+
327
+ const lost_frame_errors = [];
328
+
329
+ for (let i = 0; i < lost_frames; i++) {
330
+ try {
331
+ frame(engine);
332
+ } catch (e) {
333
+ lost_frame_errors.push(String(e && e.message ? e.message : e));
334
+ }
335
+ }
336
+
337
+ report.frames_while_lost_threw = lost_frame_errors;
338
+ report.while_lost = snapshot_renderer_state(engine);
339
+
340
+ // ---- restore ------------------------------------------------------------------------------
341
+ const restored_promise = wait_for_canvas_event(canvas, 'webglcontextrestored', 10000);
342
+
343
+ renderer.forceContextRestore();
344
+
345
+ const restore_delay = await restored_promise;
346
+
347
+ report.restored_event_delay_ms = Number(restore_delay.toFixed(2));
348
+ report.restored = restore_delay >= 0;
349
+
350
+ if (!report.restored) {
351
+ report.verdict = 'context was NOT restored within 10s';
352
+ return report;
353
+ }
354
+
355
+ // first frame after restore carries the re-upload + recompile storm
356
+ report.first_frame_ms = Number(frame(engine).toFixed(2));
357
+ const first = capture(engine);
358
+
359
+ const settle_durations = [];
360
+
361
+ for (let i = 0; i < settle_frames; i++) {
362
+ settle_durations.push(frame(engine));
363
+ }
364
+
365
+ frame(engine);
366
+ const settled = capture(engine);
367
+
368
+ report.settle_frames_ms = {
369
+ max: Number(Math.max(...settle_durations).toFixed(2)),
370
+ mean: Number((settle_durations.reduce((a, b) => a + b, 0) / settle_durations.length).toFixed(2))
371
+ };
372
+
373
+ report.after = snapshot_renderer_state(engine);
374
+
375
+ report.first_frame_vs_baseline = compare(baseline, first);
376
+ report.settled_vs_baseline = compare(baseline, settled);
377
+
378
+ report.settled = settled;
379
+
380
+ return report;
381
+ }
382
+
383
+ /**
384
+ * Loss/restore lifecycle without actually killing the context: the canvas events are dispatched by hand.
385
+ *
386
+ * three.js reacts to the restore event by rebuilding all of its GPU-object bookkeeping, so everything is
387
+ * re-uploaded and every shader recompiled exactly as it would be after a real restore - the difference is
388
+ * that the underlying context stays healthy, which is what makes this runnable in a hidden tab (browsers
389
+ * only restore a genuinely lost context while the page is visible).
390
+ *
391
+ * What this covers: the engine's gate, the fix-up sequence, the environment re-bake, and three's own
392
+ * restore path. What it cannot cover: whether the browser is willing to restore, and how stale GL handles
393
+ * from the dead context behave.
394
+ *
395
+ * @param {Engine} engine
396
+ */
397
+ function run_synthetic_cycle(engine, { warmup_frames = 40, lost_frames = 5, settle_frames = 10 } = {}) {
398
+ const renderer = get_renderer(engine);
399
+ const canvas = renderer.domElement;
400
+
401
+ const report = {};
402
+
403
+ for (let i = 0; i < warmup_frames; i++) {
404
+ frame(engine);
405
+ }
406
+
407
+ frame(engine);
408
+ const baseline = capture(engine);
409
+
410
+ frame(engine);
411
+ report.noise_floor = compare(baseline, capture(engine));
412
+ report.baseline = baseline;
413
+ report.before = snapshot_renderer_state(engine);
414
+ report.baseline_image = ascii_image(engine);
415
+
416
+ // ---- loss -----------------------------------------------------------------------------------
417
+ const frame_index_before = engine.graphics.frameIndex;
418
+
419
+ canvas.dispatchEvent(new Event('webglcontextlost', { cancelable: true }));
420
+
421
+ report.state_while_lost = engine.graphics.context.state;
422
+
423
+ const errors = [];
424
+
425
+ for (let i = 0; i < lost_frames; i++) {
426
+ try {
427
+ frame(engine);
428
+ } catch (e) {
429
+ errors.push(String(e && e.message ? e.message : e));
430
+ }
431
+ }
432
+
433
+ report.frames_while_lost_threw = errors;
434
+ // the gate returns before the frame counter is touched, so this proves no drawing happened
435
+ report.frames_drawn_while_lost = engine.graphics.frameIndex - frame_index_before;
436
+
437
+ // ---- restore --------------------------------------------------------------------------------
438
+ canvas.dispatchEvent(new Event('webglcontextrestored'));
439
+
440
+ report.first_frame_ms = Number(frame(engine).toFixed(2));
441
+ const first = capture(engine);
442
+
443
+ for (let i = 0; i < settle_frames; i++) {
444
+ frame(engine);
445
+ }
446
+
447
+ frame(engine);
448
+ const settled = capture(engine);
449
+
450
+ report.after = snapshot_renderer_state(engine);
451
+ report.first_frame_vs_baseline = compare(baseline, first);
452
+ report.settled_vs_baseline = compare(baseline, settled);
453
+ report.settled = settled;
454
+ report.settled_image = ascii_image(engine);
455
+
456
+ return report;
457
+ }
458
+
459
+ /**
460
+ * Renders the same scene through a brand new renderer on a brand new context.
461
+ *
462
+ * Note that the environment map is expected to differ here: swapping the renderer is not a context
463
+ * restore, so the engine's recovery hook never runs and the prefiltered radiance is never re-baked. The
464
+ * value of this scenario is everything else - geometry, textures, shaders, render targets and the
465
+ * composit chain all have to come back from CPU-side data, and any of them failing to shows up as a
466
+ * difference beyond the known environment delta.
467
+ *
468
+ * This is the closest analogue of a restore that can be produced in a hidden tab while still exercising
469
+ * real GPU work: the object graph is untouched, but the GL-side caches are empty, so everything that
470
+ * cannot be re-derived from CPU-side data shows up as a difference against the baseline.
471
+ *
472
+ * @param {Engine} engine
473
+ */
474
+ function run_fresh_context(engine, { warmup_frames = 40, settle_frames = 10 } = {}) {
475
+ const graphics = engine.graphics;
476
+
477
+ const report = {};
478
+
479
+ for (let i = 0; i < warmup_frames; i++) {
480
+ frame(engine);
481
+ }
482
+
483
+ frame(engine);
484
+ const baseline = capture(engine);
485
+
486
+ frame(engine);
487
+ report.noise_floor = compare(baseline, capture(engine));
488
+ report.baseline = baseline;
489
+
490
+ const previous = graphics.renderer;
491
+
492
+ const canvas = document.createElement('canvas');
493
+ const context = canvas.getContext('webgl2', { antialias: false });
494
+
495
+ const fresh = new WebGLRenderer({
496
+ antialias: true,
497
+ logarithmicDepthBuffer: false,
498
+ canvas,
499
+ context,
500
+ powerPreference: 'high-performance'
501
+ });
502
+
503
+ configureThreeRenderer(fresh);
504
+
505
+ graphics.renderer = fresh;
506
+
507
+ graphics.updateSize();
508
+
509
+ report.first_frame_ms = Number(frame(engine).toFixed(2));
510
+ const first = capture(engine);
511
+
512
+ for (let i = 0; i < settle_frames; i++) {
513
+ frame(engine);
514
+ }
515
+
516
+ frame(engine);
517
+ const settled = capture(engine);
518
+
519
+ report.fresh_programs = fresh.info.programs.length;
520
+ report.fresh_textures = fresh.info.memory.textures;
521
+ report.fresh_geometries = fresh.info.memory.geometries;
522
+ report.fresh_draw_calls = fresh.info.render.calls;
523
+ report.fresh_triangles = fresh.info.render.triangles;
524
+ report.settled_image = ascii_image(engine);
525
+
526
+ graphics.renderer = previous;
527
+
528
+ graphics.updateSize();
529
+
530
+ report.first_frame_vs_baseline = compare(baseline, first);
531
+ report.settled_vs_baseline = compare(baseline, settled);
532
+
533
+ // and confirm the shared object graph was not disturbed by the swap
534
+ frame(engine);
535
+ report.restored_original_vs_baseline = compare(baseline, capture(engine));
536
+
537
+ fresh.forceContextLoss();
538
+ fresh.dispose();
539
+
540
+ return report;
541
+ }
542
+
543
+ /**
544
+ *
545
+ * @param {Engine} engine
546
+ */
547
+ function install_api(engine) {
548
+ const api = {
549
+ engine,
550
+
551
+ frame: (n = 1) => {
552
+ const durations = [];
553
+ for (let i = 0; i < n; i++) {
554
+ durations.push(frame(engine));
555
+ }
556
+ return durations;
557
+ },
558
+
559
+ capture: () => {
560
+ frame(engine);
561
+ return capture(engine);
562
+ },
563
+
564
+ state: () => snapshot_renderer_state(engine),
565
+
566
+ image: () => ascii_image(engine),
567
+
568
+ /**
569
+ * Loss/restore lifecycle driven by synthetic canvas events. Works in a hidden tab.
570
+ */
571
+ synthetic(options) {
572
+ const report = run_synthetic_cycle(engine, options);
573
+
574
+ window.__context_loss_report = report;
575
+
576
+ console.log('[context-loss] synthetic report', report);
577
+ console.log('[context-loss] baseline\n' + report.baseline_image);
578
+ console.log('[context-loss] after restore\n' + report.settled_image);
579
+
580
+ return report;
581
+ },
582
+
583
+ /**
584
+ * Same scene, brand new context. Works in a hidden tab.
585
+ */
586
+ fresh(options) {
587
+ const report = run_fresh_context(engine, options);
588
+
589
+ window.__context_loss_report = report;
590
+
591
+ console.log('[context-loss] fresh-context report', report);
592
+
593
+ return report;
594
+ },
595
+
596
+ async run(options) {
597
+ const report = await run_cycle(engine, options);
598
+
599
+ window.__context_loss_report = report;
600
+
601
+ console.log('[context-loss] report', report);
602
+
603
+ return report;
604
+ },
605
+
606
+ async repeat(count = 3, options) {
607
+ const reports = [];
608
+
609
+ for (let i = 0; i < count; i++) {
610
+ console.log(`[context-loss] cycle ${i + 1}/${count}`);
611
+ reports.push(await run_cycle(engine, options));
612
+ }
613
+
614
+ const summary = reports.map((r, i) => ({
615
+ cycle: i,
616
+ restored: r.restored,
617
+ first_frame_ms: r.first_frame_ms,
618
+ settled_vs_baseline: r.settled_vs_baseline,
619
+ textures_before: r.before.textures,
620
+ textures_after: r.after === undefined ? -1 : r.after.textures,
621
+ geometries_after: r.after === undefined ? -1 : r.after.geometries,
622
+ programs_after: r.after === undefined ? -1 : r.after.programs
623
+ }));
624
+
625
+ window.__context_loss_report = { reports, summary };
626
+
627
+ console.log('[context-loss] repeat summary', summary);
628
+
629
+ return summary;
630
+ }
631
+ };
632
+
633
+ window.__context_loss_test = api;
634
+ }
635
+
636
+ /**
637
+ *
638
+ * @param {Engine} engine
639
+ * @returns {Promise<void>}
640
+ */
641
+ async function main(engine) {
642
+ // fixed viewport: the pixel A/B needs a stable resolution, and the harness is expected to run in a
643
+ // hidden tab where the window-driven sizing path produces a 0-sized viewport
644
+ engine.settings.graphics_control_viewport_size.set(false);
645
+ engine.viewStack.size.set(VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
646
+
647
+ await EngineHarness.buildBasics({
648
+ engine,
649
+ focus: SPHERE_POSITION,
650
+ distance: 6,
651
+ pitch: 0.35,
652
+ // static scene: animated water would make consecutive frames differ
653
+ enableWater: false,
654
+ enableTerrain: true,
655
+ terrainSize: { x: 32, y: 32 },
656
+ enableLights: true,
657
+ enableShadows: true,
658
+ cameraController: false
659
+ });
660
+
661
+ const ecd = engine.entityManager.dataset;
662
+
663
+ // a large mirror-metal sphere; almost all of its shading comes from scene.environment, which makes
664
+ // the PMREM environment map's survival directly visible in the pixel A/B
665
+ const material = new MeshStandardMaterial({
666
+ color: 0xffffff,
667
+ metalness: 1,
668
+ roughness: 0.08
669
+ });
670
+
671
+ const mesh = new Mesh(new SphereGeometry(2, 48, 32), material);
672
+
673
+ mesh.castShadow = true;
674
+
675
+ new Entity()
676
+ .add(new Renderable(mesh))
677
+ .add(Transform.fromJSON({
678
+ position: SPHERE_POSITION,
679
+ scale: { x: 1, y: 1, z: 1 }
680
+ }))
681
+ .build(ecd);
682
+
683
+ await load_and_set_cubemap_v0(engine.graphics, 'data/textures/cubemaps/hip_miramar/32/', '.png');
684
+
685
+ install_api(engine);
686
+
687
+ console.log('[context-loss] ready. Run window.__context_loss_test.run()');
688
+ }
689
+
690
+ harness.initialize({
691
+ configuration(config, engine) {
692
+ config.addManySystems(
693
+ new RenderSystem(engine.graphics)
694
+ );
695
+ }
696
+ }).then(main);
@@ -1 +1 @@
1
- {"version":3,"file":"CameraSerializationAdapter.d.ts","sourceRoot":"","sources":["../../../../../../../src/engine/graphics/ecs/camera/serialization/CameraSerializationAdapter.js"],"names":[],"mappings":"AAGA;;IAEI,qBAAe;IAGf;;;;OAIG;IACH,uCAFW,MAAM,QAShB;IAED;;;;OAIG;IACH,yCAFW,MAAM,QAKhB;CACJ;gDA/B+C,mEAAmE;uBAC5F,cAAc"}
1
+ {"version":3,"file":"CameraSerializationAdapter.d.ts","sourceRoot":"","sources":["../../../../../../../src/engine/graphics/ecs/camera/serialization/CameraSerializationAdapter.js"],"names":[],"mappings":"AAeA;;IAEI,qBAAe;IAGf;;;;OAIG;IACH,uCAFW,MAAM,QAmBhB;IAED;;;;OAIG;IACH,yCAFW,MAAM,QAmBhB;CACJ;gDAnE+C,mEAAmE;uBAC5F,cAAc"}