@woosh/meep-engine 3.60.3 → 3.60.5

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 (514) hide show
  1. package/CHANGELOG.md +2602 -0
  2. package/CONTRIBUTING.md +7 -0
  3. package/MIGRATION_2_TO_3.md +136 -0
  4. package/SECURITY.md +4 -0
  5. package/editor/EditorCameraNavigation.d.ts +2 -1
  6. package/editor/EditorCameraNavigation.d.ts.map +1 -1
  7. package/editor/EditorCameraNavigation.js +51 -57
  8. package/editor/ecs/component/editors/ecs/Trail3DEditor.d.ts +3 -0
  9. package/editor/ecs/component/editors/ecs/Trail3DEditor.d.ts.map +1 -1
  10. package/editor/ecs/component/editors/ecs/Trail3DEditor.js +6 -0
  11. package/package.json +6 -2
  12. package/src/engine/EngineHarness.d.ts +3 -9
  13. package/src/engine/EngineHarness.d.ts.map +1 -1
  14. package/src/engine/EngineHarness.js +6 -8
  15. package/src/engine/graphics/camera/makeOrbitalCameraController.d.ts +9 -6
  16. package/src/engine/graphics/camera/makeOrbitalCameraController.d.ts.map +1 -1
  17. package/src/engine/graphics/camera/makeOrbitalCameraController.js +44 -71
  18. package/src/engine/graphics/camera/orbital/MomentumAxis.d.ts +64 -0
  19. package/src/engine/graphics/camera/orbital/MomentumAxis.d.ts.map +1 -0
  20. package/src/engine/graphics/camera/orbital/MomentumAxis.js +187 -0
  21. package/src/engine/graphics/camera/orbital/OrbitalCameraRig.d.ts +86 -0
  22. package/src/engine/graphics/camera/orbital/OrbitalCameraRig.d.ts.map +1 -0
  23. package/src/engine/graphics/camera/orbital/OrbitalCameraRig.js +319 -0
  24. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraController.d.ts +34 -10
  25. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraController.d.ts.map +1 -1
  26. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraController.js +116 -30
  27. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.d.ts +1 -7
  28. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.d.ts.map +1 -1
  29. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.js +1 -37
  30. package/src/engine/graphics/ecs/mesh-v2/ShadedGeometryFlags.js +1 -2
  31. package/src/engine/graphics/ecs/trail3d/TRAIL3D_FADE_LINEAR.d.ts +14 -0
  32. package/src/engine/graphics/ecs/trail3d/TRAIL3D_FADE_LINEAR.d.ts.map +1 -0
  33. package/src/engine/graphics/ecs/trail3d/TRAIL3D_FADE_LINEAR.js +22 -0
  34. package/src/engine/graphics/ecs/trail3d/Trail3D.d.ts +19 -3
  35. package/src/engine/graphics/ecs/trail3d/Trail3D.d.ts.map +1 -1
  36. package/src/engine/graphics/ecs/trail3d/Trail3D.js +31 -4
  37. package/src/engine/graphics/ecs/trail3d/advance_trail.js +1 -1
  38. package/src/engine/graphics/ecs/water/Water.d.ts +8 -0
  39. package/src/engine/graphics/ecs/water/Water.d.ts.map +1 -1
  40. package/src/engine/graphics/ecs/water/Water.js +8 -0
  41. package/src/engine/graphics/trail/tube/simulator/TubeXFixedPhysicsSimulator.d.ts +5 -5
  42. package/src/engine/graphics/trail/tube/simulator/TubeXFixedPhysicsSimulator.d.ts.map +1 -1
  43. package/src/engine/graphics/trail/tube/simulator/TubeXFixedPhysicsSimulator.js +6 -6
  44. package/src/engine/graphics3/WaterSystem.d.ts.map +1 -1
  45. package/src/engine/graphics3/WaterSystem.js +731 -734
  46. package/src/engine/graphics3/decal/DecalTileShader.d.ts +61 -0
  47. package/src/engine/graphics3/decal/DecalTileShader.d.ts.map +1 -0
  48. package/src/engine/graphics3/decal/DecalTileShader.js +138 -0
  49. package/src/engine/graphics3/decal/GPUDecalRenderer.d.ts +10 -4
  50. package/src/engine/graphics3/decal/GPUDecalRenderer.d.ts.map +1 -1
  51. package/src/engine/graphics3/decal/GPUDecalRenderer.js +149 -44
  52. package/src/engine/graphics3/decal/chunk_decal_tile_vertex.d.ts +25 -0
  53. package/src/engine/graphics3/decal/chunk_decal_tile_vertex.d.ts.map +1 -0
  54. package/src/engine/graphics3/decal/chunk_decal_tile_vertex.js +55 -0
  55. package/src/engine/graphics3/decal/graph_gather_decal_tiles.d.ts +22 -0
  56. package/src/engine/graphics3/decal/graph_gather_decal_tiles.d.ts.map +1 -0
  57. package/src/engine/graphics3/decal/graph_gather_decal_tiles.js +70 -0
  58. package/src/engine/graphics3/decal/shader_decal_composite.d.ts +7 -5
  59. package/src/engine/graphics3/decal/shader_decal_composite.d.ts.map +1 -1
  60. package/src/engine/graphics3/decal/shader_decal_composite.js +48 -44
  61. package/src/engine/graphics3/decal/shader_decal_tile_copy.d.ts +12 -0
  62. package/src/engine/graphics3/decal/shader_decal_tile_copy.d.ts.map +1 -0
  63. package/src/engine/graphics3/decal/shader_decal_tile_copy.js +78 -0
  64. package/src/engine/graphics3/decal/shader_gather_decal_tiles.d.ts +11 -0
  65. package/src/engine/graphics3/decal/shader_gather_decal_tiles.d.ts.map +1 -0
  66. package/src/engine/graphics3/decal/shader_gather_decal_tiles.js +80 -0
  67. package/src/engine/graphics3/trail/trail_tube_write_geometry.d.ts +10 -0
  68. package/src/engine/graphics3/trail/trail_tube_write_geometry.d.ts.map +1 -1
  69. package/src/engine/graphics3/trail/trail_tube_write_geometry.js +13 -1
  70. package/src/engine/input/devices/mouse/MouseEventButtons.d.ts +13 -0
  71. package/src/engine/input/devices/mouse/MouseEventButtons.d.ts.map +1 -0
  72. package/src/engine/input/devices/mouse/MouseEventButtons.js +23 -0
  73. package/src/engine/input/ecs/controllers/KeyboardCameraController.d.ts +4 -0
  74. package/src/engine/input/ecs/controllers/KeyboardCameraController.d.ts.map +1 -1
  75. package/src/engine/input/ecs/controllers/KeyboardCameraController.js +9 -45
  76. package/src/engine/physics/cloth/ecs/cloth_geodesic.d.ts +2 -2
  77. package/src/engine/physics/cloth/ecs/cloth_geodesic.js +2 -2
  78. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  79. package/src/shade/playground/probe_clipmap/README.md +1 -0
  80. package/src/shade/playground/probe_clipmap/index.html +5 -0
  81. package/src/shade/playground/probe_clipmap/main.d.ts.map +1 -1
  82. package/src/shade/playground/probe_clipmap/main.js +16 -2
  83. package/src/shade/playground/vgeo_scene/README.md +1 -1
  84. package/src/shade/playground/water_refraction/README.md +5 -6
  85. package/src/shade/playground/water_refraction/index.html +1 -1
  86. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  87. package/src/shade/renderer/Renderer.js +7 -5
  88. package/src/shade/renderer/atmosphere/MULTISCATTER_LUT_CONFIG.d.ts +4 -6
  89. package/src/shade/renderer/atmosphere/MULTISCATTER_LUT_CONFIG.d.ts.map +1 -1
  90. package/src/shade/renderer/atmosphere/MULTISCATTER_LUT_CONFIG.js +34 -36
  91. package/src/shade/renderer/atmosphere/chunk_get_multiscatter_values.d.ts +1 -1
  92. package/src/shade/renderer/atmosphere/chunk_get_multiscatter_values.d.ts.map +1 -1
  93. package/src/shade/renderer/atmosphere/chunk_get_multiscatter_values.js +162 -163
  94. package/src/shade/renderer/atmosphere/compute_mie_absorption.d.ts +1 -1
  95. package/src/shade/renderer/atmosphere/compute_mie_absorption.js +1 -1
  96. package/src/shade/renderer/atmosphere/hillaire/ATMOSPHERE_EARTH.js +1 -1
  97. package/src/shade/renderer/atmosphere/hillaire/ATMOSPHERE_PARAMETERS_STRUCT.js +1 -1
  98. package/src/shade/renderer/atmosphere/shader_multiscatter_lut.js +164 -164
  99. package/src/shade/renderer/atmosphere/shader_sky_irradiance_lut.js +1 -1
  100. package/src/shade/renderer/camera/orbital/OrbitalCameraController.d.ts +40 -80
  101. package/src/shade/renderer/camera/orbital/OrbitalCameraController.d.ts.map +1 -1
  102. package/src/shade/renderer/camera/orbital/OrbitalCameraController.js +197 -147
  103. package/src/shade/renderer/fluid/GPUFluidCascade.d.ts +3 -3
  104. package/src/shade/renderer/fluid/GPUFluidCascadeStack.d.ts +1 -1
  105. package/src/shade/renderer/fluid/forcing/GPUFluidForcing.d.ts +6 -6
  106. package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.d.ts +1 -1
  107. package/src/shade/renderer/fluid/query/GPUFluidQueries.d.ts +1 -1
  108. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts +4 -4
  109. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.js +4 -4
  110. package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.d.ts +2 -1
  111. package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.d.ts.map +1 -1
  112. package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.js +18 -1
  113. package/src/shade/renderer/geometry/sdf/cards/mesh_cards_raster_pass_descriptor.js +2 -2
  114. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_histogram.d.ts +1 -1
  115. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_histogram.js +1 -1
  116. package/src/shade/renderer/geometry/sdf/chunk_blas_query_band_sdf.d.ts +4 -5
  117. package/src/shade/renderer/geometry/sdf/chunk_blas_query_band_sdf.d.ts.map +1 -1
  118. package/src/shade/renderer/geometry/sdf/chunk_blas_query_band_sdf.js +6 -7
  119. package/src/shade/renderer/geometry/virtual/proxy/vgeo_to_proxy_mesh.d.ts +31 -0
  120. package/src/shade/renderer/geometry/virtual/proxy/vgeo_to_proxy_mesh.d.ts.map +1 -0
  121. package/src/shade/renderer/geometry/virtual/proxy/vgeo_to_proxy_mesh.js +343 -0
  122. package/src/shade/renderer/geometry/virtual/runtime/vgeo_meshlet_metadata_write.d.ts +17 -0
  123. package/src/shade/renderer/geometry/virtual/runtime/vgeo_meshlet_metadata_write.d.ts.map +1 -0
  124. package/src/shade/renderer/geometry/virtual/runtime/vgeo_meshlet_metadata_write.js +29 -0
  125. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_meshlet_batch.d.ts.map +1 -1
  126. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_meshlet_batch.js +7 -13
  127. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts.map +1 -1
  128. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.js +2 -8
  129. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.d.ts +5 -5
  130. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.d.ts.map +1 -1
  131. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.js +10 -10
  132. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSettings.d.ts +12 -0
  133. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSettings.d.ts.map +1 -1
  134. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSettings.js +22 -0
  135. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts +4 -4
  136. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts.map +1 -1
  137. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.js +50 -13
  138. package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.d.ts +6 -0
  139. package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.d.ts.map +1 -1
  140. package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.js +7 -0
  141. package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP_RESAMPLING.d.ts +13 -0
  142. package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP_RESAMPLING.d.ts.map +1 -0
  143. package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP_RESAMPLING.js +13 -0
  144. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.d.ts +17 -0
  145. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.d.ts.map +1 -1
  146. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.js +20 -0
  147. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_surface.d.ts +5 -15
  148. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_surface.d.ts.map +1 -1
  149. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_surface.js +6 -34
  150. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_resampled.d.ts +18 -0
  151. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_resampled.d.ts.map +1 -0
  152. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_resampled.js +42 -0
  153. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_sample_radiance.d.ts.map +1 -1
  154. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_sample_radiance.js +5 -4
  155. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_accumulate.d.ts +4 -0
  156. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_accumulate.d.ts.map +1 -1
  157. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_accumulate.js +13 -2
  158. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_resample.d.ts +52 -0
  159. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_resample.d.ts.map +1 -0
  160. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_resample.js +250 -0
  161. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.d.ts.map +1 -1
  162. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.js +1 -7
  163. package/src/shade/renderer/hiz/HZBFootprint.d.ts +14 -0
  164. package/src/shade/renderer/hiz/HZBFootprint.d.ts.map +1 -0
  165. package/src/shade/renderer/hiz/HZBFootprint.js +16 -0
  166. package/src/shade/renderer/hiz/HZB_FOOTPRINT_X.d.ts +10 -0
  167. package/src/shade/renderer/hiz/HZB_FOOTPRINT_X.d.ts.map +1 -0
  168. package/src/shade/renderer/hiz/HZB_FOOTPRINT_X.js +11 -0
  169. package/src/shade/renderer/hiz/HZB_FOOTPRINT_Y.d.ts +10 -0
  170. package/src/shade/renderer/hiz/HZB_FOOTPRINT_Y.d.ts.map +1 -0
  171. package/src/shade/renderer/hiz/HZB_FOOTPRINT_Y.js +11 -0
  172. package/src/shade/renderer/hiz/HierarchicalZBuffer.d.ts +0 -7
  173. package/src/shade/renderer/hiz/HierarchicalZBuffer.d.ts.map +1 -1
  174. package/src/shade/renderer/hiz/HierarchicalZBuffer.js +405 -350
  175. package/src/shade/renderer/hiz/chunk_hzb_footprint_x.d.ts +12 -0
  176. package/src/shade/renderer/hiz/chunk_hzb_footprint_x.d.ts.map +1 -0
  177. package/src/shade/renderer/hiz/chunk_hzb_footprint_x.js +27 -0
  178. package/src/shade/renderer/hiz/chunk_hzb_footprint_y.d.ts +12 -0
  179. package/src/shade/renderer/hiz/chunk_hzb_footprint_y.d.ts.map +1 -0
  180. package/src/shade/renderer/hiz/chunk_hzb_footprint_y.js +27 -0
  181. package/src/shade/renderer/hiz/hzb_footprint_texels.d.ts +14 -0
  182. package/src/shade/renderer/hiz/hzb_footprint_texels.d.ts.map +1 -0
  183. package/src/shade/renderer/hiz/hzb_footprint_texels.js +34 -0
  184. package/src/shade/renderer/hiz/shader_hzb_reduce_any.d.ts +0 -5
  185. package/src/shade/renderer/hiz/shader_hzb_reduce_any.d.ts.map +1 -1
  186. package/src/shade/renderer/hiz/shader_hzb_reduce_any.js +37 -57
  187. package/src/shade/renderer/hiz/shader_hzb_reduce_mip0.d.ts +11 -0
  188. package/src/shade/renderer/hiz/shader_hzb_reduce_mip0.d.ts.map +1 -0
  189. package/src/shade/renderer/hiz/{shader_hzb_reduce_mip0_clip.js → shader_hzb_reduce_mip0.js} +120 -111
  190. package/src/shade/renderer/light/environment/environment_level_1_blur_plan.d.ts +39 -0
  191. package/src/shade/renderer/light/environment/environment_level_1_blur_plan.d.ts.map +1 -0
  192. package/src/shade/renderer/light/environment/environment_level_1_blur_plan.js +119 -0
  193. package/src/shade/renderer/light/environment/execute_filter_environment_map.d.ts +15 -7
  194. package/src/shade/renderer/light/environment/execute_filter_environment_map.d.ts.map +1 -1
  195. package/src/shade/renderer/light/environment/execute_filter_environment_map.js +66 -83
  196. package/src/shade/renderer/light/environment/graph_filter_environment_map.d.ts.map +1 -1
  197. package/src/shade/renderer/light/environment/graph_filter_environment_map.js +15 -6
  198. package/src/shade/renderer/light/environment/shader_blur_environment_map.d.ts +3 -0
  199. package/src/shade/renderer/light/environment/shader_blur_environment_map.d.ts.map +1 -0
  200. package/src/shade/renderer/light/environment/shader_blur_environment_map.js +111 -0
  201. package/src/shade/renderer/light/environment/shader_convolve_reflection_map_from_blurred.d.ts +3 -0
  202. package/src/shade/renderer/light/environment/shader_convolve_reflection_map_from_blurred.d.ts.map +1 -0
  203. package/src/shade/renderer/light/environment/shader_convolve_reflection_map_from_blurred.js +128 -0
  204. package/src/shade/renderer/light/environment/shader_downsample_environment_map.d.ts.map +1 -1
  205. package/src/shade/renderer/light/environment/shader_downsample_environment_map.js +0 -1
  206. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  207. package/src/shade/renderer/material/GPUMaterialManager.d.ts +7 -0
  208. package/src/shade/renderer/material/GPUMaterialManager.d.ts.map +1 -1
  209. package/src/shade/renderer/material/GPUMaterialManager.js +11 -0
  210. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.d.ts +12 -12
  211. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.d.ts.map +1 -1
  212. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.js +17 -118
  213. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -3
  214. package/src/shade/renderer/postprocess/nss/NSS.d.ts.map +1 -1
  215. package/src/shade/renderer/postprocess/nss/NSS.js +1 -3
  216. package/src/shade/renderer/postprocess/nss/NSS_NETWORK_SCHEMA.d.ts +5 -6
  217. package/src/shade/renderer/postprocess/nss/NSS_NETWORK_SCHEMA.d.ts.map +1 -1
  218. package/src/shade/renderer/postprocess/nss/NSS_NETWORK_SCHEMA.js +9 -10
  219. package/src/shade/renderer/postprocess/nss/shader_nss_extract_feedback.d.ts.map +1 -1
  220. package/src/shade/renderer/postprocess/nss/shader_nss_extract_feedback.js +48 -49
  221. package/src/shade/renderer/postprocess/nss/shader_nss_postprocess.d.ts.map +1 -1
  222. package/src/shade/renderer/postprocess/nss/shader_nss_postprocess.js +12 -16
  223. package/src/shade/renderer/postprocess/nss/shader_nss_preprocess.js +246 -246
  224. package/src/shade/renderer/rasterize/chunk_triangle_winding_is_reversed.d.ts +1 -2
  225. package/src/shade/renderer/rasterize/chunk_triangle_winding_is_reversed.d.ts.map +1 -1
  226. package/src/shade/renderer/rasterize/chunk_triangle_winding_is_reversed.js +34 -35
  227. package/src/shade/renderer/shader/chunk/atmosphere/C_MIE_SCATTERING_DECLARATION.d.ts +2 -2
  228. package/src/shade/renderer/shader/chunk/atmosphere/C_MIE_SCATTERING_DECLARATION.js +2 -2
  229. package/src/shade/renderer/shader/chunk/atmosphere/chunk_compute_extinction.js +1 -1
  230. package/src/shade/renderer/shader/chunk/atmosphere/hillaire/DENSITY_PROFILE_LAYER_STRUCT.d.ts +1 -1
  231. package/src/shade/renderer/shader/chunk/atmosphere/hillaire/DENSITY_PROFILE_LAYER_STRUCT.js +1 -1
  232. package/src/shade/renderer/shader/chunk/brdf/fresnel/chunk_F_Schlick.d.ts +3 -3
  233. package/src/shade/renderer/shader/chunk/brdf/fresnel/chunk_F_Schlick.js +3 -3
  234. package/src/shade/renderer/shader/chunk/color/tonemap/aces/chunk_aces_ue_matrices.d.ts +9 -10
  235. package/src/shade/renderer/shader/chunk/color/tonemap/aces/chunk_aces_ue_matrices.d.ts.map +1 -1
  236. package/src/shade/renderer/shader/chunk/color/tonemap/aces/chunk_aces_ue_matrices.js +9 -10
  237. package/src/shade/renderer/shader/chunk/color/tonemap/aces/chunk_tonemap_ue_filmic.d.ts +4 -4
  238. package/src/shade/renderer/shader/chunk/color/tonemap/aces/chunk_tonemap_ue_filmic.js +5 -5
  239. package/src/shade/renderer/shader/chunk/math/chunk_f16_round_stochastic.d.ts +1 -2
  240. package/src/shade/renderer/shader/chunk/math/chunk_f16_round_stochastic.d.ts.map +1 -1
  241. package/src/shade/renderer/shader/chunk/math/chunk_f16_round_stochastic.js +1 -2
  242. package/src/shade/renderer/shader/chunk/noise/chunk_stbn_sample_vec2.d.ts +14 -1
  243. package/src/shade/renderer/shader/chunk/noise/chunk_stbn_sample_vec2.d.ts.map +1 -1
  244. package/src/shade/renderer/shader/chunk/noise/chunk_stbn_sample_vec2.js +19 -6
  245. package/src/shade/renderer/shader/chunk/noise/chunk_stbn_sample_vec3.d.ts +10 -1
  246. package/src/shade/renderer/shader/chunk/noise/chunk_stbn_sample_vec3.d.ts.map +1 -1
  247. package/src/shade/renderer/shader/chunk/noise/chunk_stbn_sample_vec3.js +14 -6
  248. package/src/shade/renderer/shader/chunk/random/murmur/chunk_murmur3_vec3u.d.ts +1 -1
  249. package/src/shade/renderer/shader/chunk/random/murmur/chunk_murmur3_vec3u.js +1 -1
  250. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.d.ts.map +1 -1
  251. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.js +7 -2
  252. package/src/shade/renderer/shadow/vsm/DEFAULT_VSM_MAX_DYNAMIC_LOD_BIAS.d.ts +2 -3
  253. package/src/shade/renderer/shadow/vsm/DEFAULT_VSM_MAX_DYNAMIC_LOD_BIAS.d.ts.map +1 -1
  254. package/src/shade/renderer/shadow/vsm/DEFAULT_VSM_MAX_DYNAMIC_LOD_BIAS.js +7 -8
  255. package/src/shade/renderer/shadow/vsm/DEFAULT_VSM_MAX_LOAD_FACTOR.d.ts +1 -1
  256. package/src/shade/renderer/shadow/vsm/DEFAULT_VSM_MAX_LOAD_FACTOR.js +12 -12
  257. package/src/shade/renderer/shadow/vsm/VSMPageManager.d.ts +2 -2
  258. package/src/shade/renderer/shadow/vsm/VSMPageManager.d.ts.map +1 -1
  259. package/src/shade/renderer/shadow/vsm/VSMPageManager.js +3 -4
  260. package/src/shade/renderer/water/GPUWaterRenderer.d.ts +0 -6
  261. package/src/shade/renderer/water/GPUWaterRenderer.d.ts.map +1 -1
  262. package/src/shade/renderer/water/GPUWaterRenderer.js +12 -17
  263. package/src/shade/renderer/water/medium/graph_water_meshlets.d.ts +35 -0
  264. package/src/shade/renderer/water/medium/graph_water_meshlets.d.ts.map +1 -0
  265. package/src/shade/renderer/water/medium/graph_water_meshlets.js +89 -0
  266. package/src/shade/renderer/water/query/GPUWaterQueries.d.ts +1 -1
  267. package/src/shade/renderer/water/shader_water.d.ts.map +1 -1
  268. package/src/shade/renderer/water/shader_water.js +22 -13
  269. package/src/shade/renderer/water/shader_water_avboit.d.ts.map +1 -1
  270. package/src/shade/renderer/water/shader_water_avboit.js +7 -7
  271. package/src/shade/renderer/water/surface/graph_water_tessellation.d.ts +1 -1
  272. package/src/shade/renderer/water/surface/graph_water_tessellation.js +1 -1
  273. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +9 -1
  274. package/src/view/elements/progress/segmented/SegmentedResourceBarView.d.ts +0 -19
  275. package/src/view/elements/progress/segmented/SegmentedResourceBarView.d.ts.map +1 -1
  276. package/src/view/elements/progress/segmented/SegmentedResourceBarView.js +2 -52
  277. package/editor/REWORK_PLAN_2026_08.md +0 -692
  278. package/src/CODEC_LAYOUT_VERIFICATION.md +0 -419
  279. package/src/CORRECTNESS_HUNT_2026_07_24.md +0 -142
  280. package/src/DUPLICATION_AUDIT_2026_08_07/00_core_reuse_surface.md +0 -738
  281. package/src/DUPLICATION_AUDIT_2026_08_07/A_core_math_geom.md +0 -79
  282. package/src/DUPLICATION_AUDIT_2026_08_07/B_core_data.md +0 -93
  283. package/src/DUPLICATION_AUDIT_2026_08_07/C_gfx_render.md +0 -80
  284. package/src/DUPLICATION_AUDIT_2026_08_07/D_gfx_features.md +0 -164
  285. package/src/DUPLICATION_AUDIT_2026_08_07/E_physics.md +0 -69
  286. package/src/DUPLICATION_AUDIT_2026_08_07/F_sound.md +0 -110
  287. package/src/DUPLICATION_AUDIT_2026_08_07/G_net_save.md +0 -129
  288. package/src/DUPLICATION_AUDIT_2026_08_07/H_engine_misc.md +0 -72
  289. package/src/DUPLICATION_AUDIT_2026_08_07/I_generation_view.md +0 -74
  290. package/src/DUPLICATION_AUDIT_2026_08_07/K_crosscutting.md +0 -169
  291. package/src/DUPLICATION_AUDIT_2026_08_07.md +0 -254
  292. package/src/DUPLICATION_AUDIT_REMEDIATION.md +0 -250
  293. package/src/DUPLICATION_REVIEW_2026_10_24.md +0 -1072
  294. package/src/REVIEW_2026_08_06/adv-core.md +0 -511
  295. package/src/REVIEW_2026_08_06/adv-gfx.md +0 -480
  296. package/src/REVIEW_2026_08_06/adv-view.md +0 -446
  297. package/src/REVIEW_2026_08_06/api-core.md +0 -296
  298. package/src/REVIEW_2026_08_06/api-engine.md +0 -195
  299. package/src/REVIEW_2026_08_06/bvh-phys-sound-net.md +0 -507
  300. package/src/REVIEW_2026_08_06/core-binary.md +0 -348
  301. package/src/REVIEW_2026_08_06/core-collection.md +0 -376
  302. package/src/REVIEW_2026_08_06/core-math.md +0 -221
  303. package/src/REVIEW_2026_08_06/core-process.md +0 -266
  304. package/src/REVIEW_2026_08_06/core-science.md +0 -223
  305. package/src/REVIEW_2026_08_06/engine-ai-nav.md +0 -279
  306. package/src/REVIEW_2026_08_06/engine-animation.md +0 -167
  307. package/src/REVIEW_2026_08_06/engine-asset.md +0 -166
  308. package/src/REVIEW_2026_08_06/engine-ecs.md +0 -920
  309. package/src/REVIEW_2026_08_06/engine-input.md +0 -197
  310. package/src/REVIEW_2026_08_06/engine-misc.md +0 -248
  311. package/src/REVIEW_2026_08_06/engine-terrain.md +0 -52
  312. package/src/REVIEW_2026_08_06/generation.md +0 -176
  313. package/src/REVIEW_2026_08_06/geom-2d.md +0 -434
  314. package/src/REVIEW_2026_08_06/geom-3d.md +0 -117
  315. package/src/REVIEW_2026_08_06/gfx-gi.md +0 -143
  316. package/src/REVIEW_2026_08_06/gfx-render.md +0 -740
  317. package/src/REVIEW_2026_08_06/gfx-texture.md +0 -690
  318. package/src/REVIEW_2026_08_06/prior-criticals.md +0 -49
  319. package/src/REVIEW_2026_08_06/prior-highs.md +0 -138
  320. package/src/REVIEW_2026_08_06/test-gaps.md +0 -364
  321. package/src/REVIEW_2026_08_06/view.md +0 -667
  322. package/src/REVIEW_2026_08_06.md +0 -610
  323. package/src/core/binary/lz4/LZ4_HIGH_COMPRESSION_PLAN_2026_09_14.md +0 -542
  324. package/src/core/bvh2/bvh3/NOTES.md +0 -2
  325. package/src/core/bvh8/NOTES.md +0 -63
  326. package/src/core/cache/wtinylfu/benchmark/CacheWTinylfu.bench.md +0 -243
  327. package/src/core/color/COLOR_FIX_PLAN_2026_08_28.md +0 -417
  328. package/src/core/color/COLOR_REVIEW_2026_08_28.md +0 -779
  329. package/src/core/geom/2d/polygon/TRIANGULATION_DESIGN.md +0 -433
  330. package/src/core/geom/3d/atlas/ATLAS_PORT_PLAN.md +0 -486
  331. package/src/core/geom/3d/atlas/BFF_PLAN.md +0 -174
  332. package/src/core/geom/3d/atlas/REVIEW_02.md +0 -392
  333. package/src/core/geom/3d/gjk/GJK_REVIEW_NOTES.md +0 -146
  334. package/src/core/geom/3d/gjk/NOTES.md +0 -8
  335. package/src/core/geom/3d/topology/TOPO_MESH_RETIREMENT_PLAN.md +0 -135
  336. package/src/core/geom/GEOMETRY_REVIEW_002_API_ISSUES.md +0 -381
  337. package/src/core/geom/GEOMETRY_REVIEW_002_NAMING.md +0 -684
  338. package/src/core/geom/MANIFOLD_COMPARISON_2026_08_01.md +0 -554
  339. package/src/core/model/reactive/evaluation/PREDICATE_APPLICABILITY_PROPOSAL.md +0 -446
  340. package/src/engine/REVIEW_2026_07_03.md +0 -211
  341. package/src/engine/asset/loaders/image/IMAGE_CODEC_REVIEW_2026_08_28.md +0 -815
  342. package/src/engine/control/first-person/DESIGN.md +0 -658
  343. package/src/engine/control/first-person/DESIGN_COLLISION.md +0 -382
  344. package/src/engine/control/first-person/DESIGN_EXTENSIONS.md +0 -563
  345. package/src/engine/control/first-person/TODO.md +0 -160
  346. package/src/engine/ecs/ASYNC_SYSTEMS_PROPOSAL.md +0 -531
  347. package/src/engine/ecs/HIERARCHY_REVIEW.md +0 -717
  348. package/src/engine/ecs/async/WORKER_SYSTEM_PLAN.md +0 -262
  349. package/src/engine/ecs/ik/PLAN.md +0 -179
  350. package/src/engine/ecs/storage/binary/SERIALIZATION_COVERAGE.md +0 -272
  351. package/src/engine/ecs/storage/binary/object-v2/DESIGN.md +0 -199
  352. package/src/engine/ecs/transform/TRANSFORM64_MIGRATION_PLAN_2026_09_04.md +0 -521
  353. package/src/engine/graphics/CONTEXT_LOSS_RECOVERY_PLAN.md +0 -463
  354. package/src/engine/graphics/ecs/camera/pp/NOTES.md +0 -48
  355. package/src/engine/graphics/render/frame_graph/CORRECTNESS_FIXES_2026_09_04.md +0 -659
  356. package/src/engine/graphics/render/frame_graph/FRAME_GRAPH_RECOMMENDATIONS.md +0 -235
  357. package/src/engine/graphics/sh3/path_tracer/REVIEW_001_ACTION_PLAN.md +0 -490
  358. package/src/engine/graphics/texture/sampler/compare/FLIP_IMPLEMENTATION_PLAN.md +0 -466
  359. package/src/engine/input/GAMEPAD_API_PROPOSAL.md +0 -717
  360. package/src/engine/input/ecs/ism/ISM_DESIGN.md +0 -1523
  361. package/src/engine/input/ecs/ism/ISM_IMPLEMENTATION_PLAN.md +0 -627
  362. package/src/engine/navigation/mesh/OVERLAPPING_SURFACES_2026_08_25.md +0 -661
  363. package/src/engine/navigation/mesh/PATHFINDING_PLAN.md +0 -229
  364. package/src/engine/network/CONGESTION_CONTROL.md +0 -87
  365. package/src/engine/network/MESSAGE_TRANSPORT.md +0 -364
  366. package/src/engine/network/SMOOTHNESS_DESIGN.md +0 -400
  367. package/src/engine/physics/cloth/MEASUREMENTS.md +0 -5304
  368. package/src/engine/physics/cloth/PLAN.md +0 -3056
  369. package/src/engine/physics/fluid/GPU_FLUID_CASCADES_PROPOSAL_2026_10_16.md +0 -1382
  370. package/src/engine/physics/fluid/REVIEW_02_PLAN.md +0 -243
  371. package/src/engine/physics/fluid/solver/NOTES.md +0 -46
  372. package/src/engine/sound/SOUND_EMITTER_RETIREMENT_PLAN.md +0 -536
  373. package/src/engine/sound/simulation/IMPLEMENTATION_PLAN.md +0 -432
  374. package/src/engine/sound/simulation/PROBE_PLACEMENT.md +0 -250
  375. package/src/engine/sound/simulation/PROBE_TRANSFER_RESEARCH.md +0 -322
  376. package/src/engine/sound/simulation/REFLECTION_IR_PLAN.md +0 -261
  377. package/src/engine/sound/simulation/VISIBILITY_GRAPH_PLAN.md +0 -121
  378. package/src/engine/sound/sopra/IMPLEMENTATION_PLAN.md +0 -999
  379. package/src/format/image/avif/DECISIONS.md +0 -545
  380. package/src/format/image/jpeg/NOTES.md +0 -3
  381. package/src/format/scene/gltf/MESHOPT_COMPRESSION_PLAN.md +0 -814
  382. package/src/generation/COORDINATES.md +0 -54
  383. package/src/generation/REVIEW_01_ACTION_PLAN.md +0 -628
  384. package/src/generation/foliage/ANNUAL_SHOOTS_BRIEF_2026_10_25.md +0 -220
  385. package/src/generation/foliage/CROWN_FILLING_BRIEF_2026_10_26.md +0 -172
  386. package/src/generation/foliage/CROWN_FULLNESS_BRIEF_2026_10_26.md +0 -86
  387. package/src/generation/foliage/FOLIAGE_DESIGN.md +0 -547
  388. package/src/generation/foliage/FOLIAGE_PLAN.md +0 -198
  389. package/src/generation/foliage/LEAF_ARCHITECTURE_BRIEF_2026_10_26.md +0 -158
  390. package/src/generation/foliage/LOD_REWORK_BRIEF_2026_10_27.md +0 -521
  391. package/src/generation/foliage/REAL_TIME_TREES_BRIEF_2026_10_27.md +0 -86
  392. package/src/generation/foliage/SELF_ORGANIZING_FRAMEWORK_BRIEF_2026_10_26.md +0 -347
  393. package/src/generation/foliage/SHOOT_SYSTEMS_ALL_SPECIES_BRIEF_2026_10_26.md +0 -248
  394. package/src/generation/foliage/SPEEDTREE_COMPARISON_2026_10_24.md +0 -694
  395. package/src/generation/foliage/TWO_FRONT_ENDS_BRIEF_2026_10_28.md +0 -552
  396. package/src/shade/RENDERER_CONTRACT.md +0 -697
  397. package/src/shade/SHADER_F16_PROPOSAL_2026_10_24.md +0 -263
  398. package/src/shade/device/IMMEDIATE_DATA_PLAN_2026_08_28.md +0 -569
  399. package/src/shade/device/PASS_ENCODER_PROPOSAL_2026_08_31.md +0 -755
  400. package/src/shade/device/mock/EXTENSION_PROPOSAL_2026_08_22.md +0 -458
  401. package/src/shade/device/mock/IMPLEMENTATION_PLAN.md +0 -255
  402. package/src/shade/device/mock/REVIEW_2026_08_22.md +0 -527
  403. package/src/shade/device/timing/GPU_PROFILER_PROPOSAL_2026_08_28.md +0 -894
  404. package/src/shade/device/timing/profile/SGPT_FORMAT.md +0 -345
  405. package/src/shade/renderer/NOTES.md +0 -78
  406. package/src/shade/renderer/PLAN.md +0 -8
  407. package/src/shade/renderer/animation/ADDITIVE_BLENDING_PLAN.md +0 -145
  408. package/src/shade/renderer/animation/SKINNING_FRAME_PLAN.md +0 -357
  409. package/src/shade/renderer/atmosphere/NOTES.md +0 -6
  410. package/src/shade/renderer/camera/orbital/MomentumAxis.d.ts +0 -76
  411. package/src/shade/renderer/camera/orbital/MomentumAxis.d.ts.map +0 -1
  412. package/src/shade/renderer/camera/orbital/MomentumAxis.js +0 -164
  413. package/src/shade/renderer/camera/orbital/OrbitalCameraConfig.d.ts +0 -45
  414. package/src/shade/renderer/camera/orbital/OrbitalCameraConfig.d.ts.map +0 -1
  415. package/src/shade/renderer/camera/orbital/OrbitalCameraConfig.js +0 -66
  416. package/src/shade/renderer/camera/orbital/OrbitalCameraInput.d.ts +0 -98
  417. package/src/shade/renderer/camera/orbital/OrbitalCameraInput.d.ts.map +0 -1
  418. package/src/shade/renderer/camera/orbital/OrbitalCameraInput.js +0 -184
  419. package/src/shade/renderer/camera/orbital/OrbitalCameraRig.d.ts +0 -175
  420. package/src/shade/renderer/camera/orbital/OrbitalCameraRig.d.ts.map +0 -1
  421. package/src/shade/renderer/camera/orbital/OrbitalCameraRig.js +0 -411
  422. package/src/shade/renderer/camera/orbital/README.md +0 -81
  423. package/src/shade/renderer/camera/orbital/index.d.ts +0 -6
  424. package/src/shade/renderer/camera/orbital/index.d.ts.map +0 -1
  425. package/src/shade/renderer/camera/orbital/index.js +0 -9
  426. package/src/shade/renderer/extension/RENDER_EXTENSION_DESIGN.md +0 -964
  427. package/src/shade/renderer/fluid/GPU_FLUID_OCCUPANCY_AND_SOTA_REVIEW_2026_10_26.md +0 -361
  428. package/src/shade/renderer/geometry/bvh/BLAS_REFIT_BATCH_PLAN.md +0 -619
  429. package/src/shade/renderer/geometry/meshlet/COMPACTION_PLAN_2026_09_16.md +0 -674
  430. package/src/shade/renderer/geometry/sdf/NOTES.md +0 -6
  431. package/src/shade/renderer/geometry/virtual/ATTRIBUTE_PLAN_2026_09_18.md +0 -540
  432. package/src/shade/renderer/geometry/virtual/MICRON_COMPARISON_2026_08_20.md +0 -305
  433. package/src/shade/renderer/geometry/virtual/VGEO_FORMAT.md +0 -913
  434. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md +0 -787
  435. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_PLAN.md +0 -483
  436. package/src/shade/renderer/geometry/virtual/VK_LOD_CLUSTERS_COMPARISON_2026_08_20.md +0 -301
  437. package/src/shade/renderer/geometry/virtual/WEDGE_PLAN_2026_09_18.md +0 -448
  438. package/src/shade/renderer/geometry/virtual/runtime/CULL_PLAN_2026_09_16.md +0 -385
  439. package/src/shade/renderer/geometry/virtual/runtime/CUT_PLAN_2026_09_14.md +0 -656
  440. package/src/shade/renderer/geometry/virtual/runtime/REVIEW_LEDGER.md +0 -308
  441. package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN.md +0 -657
  442. package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN_2026_09_14.md +0 -551
  443. package/src/shade/renderer/geometry/virtual/runtime/SHADOW_PLAN_2026_09_28.md +0 -536
  444. package/src/shade/renderer/global_illumination/lpv/NOTES.md +0 -3
  445. package/src/shade/renderer/global_illumination/probe_clipmap/PROBE_CLIPMAP_PROPOSAL_2026_10_27.md +0 -4225
  446. package/src/shade/renderer/global_illumination/probe_clipmap/PROBE_RAYS_VARIABLE_AND_SORTED_SCOPE_2026_10_30.md +0 -410
  447. package/src/shade/renderer/global_illumination/sharc/NOTES.md +0 -8
  448. package/src/shade/renderer/gpu_primitive/bvh/GPU_BVH_BUILD_PLAN.md +0 -1369
  449. package/src/shade/renderer/gpu_primitive/bvh/PHASE1_HANDOVER.md +0 -202
  450. package/src/shade/renderer/gpu_primitive/indirect/NOTES.md +0 -94
  451. package/src/shade/renderer/hiz/NOTES.md +0 -3
  452. package/src/shade/renderer/hiz/shader_hzb_reduce_mip0_clip.d.ts +0 -8
  453. package/src/shade/renderer/hiz/shader_hzb_reduce_mip0_clip.d.ts.map +0 -1
  454. package/src/shade/renderer/light/cluster/NOTES.md +0 -11
  455. package/src/shade/renderer/light/cluster/PROPOSAL_ALGORITHM_2026_10_16.md +0 -524
  456. package/src/shade/renderer/light/cluster/PROPOSAL_HIERARCHICAL_2026_10_16.md +0 -1101
  457. package/src/shade/renderer/light/environment/shader_convolve_reflection_map_from_averages.d.ts +0 -13
  458. package/src/shade/renderer/light/environment/shader_convolve_reflection_map_from_averages.d.ts.map +0 -1
  459. package/src/shade/renderer/light/environment/shader_convolve_reflection_map_from_averages.js +0 -198
  460. package/src/shade/renderer/material/resident/shader_resident_texture_means.d.ts +0 -24
  461. package/src/shade/renderer/material/resident/shader_resident_texture_means.d.ts.map +0 -1
  462. package/src/shade/renderer/material/resident/shader_resident_texture_means.js +0 -120
  463. package/src/shade/renderer/particles/DESIGN.md +0 -1011
  464. package/src/shade/renderer/particles/EMITTER_GLOBAL_STATE_PLAN_2026_10_29.md +0 -283
  465. package/src/shade/renderer/particles/ORIENTATION_PLAN_2026_10_15.md +0 -453
  466. package/src/shade/renderer/path_tracer/PATH_TRACED_MEDIA_PLAN_2026_10_02.md +0 -520
  467. package/src/shade/renderer/postprocess/bloom/NOTES.md +0 -6
  468. package/src/shade/renderer/postprocess/fsr/NOTES.md +0 -4
  469. package/src/shade/renderer/postprocess/gtao/NOTES.md +0 -6
  470. package/src/shade/renderer/postprocess/nss/NOTES.md +0 -339
  471. package/src/shade/renderer/postprocess/perspective/NOTES.md +0 -3
  472. package/src/shade/renderer/postprocess/sscs/NOTES.md +0 -5
  473. package/src/shade/renderer/postprocess/ssr/NOTES.md +0 -14
  474. package/src/shade/renderer/postprocess/ssr/REPROJECTION_PROPOSAL.md +0 -286
  475. package/src/shade/renderer/postprocess/ssr/prefilter/NOTES.md +0 -39
  476. package/src/shade/renderer/postprocess/taa/NOTES.md +0 -11
  477. package/src/shade/renderer/postprocess/upscale-dither/NOTES.md +0 -78
  478. package/src/shade/renderer/postprocess/vrs/NOTES.md +0 -4
  479. package/src/shade/renderer/rasterize/native/avboit/AVBOIT_LEDGER.md +0 -1218
  480. package/src/shade/renderer/rasterize/native/avboit/AVBOIT_PLAN_2026_09_03.md +0 -600
  481. package/src/shade/renderer/restir/reservoir/NOTES.md +0 -6
  482. package/src/shade/renderer/shader/chunk/atmosphere/NOTES.md +0 -6
  483. package/src/shade/renderer/shader/chunk/brdf/FRESNEL_BRIEF_2026_10_16.md +0 -394
  484. package/src/shade/renderer/shader/chunk/color/tonemap/ACES_TONE_MAPPING_BRIEF_2026_10_17.md +0 -160
  485. package/src/shade/renderer/shader/chunk/color/tonemap/HDR_TONE_MAPPING_FORMS_BRIEF_2026_10_16.md +0 -322
  486. package/src/shade/renderer/shader/chunk/color/tonemap/SDR_TONE_MAPPING_BRIEF_2026_10_16.md +0 -247
  487. package/src/shade/renderer/shader/chunk/fsr/NOTES.md +0 -3
  488. package/src/shade/renderer/shader/chunk/fsr/spd/NOTES.md +0 -4
  489. package/src/shade/renderer/shader/chunk/geometry/ray/NOTES.md +0 -4
  490. package/src/shade/renderer/shader/chunk/material/MULTISCATTER.md +0 -159
  491. package/src/shade/renderer/shader/chunk/mboit/NOTES.md +0 -38
  492. package/src/shade/renderer/shader/chunk/spherical_harmonics/l1i/NOTES.md +0 -3
  493. package/src/shade/renderer/shader/chunk/spherical_harmonics/sampling/NOTES.md +0 -8
  494. package/src/shade/renderer/shader/compiler/SHADER_SWITCH_PROPOSAL_2026_10_16.md +0 -932
  495. package/src/shade/renderer/shadow/contact/FINDINGS.md +0 -413
  496. package/src/shade/renderer/shadow/map/csm/NOTES.md +0 -5
  497. package/src/shade/renderer/shadow/ray/NOTES.md +0 -31
  498. package/src/shade/renderer/shadow/sdf/NOTES.md +0 -9
  499. package/src/shade/renderer/shadow/sdf/brixelizer/NOTES.md +0 -5
  500. package/src/shade/renderer/shadow/sdf/cascade/NOTES.md +0 -9
  501. package/src/shade/renderer/shadow/vsm/NOTES.md +0 -12
  502. package/src/shade/renderer/shadow/vsm/PLAN.md +0 -442
  503. package/src/shade/renderer/shadow/vsm/REVIEW_LEDGER.md +0 -43
  504. package/src/shade/renderer/texture/COMPRESSED_TEXTURE_PLAN_2026_09_01.md +0 -2444
  505. package/src/shade/renderer/texture/mipmaps/NOTES.md +0 -4
  506. package/src/shade/renderer/volumetrics/NOTES.md +0 -1329
  507. package/src/shade/renderer/volumetrics/VOLUMETRIC_NOISE_PLAN_2026_10_15.md +0 -336
  508. package/src/shade/renderer/water/medium/GPUWaterBodies.d.ts +0 -23
  509. package/src/shade/renderer/water/medium/GPUWaterBodies.d.ts.map +0 -1
  510. package/src/shade/renderer/water/medium/GPUWaterBodies.js +0 -75
  511. package/src/shade/wgsl/NOTES.md +0 -4
  512. package/src/view/elements/progress/segmented/segment_frame_transform.d.ts +0 -15
  513. package/src/view/elements/progress/segmented/segment_frame_transform.d.ts.map +0 -1
  514. package/src/view/elements/progress/segmented/segment_frame_transform.js +0 -69
@@ -1,463 +0,0 @@
1
- # WebGL context loss recovery — investigation, plan, and results
2
-
3
- Date: 2026-07-30. Scope: `meep` graphics stack (three.js r136, WebGL2) as consumed by the Askara app
4
- (`app/src/mir-engine/model/game/makeMirEngineConfig.js`).
5
-
6
- Goal: when the browser drops the WebGL context, detect it, recover in place, and let the player continue —
7
- no application restart, no reload, no lost session state.
8
-
9
- **Status: superseded, kept as the record.** Phases 0–3 were implemented and verified against the
10
- renderer described here; that renderer — three.js r136 on WebGL2 — has since been removed from the
11
- repo, and Shade (WebGPU) replaced it. Phases 4–6 (§11) will not be done as written: Shade does not
12
- recover a lost device at all — `Renderer.on.contextRestored` is documented as never firing, and the
13
- response to a loss is a message and a reload (`ShadeDeviceFailure.device_lost`) — so the in-place
14
- recovery this document is about has no successor to port it to. Most links below point into a tree
15
- that no longer holds these files. Claims are tagged **[src]** (read from three.js / meep source) or
16
- **[measured]** (observed in the browser harness, §10).
17
-
18
- ---
19
-
20
- ## 1. TL;DR
21
-
22
- * **The engine was much closer to recoverable than it looked.** three.js r136 rebuilds all of its
23
- GPU-object bookkeeping on `webglcontextrestored` (`initGLContext()` re-instantiates `WebGLProperties`),
24
- so every texture, geometry, render target and shader program is re-created from CPU-side data on first
25
- use after restore. meep keeps CPU-side sources for essentially everything it uploads. **[src]**
26
- **[measured]**: on a fresh context the same scene renders with identical draw calls (7) and triangle
27
- count (412,999), and pixel-identical output once one known defect is accounted for.
28
- * **That one defect was the environment map.** `load_and_set_cubemap_v0` baked PMREM into a render target
29
- and dropped the source texture, so IBL died with the context — worth **59% of scene luminance** in the
30
- test scene (83.8 → 34.7). It is now re-baked on restore from a retained source. **[measured]**
31
- * **Everything else needed was state, not content**: three silently resets the clear colour on restore
32
- (`WebGLBackground` is re-instantiated), rendering was not gated while the context was gone, and nothing
33
- told the user or the metrics pipeline anything.
34
- * **Recovery is now pixel-exact.** Repeated loss/restore cycles on the harness scene come back
35
- bit-identical to the baseline, with no resource growth across cycles. **[measured]**
36
- * **Cost**: steady-state overhead is one boolean compare per frame and no allocations — the design is
37
- push-based (signals), never polled. The unavoidable cost is the first frame after restore:
38
- **~37 ms** on the harness scene, **~214 ms** on the game's title scene, against ~0.6 ms steady state.
39
- **[measured]**
40
- * **What is not yet proven**: that the *browser* will hand the context back. The restore path only runs
41
- while the page is visible, and the harness available here runs in a hidden tab (§10.4). The failure
42
- ladder exists precisely because that decision is not ours to make.
43
-
44
- ---
45
-
46
- ## 2. What happened before this change
47
-
48
- | Step | Old behaviour | File |
49
- | --- | --- | --- |
50
- | Context lost | three set `_isContextLost = true`; meep logged a typo'd warning | three.module.js:26236, GraphicsEngine.js |
51
- | During loss | `Engine.render()` kept calling `graphics.render()` every rAF. three guards only `render()`; `setRenderTarget` / `clear` / `copyTextureToTexture` / `readRenderTargetPixels` are unguarded | three.module.js:26555, [Engine.js:438](src/engine/Engine.js:438) |
52
- | Context restored | three ran `initGLContext()`, meep logged and did nothing | three.module.js:26246 |
53
- | Result | scene mostly returned by accident, with black IBL, a reset clear colour, a multi-second hitch, and no diagnostics | — |
54
- | User feedback | none, ever, including on unrecoverable failure | — |
55
-
56
- ---
57
-
58
- ## 3. Why most of it recovers for free
59
-
60
- `onContextRestore` → `initGLContext()` replaces `properties`, `textures`, `attributes`, `geometries`,
61
- `bindingStates`, `programCache`, `state`, `background`, `info`, `renderLists`, `renderStates`
62
- (three.module.js:25921, 26246). Because `WebGLProperties` is a **fresh `WeakMap`**:
63
-
64
- * **Textures** — `initTexture()` sees no `__webglInit`, `uploadTexture()` sees `__version === undefined`,
65
- so every texture re-uploads from `texture.image` / `texture.mipmaps` (three.module.js:22505).
66
- * **Render targets** — `setRenderTarget()` sees `__webglFramebuffer === undefined` and calls
67
- `setupRenderTarget()` (three.module.js:27473). The objects and their `texture` identities survive, so
68
- uniforms pointing at them stay valid. Their *contents* are gone (§4.2).
69
- * **Geometry / VAOs** — re-uploaded from the `BufferAttribute` arrays; meep never uses
70
- `BufferAttribute.onUpload` to release them.
71
- * **Programs** — `WebGLPrograms` cache is new, so every material recompiles on first draw.
72
- * **Extensions** — `extensions.init()` re-requests `EXT_color_buffer_float` on WebGL2, which is what the
73
- float/half-float buffers need (three.module.js:16065).
74
- * **Shadow maps** — re-rendered every frame from `postVisibilityBuild`
75
- ([ThreeLightBinding.js:291](src/engine/graphics/ecs/light/binding/three/ThreeLightBinding.js:291)).
76
- * **CPU-sourced data textures** — FoW (`Sampler2D` → `DataTexture`), Forward+ cluster tables, terrain
77
- splat/height/AO maps, LPG SH textures. All keep their typed arrays, so all re-upload.
78
- * **Extra memory cost of relying on this**: none. Those CPU-side sources are retained today regardless.
79
-
80
- **Corollary that shaped the design:** recovery must be *narrow*. Re-running startup would be actively
81
- harmful — `FrameBuffer.initialize()` allocates a **new** render target per call
82
- ([ColorAndDepthFrameBuffer.js:31](src/engine/graphics/render/buffer/buffers/ColorAndDepthFrameBuffer.js:31))
83
- and plugins allocate their own
84
- ([AmbientOcclusionPostProcessEffect.js:91](src/engine/graphics/render/buffer/simple-fx/ao/AmbientOcclusionPostProcessEffect.js:91)),
85
- so "just restart graphics" would leak a full G-buffer set per loss and turn a recoverable event into an
86
- out-of-memory crash.
87
-
88
- ---
89
-
90
- ## 4. What is lost and does not come back by itself
91
-
92
- ### 4.1 Renderer configuration dropped by `initGLContext()` — FIXED
93
-
94
- `WebGLBackground` is re-instantiated and owns the clear colour/alpha (`clearColor = 0x000000`,
95
- `clearAlpha = 0`; three.module.js:13615), and `setClearColor` delegates to it (three.module.js:26154).
96
- **[measured]** counterfactual on a bare renderer: `setClearColor(0xBBBBFF, 0)` then a restore event →
97
- `getClearColor` returns `(0, 0, 0)`. Plain renderer properties (`autoClear`, `toneMapping`,
98
- `outputEncoding`, `sortObjects`, `info.autoReset`, `shadowMap.*`) do survive — three preserves the
99
- shadow-map and `info.autoReset` fields explicitly (three.module.js:26250).
100
-
101
- Fix: `configureThreeRenderer` is exported and re-applied on restore, along with `enableExtensions()`,
102
- `debug.checkShaderErrors` and `updateSize()`.
103
-
104
- ### 4.2 Render-target contents that are not rebuilt every frame — FIXED
105
-
106
- Every `WebGLRenderTarget` construction site (16 files) was audited. In the shipped configuration all are
107
- re-rendered each frame (G-buffer, normal buffer, composit layers, outline, AO, shadow maps) **except** the
108
- PMREM environment map: `load_and_set_cubemap_v0` → `load_environment_map` baked a `WebGLCubeRenderTarget`
109
- once, assigned `scene.environment`, and then `dispose()`d the source cube texture, dropping the only
110
- reference — so the bake could not be repeated. **[measured]**: losing it costs 59% of scene luminance, and
111
- `scene.environment = null` on a live renderer is pixel-identical to a fresh context, which is how the
112
- defect was isolated.
113
-
114
- Fix: the graphics engine owns the bake. `set_environment_map(texture, projection)` retains the source and
115
- produces the prefiltered radiance; `set_environment_texture` adds the skybox on top; the restore handler
116
- re-bakes and disposes the previous target. `load_and_set_cubemap_v0` now loads the source and hands it
117
- over instead of baking behind the engine's back.
118
-
119
- ### 4.3 Raw GL handles and residency bookkeeping — library tier, since deleted
120
-
121
- These were `meep` public surface but were not reachable from `makeMirEngineConfig`, so they were
122
- correctness debt rather than shipping blockers (Phase 6). Every one of them went with the WebGL
123
- renderer, so the paths are recorded as they stood rather than linked:
124
-
125
- | Subsystem | What breaks | File, as of 2026-07-30 |
126
- | --- | --- | --- |
127
- | Virtual texture | page atlas written with `copyTextureToTexture`; CPU residency map still claims pages are valid → garbage tiles forever | `src/engine/graphics/texture/virtual/VirtualTexturePage.js:389` |
128
- | `WebGLTextureAtlas` | same pattern | `src/engine/graphics/texture/atlas/gpu/WebGLTextureAtlas.js:178` |
129
- | Node-based particles | raw `gl.createBuffer()` handles + cached `gl`, no invalidation | `src/engine/graphics/particles/node-based/simulation/GLDataBuffer.js:48`, `TransformFeedback.js:414` |
130
- | Hi-Z occlusion | readback of a lost target yields zeroes → whole-frame visibility misclassification | `src/engine/graphics/render/visibility/hiz/query/BatchOcclusionQuery.js:149` |
131
- | Impostors | baked atlases are GPU-only | `src/engine/graphics/impostors/octahedral/ImpostorBaker.js` |
132
-
133
- Virtual texturing is the one row with a live successor — `shade/renderer/texture/virtual/`
134
- (`VirtualTextureManager` / `VTPageTable` / `VTPhysicalCache`), which keeps a CPU mirror of residency
135
- just as the old stack did. The concern still does not carry over, because it is a *restore* hazard:
136
- it needs a frame drawn after the device comes back, reading a residency map that outlived the loss.
137
- Shade never draws that frame — `Renderer.on.contextRestored` is documented as never firing — and the
138
- VT stack accordingly has no loss, restore or generation hook anywhere in it. There is nothing to
139
- re-point this row at.
140
-
141
- ### 4.4 Secondary contexts — Phase 4
142
-
143
- A GPU-process crash kills every context on the page at once, so recovery is ultimately a page-level
144
- concern. The secondary contexts, in priority order:
145
-
146
- * **`computeImageBitmapEquality`** — caches a module-level WebGL2 context plus **one texture and one
147
- framebuffer created once** ([computeImageBitmapEquality.js:43](src/engine/asset/loaders/material/computeImageBitmapEquality.js:43)).
148
- After a loss those handles are dead and never recreated, so `bitmap2sampler_gl` silently reads zeroes and
149
- texture dedup starts declaring unrelated textures identical. This is the worst failure mode found:
150
- silent, wrong, and it corrupts CPU-side results rather than just pixels. Worth fixing on its own merits.
151
- * **`MinimapWorldGL`** — holds a pooled renderer for the lifetime of the minimap
152
- ([MinimapWorldGL.js:124](src/view/minimap/gl/MinimapWorldGL.js:124)); it has a full re-render path, so
153
- recovery is a re-render, not a rebuild.
154
- * **`MeshPreview`** — takes a renderer per linked view. Editor-level feature, low priority.
155
-
156
- `WebGLRendererPool` itself is not a significant risk: most of the engine takes a supplied renderer rather
157
- than reaching into the pool, and the remaining callers are short-lived bakes. (Noted in passing while
158
- reading it: `useAsync()` drops the callback's return value — `await` without `return`,
159
- [RendererPool.js:74](src/engine/graphics/render/RendererPool.js:74). `buildLightTexture` happens to rely
160
- only on the side effect, so nothing is broken today.)
161
-
162
- ### 4.5 Async work in flight across a loss — partly addressed
163
-
164
- Bakes that straddle a loss complete with garbage and nobody notices: terrain AO
165
- ([BuildLightTexture.js:31](src/engine/ecs/terrain/ecs/BuildLightTexture.js:31)), impostor bakes,
166
- `compileAllMaterials` during `transitionToScene`. The environment bake is now immune because it is repeated
167
- on restore from a retained source; the general mechanism is the context generation counter
168
- (`graphics.context.generation`), which async work can compare against the generation it started in. No
169
- existing bake uses it yet — wiring them is Phase 4 work, and there is no way to detect the problem by
170
- catching, because a lost context does not throw.
171
-
172
- ---
173
-
174
- ## 5. What was built
175
-
176
- ### 5.1 `WebGLContextMonitor` — the state machine
177
-
178
- `src/engine/graphics/context/WebGLContextMonitor.js`, with `WebGLContextState` (Live / Lost / Failed) and
179
- `WebGLContextFailureReason` (`restore-timeout` / `too-many-losses`).
180
-
181
- * **Push, not poll.** No `gl.isContextLost()` per frame, no per-resource generation comparison in hot
182
- loops. Consumers subscribe; the per-frame cost is one field compare (`monitor.is_live`).
183
- * **No separate `Restoring` state.** The monitor always calls `preventDefault()`, so `Lost` already means
184
- "gone, waiting for the browser", and the fix-ups run synchronously inside the restore handler. Three
185
- states, no observable in-between.
186
- * **Generation counter** — monotonic, bumped per restore, never reset (even when re-attaching to a new
187
- canvas), so stale async results are always recognisable.
188
- * **Bounded recovery**: `restore_timeout` (default 5 s) escalates to `Failed`; `max_loss_count` (default 3)
189
- within `loss_window` (default 60 s) does too. The window matters: a session that hits one unrelated loss
190
- every couple of hours should keep recovering, one that dies four times in a minute should not.
191
- * **Terminal means terminal** — a restore that arrives after `Failed` is ignored, because the application
192
- has already been told the device is gone and may have torn down presentation state.
193
- * **No new virtual hooks.** Deliberately not adding `onContextRestored()` no-ops to `FrameBuffer`,
194
- `EnginePlugin`, `System` and friends: that would spread an empty method across dozens of classes for a
195
- handful of real subscribers.
196
-
197
- ### 5.2 Graphics engine wiring
198
-
199
- `GraphicsEngine` owns the monitor (`graphics.context`) and re-emits ordered engine-level signals
200
- `on.contextLost` / `on.contextRestored(generation)` / `on.contextFailed(reason)` — dispatched *after* its
201
- own fix-ups, so subscribers can render immediately. `render()` returns early while the context is not
202
- live, which is also what keeps meep's unguarded `setRenderTarget`/`clear`/readback calls away from a dead
203
- context. Loss, restore and failure are recorded through `globalMetrics`, next to the existing `gpu-type`
204
- metric, because without telemetry we will never learn the real-world loss rate.
205
-
206
- Restore sequence, in order: `configureThreeRenderer` → `debug.checkShaderErrors` → `enableExtensions()` →
207
- `updateSize()` → re-bake environment → `on.contextRestored`. Explicitly *not* included:
208
- `initializeFrameBuffers()` or any plugin startup (§3 corollary).
209
-
210
- ### 5.3 Simulation and failure policy
211
-
212
- `Engine` subscribes to the three signals. Rendering stops immediately, but the simulation keeps running for
213
- the first `CONTEXT_LOSS_SIMULATION_PAUSE_DELAY` (2 s) — most losses resolve in well under a second and
214
- stopping the world for those is more disruptive than letting it run. A longer outage pauses the ticker via
215
- `Ticker.pause()`, which freezes the clock so the first step after resuming is normal-sized (`Clock.getDelta`
216
- does not clamp, so pausing without that would hand physics one enormous step). A ticker that somebody else
217
- already paused is left alone, and never resumed by us — hence the new `Ticker.is_active` / `Ticker.is_paused`
218
- accessors, since `pause()`/`resume()` throw when the loop is not cycling.
219
-
220
- On `Failed`: the simulation is paused, application state is left intact (so a save-on-failure handler
221
- stays viable), and `GraphicsContextFailureView` explains the situation with a reload button, instead of
222
- leaving the player looking at a black canvas.
223
-
224
- ---
225
-
226
- ## 6. Performance impact
227
-
228
- **Steady state (no loss):**
229
-
230
- | Cost | Magnitude |
231
- | --- | --- |
232
- | Per-frame gate in `GraphicsEngine.render()` | one field compare; unmeasurable |
233
- | Signal subscriptions | 4 subscribers, invoked only on context events |
234
- | Extra retained memory | the environment source texture (~24 KB for the shipped 32² cubemap) |
235
- | Polling / `isContextLost()` | none, by design |
236
- | Hot-path branches added elsewhere | none |
237
-
238
- **During recovery [measured]** — intrinsic to context loss, not to this design:
239
-
240
- | Scene | First frame after restore | Steady state |
241
- | --- | --- | --- |
242
- | Harness (terrain + metal sphere + sun/shadows, 5 programs) | 35–48 ms | ~0.6 ms |
243
- | Game title scene (14 programs) | 214 ms | — |
244
-
245
- The dominant term is shader recompilation plus lazy texture re-upload, both driven by three.js as materials
246
- are drawn. A one-off couple of hundred milliseconds is well inside what the failure overlay's absence
247
- implies (nothing is shown; the frame simply arrives late). If a larger scene turns out to stall long enough
248
- to be objectionable, the existing time-sliced `compileAllMaterials` task is the lever — it is already used
249
- on scene transitions — but on this evidence pre-warming is not worth its complexity yet.
250
-
251
- ---
252
-
253
- ## 7. Complexity
254
-
255
- ~640 lines added across 8 files, of which ~250 are the state machine plus its 12 tests and ~340 are the
256
- harness. No new abstractions imposed on unrelated code, no base-class churn, no per-resource generation
257
- plumbing:
258
-
259
- | File | Change |
260
- | --- | --- |
261
- | `graphics/context/WebGLContextState.js` | new, enum |
262
- | `graphics/context/WebGLContextFailureReason.js` | new, enum |
263
- | `graphics/context/WebGLContextMonitor.js` | new, state machine |
264
- | `graphics/context/WebGLContextMonitor.spec.js` | new, 12 tests |
265
- | `graphics/context/testWebGLContextLoss.js` | new, browser harness |
266
- | `graphics/GraphicsEngine.js` | monitor wiring, render gate, restore fix-ups, environment retention/re-bake |
267
- | `graphics/load_and_set_cubemap_v0.js` | hand the source to the engine instead of baking |
268
- | `Engine.js` | ticker policy, failure view, logging |
269
- | `simulation/Ticker.js` | `is_active` / `is_paused` accessors |
270
- | `view/graphics/WebGLContextFailureView.js` | new, failure overlay |
271
-
272
- ---
273
-
274
- ## 8. Adversarial review
275
-
276
- Each claim challenged, with what would falsify it, and what the experiments actually showed.
277
-
278
- **#1 "three re-uploads everything automatically, so most of the engine is already recoverable."**
279
- This was the load-bearing claim and it rested on reading `initGLContext()`. It could have failed if a
280
- texture's CPU source had been released, if a `Texture` subclass cached upload state outside `properties`,
281
- or if three left a dangling internal reference across restore. `_transmissionRenderTarget` is a closure
282
- variable *not* reset by `initGLContext()` — inspected, and it is re-allocated lazily through the fresh
283
- properties map, so it is fine, but it is exactly the shape of bug that would have invalidated the claim
284
- elsewhere. **Outcome: confirmed by pixels**, twice (fresh context, and synthetic restore). A grep would
285
- not have been enough; the fresh-context experiment is what turned it into evidence.
286
-
287
- **#2 "Nothing in the shipped game holds GPU-only content except PMREM."**
288
- Established by grepping construction sites and reading each hit — a static audit that could have missed a
289
- dirty-flag-driven cache that looks per-frame in code and behaves as cached at runtime. Shadow maps were
290
- specifically checked for this. **Outcome: confirmed for the harness scene**, and confirmed sharply: the
291
- fresh-context delta was *exactly* reproduced by setting `scene.environment = null` on the live renderer
292
- (34.70 vs 34.71 luminance, identical region breakdown), which leaves no room for a second hidden defect in
293
- that scene. Still unproven for content the harness scene does not exercise — FoW, decals, particles,
294
- Forward+ clusters, water — because the game's own scenes cannot be driven in a hidden tab (§10.4). Those
295
- are all CPU-sourced by inspection, which is weaker than a measurement.
296
-
297
- **#3 "In-place restore is sufficient."**
298
- Still the weakest assumption, and the experiments *sharpened* the worry rather than settling it:
299
- `preventDefault()` makes the browser *allowed* to restore, not obliged to, and in this environment it
300
- never did (§10.4) — for an environmental reason (hidden tab), but the failure mode was real and the code
301
- had to handle it. **Outcome: the fallback ladder is baseline, and it fired correctly** — timeout →
302
- `Failed` → overlay → simulation paused. Whatever the browser decides, the player ends up with a coherent
303
- state rather than a black screen.
304
-
305
- **#4 "Gating `GraphicsEngine.render()` stops all GL traffic during loss."**
306
- Not strictly: ECS-tick-driven work (Forward+ cluster uploads, trail/geometry updates) can still touch the
307
- renderer, and only three's `render()` is guarded internally. Analysis said this is benign because GL calls
308
- on a lost context are no-ops — **[measured]** `gl.getError()` returns `CONTEXT_LOST_WEBGL` (0x9242) and
309
- five driven frames threw nothing. There *was* a latent trap here: a `setupRenderTarget` during loss writes
310
- `__webglFramebuffer = null` into three's properties map, and `setRenderTarget` tests `=== undefined`, so
311
- that target would never be re-set-up again. It is unreachable today because `initGLContext()` replaces the
312
- map wholesale, and now doubly unreachable because the gate stops us drawing at all. Recorded so nobody
313
- "optimises" the gate away.
314
-
315
- **#5 "Readbacks during loss are harmless."**
316
- True for the shipped set (no production `readRenderTargetPixels`), false in general — §4.4's
317
- `bitmap2sampler_gl` turns a lost context into silently wrong *CPU* data. The general rule adopted: any
318
- GPU→CPU readback must be generation-checked, because "returns zeroes" is indistinguishable from "returns a
319
- valid black frame". This is also why there is no `try`/`catch` anywhere in the recovery path: a lost
320
- context does not throw, so exception handling would buy nothing.
321
-
322
- **#6 "The renderer pool is a likely cause of loss."**
323
- Corrected by the code owner: most of the engine works with a supplied renderer rather than reaching into
324
- the pool, and `MeshPreview` — the one per-instance consumer — is an editor feature. The context-cap theory
325
- was reasoned from documented Chrome behaviour, not observed, and it is not where the risk lives. Telemetry
326
- (§5.2) ships with detection so the real loss causes can be measured instead of guessed.
327
-
328
- **#7 "Recovery cost is dominated by shader recompilation."**
329
- **Outcome: consistent with measurement but not isolated.** First-frame cost scales with program count
330
- (5 programs → ~37 ms, 14 → ~214 ms), which fits, but texture upload was not separately instrumented, so
331
- this remains an inference. It matters only if pre-warming is ever built, which the numbers do not
332
- currently justify.
333
-
334
- **#8 "Re-running startup would be a simpler design."**
335
- Tempting and wrong: `FrameBuffer.initialize()` and plugin `startup()` allocate per call, so per-loss leaks
336
- would accumulate and a loss loop would exhaust GPU memory — turning a recoverable event into a hard crash.
337
- **[measured]** with the narrow sequence: three consecutive cycles held frame buffers at 2, programs at 5,
338
- textures at 6, and the environment target was replaced (id 31 → 33 → 35) rather than accumulated.
339
-
340
- **#9 "Test strategy is weak by nature."**
341
- Partly resolved. Jest cannot exercise WebGL, so the 12 unit tests cover the state machine only — using a
342
- real `HTMLCanvasElement` and real event dispatch, so nothing is mocked. Pixel-level behaviour is covered by
343
- the harness. The residual gap is honest and stated in §10.4: `WEBGL_lose_context` is a *cooperative* loss
344
- and does not reproduce a real GPU-process crash (all contexts dying at once, driver reset, restore refusal).
345
-
346
- **#10 "The `computeImageBitmapEquality` context produces silent garbage after a loss."**
347
- Still untested — it needs its own harness pass, deferred with the rest of Phase 4. If the browser instead
348
- fails loudly there, the item drops in priority.
349
-
350
- **#11 New: the loss budget was wrong when first written.**
351
- The original policy failed permanently after 3 losses *per session*, which would punish a long session
352
- that hit four unrelated hiccups hours apart. Caught while reviewing the 3-cycle measurement (which ended
353
- one loss short of tripping it) and replaced with a 3-per-60-seconds window. Worth recording as an argument
354
- for measuring your own defaults: the bug was invisible in code review and obvious in a graph.
355
-
356
- ---
357
-
358
- ## 9. Non-goals
359
-
360
- * Recovering the *contents* of anything genuinely transient (one frame of temporal history, in-flight
361
- bakes) — re-derive, do not restore.
362
- * WebGPU migration, or making the engine context-agnostic.
363
- * Surviving a browser tab crash or an OOM abort.
364
- * Deleting the unused GL-direct subsystems in §4.3 — they are public library surface; they get fixed, not
365
- removed.
366
-
367
- ---
368
-
369
- ## 10. Verification
370
-
371
- ### 10.1 Unit tests
372
-
373
- `WebGLContextMonitor.spec.js`, 12 tests, real canvas and real event dispatch: initial state, loss →
374
- `preventDefault` + `Lost`, restore → `Live` + generation increment, restore-timeout escalation, deadline
375
- cancellation, burst budget exhaustion, budget decay over an hour of spaced losses, re-attach semantics,
376
- terminal-state behaviour on late restore and on further losses, detach.
377
-
378
- ```bash
379
- npx jest -c jest.conf.json app/src/mir-engine/meep/src/engine/graphics/context/WebGLContextMonitor.spec.js
380
- ```
381
-
382
- ### 10.2 Browser harness
383
-
384
- `src/engine/graphics/context/testWebGLContextLoss.js`, run by pointing the webpack entry at it (the entry
385
- line is already present, commented, in `webpack.config.js`). Static scene — terrain, sun with shadows, and
386
- a mirror-metal sphere whose shading is almost entirely IBL, which is what makes the environment map visible
387
- in a pixel A/B. Two consecutive frames are bit-identical, so the noise floor is zero and any difference is
388
- real. Because the harness is expected to run in a hidden tab it drives frames by hand
389
- (`engine.ticker.onTick.send1(dt)` + `engine.render()`), reads the framebuffer in the same task as the draw,
390
- and can print a coarse ASCII luminance map — which is how the environment defect was localised without
391
- screenshots.
392
-
393
- | API | Scenario | Runs in a hidden tab |
394
- | --- | --- | --- |
395
- | `__context_loss_test.synthetic()` | loss/restore lifecycle via synthetic canvas events; exercises the gate, the fix-up sequence, the environment re-bake and three's own restore path | yes |
396
- | `__context_loss_test.fresh()` | same scene through a brand new renderer/context; measures what has to come back from CPU-side data | yes |
397
- | `__context_loss_test.run()` | real `WEBGL_lose_context` loss and restore | needs a visible tab |
398
- | `__context_loss_test.repeat(n)` | n real cycles, watching for resource growth | needs a visible tab |
399
- | `image()`, `capture()`, `state()`, `frame(n)` | inspection helpers | yes |
400
-
401
- ### 10.3 Results
402
-
403
- | Check | Result |
404
- | --- | --- |
405
- | Frames drawn while lost | 0, no exceptions, `gl.getError()` = `CONTEXT_LOST_WEBGL` |
406
- | Synthetic restore, harness scene | bit-identical to baseline, including IBL |
407
- | Three consecutive cycles | cycles 2 and 3 bit-identical; frame buffers 2, programs 5, textures 6 unchanged; environment target replaced, not accumulated |
408
- | Clear colour after restore | 0xBBBBFF preserved (counterfactual on a bare renderer: resets to black) |
409
- | Fresh context | identical draw calls / triangles; only delta is the environment map, reproduced exactly by `scene.environment = null` |
410
- | Real loss, no restore possible (hidden tab) | escalated to `Failed` after the 5 s deadline, overlay shown, no exceptions. Superseded: the deadline now only runs while the page is visible (see the note below the table), so this scenario stays `Lost` until the page is revealed, then fails 5 s later |
411
- | Production game bundle, synthetic cycle | frame counter frozen while lost; generation 0 → 1; environment re-baked (texture id 24 → 77); clear colour preserved; no GL errors; first frame 214 ms |
412
-
413
- Follow-up (post-review): the restore deadline is now suspended while the page is hidden. Chrome does not
414
- restore a context in a hidden tab, so counting hidden time turned any loss in a backgrounded tab — the
415
- place where the browser prefers to evict contexts — into a terminal `Failed`, shown to the user on their
416
- return even though the context was recoverable. `WebGLContextMonitor` now arms the watchdog only while
417
- the page is visible; each return to visibility restarts the full `restore_timeout`. Covered by three
418
- visibility tests in `WebGLContextMonitor.spec.js`.
419
-
420
- ### 10.4 What remains unverified, and why
421
-
422
- The Browser pane available here does not composite, and Chrome only restores a lost context while the page
423
- is visible, so `webglcontextrestored` never arrives — a real loss escalates to `Failed` instead of
424
- recovering. Consequently these need one run in a visible tab:
425
-
426
- 1. **A real browser-driven restore** (`__context_loss_test.run()` and `.repeat(3)`): does the browser hand
427
- the context back, and do stale GL handles from the dead context misbehave? Everything downstream of the
428
- restore event is already proven by the synthetic path; what is untested is the event itself.
429
- 2. **The prolonged-outage ticker pause.** In a hidden tab the ticker loop never bootstraps
430
- (`requestAnimationFrame` never fires, so `is_active` is false) and the guard correctly declines to pause
431
- — which exercised the guard but not the pause.
432
- 3. **The game's own scenes.** The game boots in a hidden tab but never renders, so per-frame GPU state in
433
- FoW, decals, particles, Forward+ and water is covered by inspection only.
434
-
435
- To run them: point the webpack entry at the harness, open the page with the pane visible, then
436
-
437
- ```bash
438
- npx jest -c jest.conf.json app/src/mir-engine/meep/src/engine/graphics/context/WebGLContextMonitor.spec.js
439
- ```
440
-
441
- and in the page console: `await __context_loss_test.run()`, then `await __context_loss_test.repeat(3)`.
442
- Expect `restored: true`, `settled_vs_baseline` near zero, and no growth in `textures` / `geometries` /
443
- `programs` across cycles.
444
-
445
- ---
446
-
447
- ## 11. Remaining phases
448
-
449
- **Phase 4 — secondary contexts and async generation checks.** `computeImageBitmapEquality` handle reset
450
- (§4.4, the silent-corruption one, worth doing on its own), `MinimapWorldGL` re-render on restore, and
451
- generation checks on the long-running bakes (§4.5). `MeshPreview` is editor-only and can trail. Estimate
452
- 1–2 days.
453
-
454
- **Phase 5 (conditional) — renderer rebuild fallback.** If telemetry shows browsers refusing to restore in
455
- practice, replace the terminal `Failed` state with a rebuild: dispose the renderer, create a new canvas,
456
- re-attach `viewport.el` / `graphics.domElement` / styles / size, and re-run frame-buffer init *with*
457
- disposal of the old targets. The monitor already supports it — `attach()` resets the loss budget and returns
458
- to `Live` while keeping the generation counter monotonic. Only worth building on evidence.
459
-
460
- **Phase 6 (closed) — library tier.** Not done, and will not be: every subsystem in §4.3 was deleted
461
- along with the WebGL renderer. The only one with a successor is virtual texturing, and residency
462
- invalidation does not carry over to it — Shade does not restore a lost device, so there is no frame in
463
- which a stale residency map could be read (§4.3).
@@ -1,48 +0,0 @@
1
- Perfect panning implementation, based on [this](https://prideout.net/blog/perfect_panning/). Below is a copy of the original article
2
-
3
- ---
4
-
5
- Perfect Panning
6
- ===============
7
-
8
- This is a quick note about _through the lens_ camera control. The user drags the mouse around in their viewport, which causes the camera to slide around within the plane that is parallel to the near and far clipping planes.
9
-
10
- This is super easy to implement, but it’s somewhat tricky if you want the user to feel like they’re grabbing something in the scene – especially if you consider the distortion caused by perspective projection.
11
-
12
- For example, the following screenshots show a terrain that has been dragged towards the southwest. Since the mountain top appears to move faster than the coastline, how do you make the 3D scene “stick” to the mouse cursor?
13
-
14
- ![](pan_a.png)
15
-
16
- ![](pan_b.png)
17
-
18
- To solve this problem the right way, it helps to leverage a raycaster, even if your actual rendering is done with OpenGL. I also find it helpful to pretend that the mouse cursor lives within the near or far planes of the viewing frustum.
19
-
20
- So, if you cast a ray from the camera’s position to the cursor’s position, you’ll hit the point in the scene that needs to be stable during the pan. In the following diagram, we’ve panned the camera from **A** to **B** such that point **C** has remained stable. The cursor at the start of the pan was projected onto the far plane at **E**, and the cursor’s current position corresponds to point **D**.
21
-
22
- ![](Perfect_Panning.png)
23
-
24
- We wish to solve for **B**, given that **A**, **C**, and **E** are known quantities, assuming that your game engine can perform basic raycasts.
25
-
26
- What’s less obvious is that **D** is also a known quantity (sort of). At any point in time during the drag, you can project the current mouse position onto the current far plane and get **D**. If you stash **A**, **C**, **E** at the start of the pan and never forget them, then you won’t accumulate error while the user pans.
27
-
28
- The next thing to notice is that **ΔCAB** is similar to **ΔCED**. Applying the law of similar triangles yields:
29
-
30
- |A-B| / |A-C| == |E-D| / |E-C|
31
-
32
- This allows you to solve for **|A-B|**:
33
-
34
- |A-B| = |A-C| * |E-D| / |E-C|
35
-
36
- Thus, we have a “perfect panning” algorithm:
37
-
38
- After every mouse-move event, translate the mouse-down camera position **A** in the direction of **(E-D)** by the distance **|A-B|**, as computed above.
39
-
40
- It’s even easier to implement perfect zooming, when you wish to zoom in at the mouse cursor while keeping the scene’s geometry stable at the point. Simply move the camera along the ray that goes from the camera’s position to the cursor’s position. It might also be desirable to adjust the speed of the zoom according to the distance between the camera and the nearest point in the scene that the ray hits. Here’s a diagram just for completeness:
41
-
42
- ![](Zooming.png)
43
-
44
- * * *
45
-
46
- For complete C code implementing the techniques described in this post, look for “map mode” in [par\_camera\_control.h](https://github.com/prideout/par/blob/master/par_camera_control.h), one of my single-file libraries on GitHub.
47
-
48
- [![](https://prideout.net/assets/PublishedLogo.svg)](https://prideout.net)