@woosh/meep-engine 3.60.4 → 3.60.6

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 (419) hide show
  1. package/CHANGELOG.md +2621 -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/package.json +6 -2
  9. package/src/engine/EngineHarness.d.ts +3 -9
  10. package/src/engine/EngineHarness.d.ts.map +1 -1
  11. package/src/engine/EngineHarness.js +6 -8
  12. package/src/engine/graphics/camera/makeOrbitalCameraController.d.ts +9 -6
  13. package/src/engine/graphics/camera/makeOrbitalCameraController.d.ts.map +1 -1
  14. package/src/engine/graphics/camera/makeOrbitalCameraController.js +44 -71
  15. package/src/engine/graphics/camera/orbital/MomentumAxis.d.ts +64 -0
  16. package/src/engine/graphics/camera/orbital/MomentumAxis.d.ts.map +1 -0
  17. package/src/engine/graphics/camera/orbital/MomentumAxis.js +187 -0
  18. package/src/engine/graphics/camera/orbital/OrbitalCameraRig.d.ts +86 -0
  19. package/src/engine/graphics/camera/orbital/OrbitalCameraRig.d.ts.map +1 -0
  20. package/src/engine/graphics/camera/orbital/OrbitalCameraRig.js +319 -0
  21. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraController.d.ts +34 -10
  22. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraController.d.ts.map +1 -1
  23. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraController.js +116 -30
  24. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.d.ts +1 -7
  25. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.d.ts.map +1 -1
  26. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.js +1 -37
  27. package/src/engine/graphics/ecs/water/Water.d.ts +8 -0
  28. package/src/engine/graphics/ecs/water/Water.d.ts.map +1 -1
  29. package/src/engine/graphics/ecs/water/Water.js +8 -0
  30. package/src/engine/graphics3/WaterSystem.d.ts.map +1 -1
  31. package/src/engine/graphics3/WaterSystem.js +731 -734
  32. package/src/engine/graphics3/decal/DecalTileShader.d.ts +61 -0
  33. package/src/engine/graphics3/decal/DecalTileShader.d.ts.map +1 -0
  34. package/src/engine/graphics3/decal/DecalTileShader.js +138 -0
  35. package/src/engine/graphics3/decal/GPUDecalRenderer.d.ts +10 -4
  36. package/src/engine/graphics3/decal/GPUDecalRenderer.d.ts.map +1 -1
  37. package/src/engine/graphics3/decal/GPUDecalRenderer.js +149 -44
  38. package/src/engine/graphics3/decal/chunk_decal_tile_vertex.d.ts +25 -0
  39. package/src/engine/graphics3/decal/chunk_decal_tile_vertex.d.ts.map +1 -0
  40. package/src/engine/graphics3/decal/chunk_decal_tile_vertex.js +55 -0
  41. package/src/engine/graphics3/decal/graph_gather_decal_tiles.d.ts +22 -0
  42. package/src/engine/graphics3/decal/graph_gather_decal_tiles.d.ts.map +1 -0
  43. package/src/engine/graphics3/decal/graph_gather_decal_tiles.js +70 -0
  44. package/src/engine/graphics3/decal/shader_decal_composite.d.ts +7 -5
  45. package/src/engine/graphics3/decal/shader_decal_composite.d.ts.map +1 -1
  46. package/src/engine/graphics3/decal/shader_decal_composite.js +48 -44
  47. package/src/engine/graphics3/decal/shader_decal_tile_copy.d.ts +12 -0
  48. package/src/engine/graphics3/decal/shader_decal_tile_copy.d.ts.map +1 -0
  49. package/src/engine/graphics3/decal/shader_decal_tile_copy.js +78 -0
  50. package/src/engine/graphics3/decal/shader_gather_decal_tiles.d.ts +11 -0
  51. package/src/engine/graphics3/decal/shader_gather_decal_tiles.d.ts.map +1 -0
  52. package/src/engine/graphics3/decal/shader_gather_decal_tiles.js +80 -0
  53. package/src/engine/input/devices/mouse/MouseEventButtons.d.ts +13 -0
  54. package/src/engine/input/devices/mouse/MouseEventButtons.d.ts.map +1 -0
  55. package/src/engine/input/devices/mouse/MouseEventButtons.js +23 -0
  56. package/src/engine/input/ecs/controllers/KeyboardCameraController.d.ts +4 -0
  57. package/src/engine/input/ecs/controllers/KeyboardCameraController.d.ts.map +1 -1
  58. package/src/engine/input/ecs/controllers/KeyboardCameraController.js +9 -45
  59. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  60. package/src/shade/playground/water_refraction/README.md +5 -6
  61. package/src/shade/playground/water_refraction/index.html +1 -1
  62. package/src/shade/renderer/Renderer.d.ts +11 -0
  63. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  64. package/src/shade/renderer/Renderer.js +50 -6
  65. package/src/shade/renderer/camera/orbital/OrbitalCameraController.d.ts +40 -80
  66. package/src/shade/renderer/camera/orbital/OrbitalCameraController.d.ts.map +1 -1
  67. package/src/shade/renderer/camera/orbital/OrbitalCameraController.js +197 -147
  68. package/src/shade/renderer/fluid/GPUFluidCascade.d.ts +3 -3
  69. package/src/shade/renderer/fluid/GPUFluidCascadeStack.d.ts +1 -1
  70. package/src/shade/renderer/fluid/forcing/GPUFluidForcing.d.ts +6 -6
  71. package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.d.ts +1 -1
  72. package/src/shade/renderer/fluid/query/GPUFluidQueries.d.ts +1 -1
  73. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts +28 -45
  74. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts.map +1 -1
  75. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.js +111 -119
  76. package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.d.ts +22 -3
  77. package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.d.ts.map +1 -1
  78. package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.js +84 -3
  79. package/src/shade/renderer/geometry/virtual/proxy/vgeo_proxy_triangle_limit.d.ts +19 -0
  80. package/src/shade/renderer/geometry/virtual/proxy/vgeo_proxy_triangle_limit.d.ts.map +1 -0
  81. package/src/shade/renderer/geometry/virtual/proxy/vgeo_proxy_triangle_limit.js +25 -0
  82. package/src/shade/renderer/geometry/virtual/proxy/vgeo_to_proxy_mesh.d.ts +31 -0
  83. package/src/shade/renderer/geometry/virtual/proxy/vgeo_to_proxy_mesh.d.ts.map +1 -0
  84. package/src/shade/renderer/geometry/virtual/proxy/vgeo_to_proxy_mesh.js +343 -0
  85. package/src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.d.ts +15 -0
  86. package/src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.d.ts.map +1 -1
  87. package/src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.js +38 -0
  88. package/src/shade/renderer/geometry/virtual/runtime/vgeo_meshlet_metadata_write.d.ts +17 -0
  89. package/src/shade/renderer/geometry/virtual/runtime/vgeo_meshlet_metadata_write.d.ts.map +1 -0
  90. package/src/shade/renderer/geometry/virtual/runtime/vgeo_meshlet_metadata_write.js +29 -0
  91. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_meshlet_batch.d.ts.map +1 -1
  92. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_meshlet_batch.js +7 -13
  93. package/src/shade/renderer/geometry/virtual/sdf/VGeoSDFProxies.d.ts +28 -59
  94. package/src/shade/renderer/geometry/virtual/sdf/VGeoSDFProxies.d.ts.map +1 -1
  95. package/src/shade/renderer/geometry/virtual/sdf/VGeoSDFProxies.js +84 -789
  96. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts.map +1 -1
  97. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.js +1 -8
  98. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.d.ts +7 -6
  99. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.d.ts.map +1 -1
  100. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.js +12 -11
  101. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_instance.d.ts +2 -2
  102. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_instance.js +2 -2
  103. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts +1 -4
  104. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts.map +1 -1
  105. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.js +1 -10
  106. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_surface.d.ts +5 -15
  107. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_surface.d.ts.map +1 -1
  108. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_surface.js +6 -34
  109. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.d.ts.map +1 -1
  110. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.js +1 -7
  111. package/src/shade/renderer/hiz/HZBFootprint.d.ts +14 -0
  112. package/src/shade/renderer/hiz/HZBFootprint.d.ts.map +1 -0
  113. package/src/shade/renderer/hiz/HZBFootprint.js +16 -0
  114. package/src/shade/renderer/hiz/HZB_FOOTPRINT_X.d.ts +10 -0
  115. package/src/shade/renderer/hiz/HZB_FOOTPRINT_X.d.ts.map +1 -0
  116. package/src/shade/renderer/hiz/HZB_FOOTPRINT_X.js +11 -0
  117. package/src/shade/renderer/hiz/HZB_FOOTPRINT_Y.d.ts +10 -0
  118. package/src/shade/renderer/hiz/HZB_FOOTPRINT_Y.d.ts.map +1 -0
  119. package/src/shade/renderer/hiz/HZB_FOOTPRINT_Y.js +11 -0
  120. package/src/shade/renderer/hiz/HierarchicalZBuffer.d.ts +0 -7
  121. package/src/shade/renderer/hiz/HierarchicalZBuffer.d.ts.map +1 -1
  122. package/src/shade/renderer/hiz/HierarchicalZBuffer.js +405 -350
  123. package/src/shade/renderer/hiz/chunk_hzb_footprint_x.d.ts +12 -0
  124. package/src/shade/renderer/hiz/chunk_hzb_footprint_x.d.ts.map +1 -0
  125. package/src/shade/renderer/hiz/chunk_hzb_footprint_x.js +27 -0
  126. package/src/shade/renderer/hiz/chunk_hzb_footprint_y.d.ts +12 -0
  127. package/src/shade/renderer/hiz/chunk_hzb_footprint_y.d.ts.map +1 -0
  128. package/src/shade/renderer/hiz/chunk_hzb_footprint_y.js +27 -0
  129. package/src/shade/renderer/hiz/hzb_footprint_texels.d.ts +14 -0
  130. package/src/shade/renderer/hiz/hzb_footprint_texels.d.ts.map +1 -0
  131. package/src/shade/renderer/hiz/hzb_footprint_texels.js +34 -0
  132. package/src/shade/renderer/hiz/shader_hzb_reduce_any.d.ts +0 -5
  133. package/src/shade/renderer/hiz/shader_hzb_reduce_any.d.ts.map +1 -1
  134. package/src/shade/renderer/hiz/shader_hzb_reduce_any.js +37 -57
  135. package/src/shade/renderer/hiz/shader_hzb_reduce_mip0.d.ts +11 -0
  136. package/src/shade/renderer/hiz/shader_hzb_reduce_mip0.d.ts.map +1 -0
  137. package/src/shade/renderer/hiz/{shader_hzb_reduce_mip0_clip.js → shader_hzb_reduce_mip0.js} +120 -111
  138. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  139. package/src/shade/renderer/material/GPUMaterialManager.d.ts +11 -1
  140. package/src/shade/renderer/material/GPUMaterialManager.d.ts.map +1 -1
  141. package/src/shade/renderer/material/GPUMaterialManager.js +16 -8
  142. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.d.ts +12 -12
  143. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.d.ts.map +1 -1
  144. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.js +17 -118
  145. package/src/shade/renderer/postprocess/gtao/GTAO.d.ts +7 -3
  146. package/src/shade/renderer/postprocess/gtao/GTAO.d.ts.map +1 -1
  147. package/src/shade/renderer/postprocess/gtao/GTAO.js +26 -13
  148. package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.d.ts +14 -0
  149. package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.d.ts.map +1 -1
  150. package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.js +196 -68
  151. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao.d.ts.map +1 -1
  152. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao.js +42 -28
  153. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao_with_irradiance.d.ts.map +1 -1
  154. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao_with_irradiance.js +429 -414
  155. package/src/shade/renderer/postprocess/gtao/shader_gtao_spatial_denoise.d.ts +16 -0
  156. package/src/shade/renderer/postprocess/gtao/shader_gtao_spatial_denoise.d.ts.map +1 -0
  157. package/src/shade/renderer/postprocess/gtao/shader_gtao_spatial_denoise.js +156 -0
  158. package/src/shade/renderer/scene/GPUSceneContext.d.ts +2 -2
  159. package/src/shade/renderer/scene/GPUSceneContext.js +5 -5
  160. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.d.ts.map +1 -1
  161. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.js +7 -2
  162. package/src/shade/renderer/water/GPUWaterRenderer.d.ts +0 -6
  163. package/src/shade/renderer/water/GPUWaterRenderer.d.ts.map +1 -1
  164. package/src/shade/renderer/water/GPUWaterRenderer.js +12 -17
  165. package/src/shade/renderer/water/medium/graph_water_meshlets.d.ts +35 -0
  166. package/src/shade/renderer/water/medium/graph_water_meshlets.d.ts.map +1 -0
  167. package/src/shade/renderer/water/medium/graph_water_meshlets.js +89 -0
  168. package/src/shade/renderer/water/query/GPUWaterQueries.d.ts +1 -1
  169. package/src/shade/renderer/water/shader_water.d.ts.map +1 -1
  170. package/src/shade/renderer/water/shader_water.js +22 -13
  171. package/src/shade/renderer/water/shader_water_avboit.d.ts.map +1 -1
  172. package/src/shade/renderer/water/shader_water_avboit.js +7 -7
  173. package/src/shade/renderer/water/surface/graph_water_tessellation.d.ts +1 -1
  174. package/src/shade/renderer/water/surface/graph_water_tessellation.js +1 -1
  175. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +9 -1
  176. package/editor/REWORK_PLAN_2026_08.md +0 -692
  177. package/src/CODEC_LAYOUT_VERIFICATION.md +0 -419
  178. package/src/CORRECTNESS_HUNT_2026_07_24.md +0 -142
  179. package/src/DUPLICATION_AUDIT_2026_08_07/00_core_reuse_surface.md +0 -738
  180. package/src/DUPLICATION_AUDIT_2026_08_07/A_core_math_geom.md +0 -79
  181. package/src/DUPLICATION_AUDIT_2026_08_07/B_core_data.md +0 -93
  182. package/src/DUPLICATION_AUDIT_2026_08_07/C_gfx_render.md +0 -80
  183. package/src/DUPLICATION_AUDIT_2026_08_07/D_gfx_features.md +0 -164
  184. package/src/DUPLICATION_AUDIT_2026_08_07/E_physics.md +0 -69
  185. package/src/DUPLICATION_AUDIT_2026_08_07/F_sound.md +0 -110
  186. package/src/DUPLICATION_AUDIT_2026_08_07/G_net_save.md +0 -129
  187. package/src/DUPLICATION_AUDIT_2026_08_07/H_engine_misc.md +0 -72
  188. package/src/DUPLICATION_AUDIT_2026_08_07/I_generation_view.md +0 -74
  189. package/src/DUPLICATION_AUDIT_2026_08_07/K_crosscutting.md +0 -169
  190. package/src/DUPLICATION_AUDIT_2026_08_07.md +0 -254
  191. package/src/DUPLICATION_AUDIT_REMEDIATION.md +0 -250
  192. package/src/DUPLICATION_REVIEW_2026_10_24.md +0 -1072
  193. package/src/REVIEW_2026_08_06/adv-core.md +0 -511
  194. package/src/REVIEW_2026_08_06/adv-gfx.md +0 -480
  195. package/src/REVIEW_2026_08_06/adv-view.md +0 -446
  196. package/src/REVIEW_2026_08_06/api-core.md +0 -296
  197. package/src/REVIEW_2026_08_06/api-engine.md +0 -195
  198. package/src/REVIEW_2026_08_06/bvh-phys-sound-net.md +0 -507
  199. package/src/REVIEW_2026_08_06/core-binary.md +0 -348
  200. package/src/REVIEW_2026_08_06/core-collection.md +0 -376
  201. package/src/REVIEW_2026_08_06/core-math.md +0 -221
  202. package/src/REVIEW_2026_08_06/core-process.md +0 -266
  203. package/src/REVIEW_2026_08_06/core-science.md +0 -223
  204. package/src/REVIEW_2026_08_06/engine-ai-nav.md +0 -279
  205. package/src/REVIEW_2026_08_06/engine-animation.md +0 -167
  206. package/src/REVIEW_2026_08_06/engine-asset.md +0 -166
  207. package/src/REVIEW_2026_08_06/engine-ecs.md +0 -920
  208. package/src/REVIEW_2026_08_06/engine-input.md +0 -197
  209. package/src/REVIEW_2026_08_06/engine-misc.md +0 -248
  210. package/src/REVIEW_2026_08_06/engine-terrain.md +0 -52
  211. package/src/REVIEW_2026_08_06/generation.md +0 -176
  212. package/src/REVIEW_2026_08_06/geom-2d.md +0 -434
  213. package/src/REVIEW_2026_08_06/geom-3d.md +0 -117
  214. package/src/REVIEW_2026_08_06/gfx-gi.md +0 -143
  215. package/src/REVIEW_2026_08_06/gfx-render.md +0 -740
  216. package/src/REVIEW_2026_08_06/gfx-texture.md +0 -690
  217. package/src/REVIEW_2026_08_06/prior-criticals.md +0 -49
  218. package/src/REVIEW_2026_08_06/prior-highs.md +0 -138
  219. package/src/REVIEW_2026_08_06/test-gaps.md +0 -364
  220. package/src/REVIEW_2026_08_06/view.md +0 -667
  221. package/src/REVIEW_2026_08_06.md +0 -610
  222. package/src/core/binary/lz4/LZ4_HIGH_COMPRESSION_PLAN_2026_09_14.md +0 -542
  223. package/src/core/bvh2/bvh3/NOTES.md +0 -2
  224. package/src/core/bvh8/NOTES.md +0 -63
  225. package/src/core/cache/wtinylfu/benchmark/CacheWTinylfu.bench.md +0 -243
  226. package/src/core/color/COLOR_FIX_PLAN_2026_08_28.md +0 -417
  227. package/src/core/color/COLOR_REVIEW_2026_08_28.md +0 -779
  228. package/src/core/geom/2d/polygon/TRIANGULATION_DESIGN.md +0 -433
  229. package/src/core/geom/3d/atlas/ATLAS_PORT_PLAN.md +0 -486
  230. package/src/core/geom/3d/atlas/BFF_PLAN.md +0 -174
  231. package/src/core/geom/3d/atlas/REVIEW_02.md +0 -392
  232. package/src/core/geom/3d/gjk/GJK_REVIEW_NOTES.md +0 -146
  233. package/src/core/geom/3d/gjk/NOTES.md +0 -8
  234. package/src/core/geom/3d/topology/TOPO_MESH_RETIREMENT_PLAN.md +0 -135
  235. package/src/core/geom/GEOMETRY_REVIEW_002_API_ISSUES.md +0 -381
  236. package/src/core/geom/GEOMETRY_REVIEW_002_NAMING.md +0 -684
  237. package/src/core/geom/MANIFOLD_COMPARISON_2026_08_01.md +0 -554
  238. package/src/core/model/reactive/evaluation/PREDICATE_APPLICABILITY_PROPOSAL.md +0 -446
  239. package/src/engine/REVIEW_2026_07_03.md +0 -211
  240. package/src/engine/asset/loaders/image/IMAGE_CODEC_REVIEW_2026_08_28.md +0 -815
  241. package/src/engine/control/first-person/DESIGN.md +0 -658
  242. package/src/engine/control/first-person/DESIGN_COLLISION.md +0 -382
  243. package/src/engine/control/first-person/DESIGN_EXTENSIONS.md +0 -563
  244. package/src/engine/control/first-person/TODO.md +0 -160
  245. package/src/engine/ecs/ASYNC_SYSTEMS_PROPOSAL.md +0 -531
  246. package/src/engine/ecs/HIERARCHY_REVIEW.md +0 -717
  247. package/src/engine/ecs/async/WORKER_SYSTEM_PLAN.md +0 -262
  248. package/src/engine/ecs/ik/PLAN.md +0 -179
  249. package/src/engine/ecs/storage/binary/SERIALIZATION_COVERAGE.md +0 -272
  250. package/src/engine/ecs/storage/binary/object-v2/DESIGN.md +0 -199
  251. package/src/engine/ecs/transform/TRANSFORM64_MIGRATION_PLAN_2026_09_04.md +0 -521
  252. package/src/engine/graphics/CONTEXT_LOSS_RECOVERY_PLAN.md +0 -463
  253. package/src/engine/graphics/ecs/camera/pp/NOTES.md +0 -48
  254. package/src/engine/graphics/render/frame_graph/CORRECTNESS_FIXES_2026_09_04.md +0 -659
  255. package/src/engine/graphics/render/frame_graph/FRAME_GRAPH_RECOMMENDATIONS.md +0 -235
  256. package/src/engine/graphics/sh3/path_tracer/REVIEW_001_ACTION_PLAN.md +0 -490
  257. package/src/engine/graphics/texture/sampler/compare/FLIP_IMPLEMENTATION_PLAN.md +0 -466
  258. package/src/engine/input/GAMEPAD_API_PROPOSAL.md +0 -717
  259. package/src/engine/input/ecs/ism/ISM_DESIGN.md +0 -1523
  260. package/src/engine/input/ecs/ism/ISM_IMPLEMENTATION_PLAN.md +0 -627
  261. package/src/engine/navigation/mesh/OVERLAPPING_SURFACES_2026_08_25.md +0 -661
  262. package/src/engine/navigation/mesh/PATHFINDING_PLAN.md +0 -229
  263. package/src/engine/network/CONGESTION_CONTROL.md +0 -87
  264. package/src/engine/network/MESSAGE_TRANSPORT.md +0 -364
  265. package/src/engine/network/SMOOTHNESS_DESIGN.md +0 -400
  266. package/src/engine/physics/cloth/MEASUREMENTS.md +0 -5304
  267. package/src/engine/physics/cloth/PLAN.md +0 -3056
  268. package/src/engine/physics/fluid/GPU_FLUID_CASCADES_PROPOSAL_2026_10_16.md +0 -1382
  269. package/src/engine/physics/fluid/REVIEW_02_PLAN.md +0 -243
  270. package/src/engine/physics/fluid/solver/NOTES.md +0 -46
  271. package/src/engine/sound/SOUND_EMITTER_RETIREMENT_PLAN.md +0 -536
  272. package/src/engine/sound/simulation/IMPLEMENTATION_PLAN.md +0 -432
  273. package/src/engine/sound/simulation/PROBE_PLACEMENT.md +0 -250
  274. package/src/engine/sound/simulation/PROBE_TRANSFER_RESEARCH.md +0 -322
  275. package/src/engine/sound/simulation/REFLECTION_IR_PLAN.md +0 -261
  276. package/src/engine/sound/simulation/VISIBILITY_GRAPH_PLAN.md +0 -121
  277. package/src/engine/sound/sopra/IMPLEMENTATION_PLAN.md +0 -999
  278. package/src/format/image/avif/DECISIONS.md +0 -545
  279. package/src/format/image/jpeg/NOTES.md +0 -3
  280. package/src/format/scene/gltf/MESHOPT_COMPRESSION_PLAN.md +0 -814
  281. package/src/generation/COORDINATES.md +0 -54
  282. package/src/generation/REVIEW_01_ACTION_PLAN.md +0 -628
  283. package/src/generation/foliage/ANNUAL_SHOOTS_BRIEF_2026_10_25.md +0 -220
  284. package/src/generation/foliage/CROWN_FILLING_BRIEF_2026_10_26.md +0 -172
  285. package/src/generation/foliage/CROWN_FULLNESS_BRIEF_2026_10_26.md +0 -86
  286. package/src/generation/foliage/FOLIAGE_DESIGN.md +0 -547
  287. package/src/generation/foliage/FOLIAGE_PLAN.md +0 -198
  288. package/src/generation/foliage/LEAF_ARCHITECTURE_BRIEF_2026_10_26.md +0 -158
  289. package/src/generation/foliage/LOD_REWORK_BRIEF_2026_10_27.md +0 -521
  290. package/src/generation/foliage/REAL_TIME_TREES_BRIEF_2026_10_27.md +0 -86
  291. package/src/generation/foliage/SELF_ORGANIZING_FRAMEWORK_BRIEF_2026_10_26.md +0 -347
  292. package/src/generation/foliage/SHOOT_SYSTEMS_ALL_SPECIES_BRIEF_2026_10_26.md +0 -248
  293. package/src/generation/foliage/SPEEDTREE_COMPARISON_2026_10_24.md +0 -694
  294. package/src/generation/foliage/TWO_FRONT_ENDS_BRIEF_2026_10_28.md +0 -552
  295. package/src/shade/RENDERER_CONTRACT.md +0 -697
  296. package/src/shade/SHADER_F16_PROPOSAL_2026_10_24.md +0 -263
  297. package/src/shade/device/IMMEDIATE_DATA_PLAN_2026_08_28.md +0 -569
  298. package/src/shade/device/PASS_ENCODER_PROPOSAL_2026_08_31.md +0 -755
  299. package/src/shade/device/mock/EXTENSION_PROPOSAL_2026_08_22.md +0 -458
  300. package/src/shade/device/mock/IMPLEMENTATION_PLAN.md +0 -255
  301. package/src/shade/device/mock/REVIEW_2026_08_22.md +0 -527
  302. package/src/shade/device/timing/GPU_PROFILER_PROPOSAL_2026_08_28.md +0 -894
  303. package/src/shade/device/timing/profile/SGPT_FORMAT.md +0 -345
  304. package/src/shade/renderer/NOTES.md +0 -78
  305. package/src/shade/renderer/PLAN.md +0 -8
  306. package/src/shade/renderer/animation/ADDITIVE_BLENDING_PLAN.md +0 -145
  307. package/src/shade/renderer/animation/SKINNING_FRAME_PLAN.md +0 -357
  308. package/src/shade/renderer/atmosphere/NOTES.md +0 -6
  309. package/src/shade/renderer/camera/orbital/MomentumAxis.d.ts +0 -76
  310. package/src/shade/renderer/camera/orbital/MomentumAxis.d.ts.map +0 -1
  311. package/src/shade/renderer/camera/orbital/MomentumAxis.js +0 -164
  312. package/src/shade/renderer/camera/orbital/OrbitalCameraConfig.d.ts +0 -45
  313. package/src/shade/renderer/camera/orbital/OrbitalCameraConfig.d.ts.map +0 -1
  314. package/src/shade/renderer/camera/orbital/OrbitalCameraConfig.js +0 -66
  315. package/src/shade/renderer/camera/orbital/OrbitalCameraInput.d.ts +0 -98
  316. package/src/shade/renderer/camera/orbital/OrbitalCameraInput.d.ts.map +0 -1
  317. package/src/shade/renderer/camera/orbital/OrbitalCameraInput.js +0 -184
  318. package/src/shade/renderer/camera/orbital/OrbitalCameraRig.d.ts +0 -175
  319. package/src/shade/renderer/camera/orbital/OrbitalCameraRig.d.ts.map +0 -1
  320. package/src/shade/renderer/camera/orbital/OrbitalCameraRig.js +0 -411
  321. package/src/shade/renderer/camera/orbital/README.md +0 -81
  322. package/src/shade/renderer/camera/orbital/index.d.ts +0 -6
  323. package/src/shade/renderer/camera/orbital/index.d.ts.map +0 -1
  324. package/src/shade/renderer/camera/orbital/index.js +0 -9
  325. package/src/shade/renderer/extension/RENDER_EXTENSION_DESIGN.md +0 -964
  326. package/src/shade/renderer/fluid/GPU_FLUID_OCCUPANCY_AND_SOTA_REVIEW_2026_10_26.md +0 -361
  327. package/src/shade/renderer/geometry/bvh/BLAS_REFIT_BATCH_PLAN.md +0 -619
  328. package/src/shade/renderer/geometry/meshlet/COMPACTION_PLAN_2026_09_16.md +0 -674
  329. package/src/shade/renderer/geometry/sdf/NOTES.md +0 -6
  330. package/src/shade/renderer/geometry/virtual/ATTRIBUTE_PLAN_2026_09_18.md +0 -540
  331. package/src/shade/renderer/geometry/virtual/MICRON_COMPARISON_2026_08_20.md +0 -305
  332. package/src/shade/renderer/geometry/virtual/VGEO_FORMAT.md +0 -913
  333. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md +0 -787
  334. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_PLAN.md +0 -481
  335. package/src/shade/renderer/geometry/virtual/VK_LOD_CLUSTERS_COMPARISON_2026_08_20.md +0 -301
  336. package/src/shade/renderer/geometry/virtual/WEDGE_PLAN_2026_09_18.md +0 -448
  337. package/src/shade/renderer/geometry/virtual/runtime/CULL_PLAN_2026_09_16.md +0 -385
  338. package/src/shade/renderer/geometry/virtual/runtime/CUT_PLAN_2026_09_14.md +0 -656
  339. package/src/shade/renderer/geometry/virtual/runtime/REVIEW_LEDGER.md +0 -308
  340. package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN.md +0 -657
  341. package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN_2026_09_14.md +0 -551
  342. package/src/shade/renderer/geometry/virtual/runtime/SHADOW_PLAN_2026_09_28.md +0 -529
  343. package/src/shade/renderer/geometry/virtual/sdf/VGEO_SDF.d.ts +0 -47
  344. package/src/shade/renderer/geometry/virtual/sdf/VGEO_SDF.d.ts.map +0 -1
  345. package/src/shade/renderer/geometry/virtual/sdf/VGEO_SDF.js +0 -80
  346. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_collect.d.ts +0 -16
  347. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_collect.d.ts.map +0 -1
  348. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_collect.js +0 -67
  349. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_decode.d.ts +0 -17
  350. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_decode.d.ts.map +0 -1
  351. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_decode.js +0 -145
  352. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_traverse.d.ts +0 -12
  353. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_traverse.d.ts.map +0 -1
  354. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_traverse.js +0 -105
  355. package/src/shade/renderer/global_illumination/lpv/NOTES.md +0 -3
  356. package/src/shade/renderer/global_illumination/probe_clipmap/PROBE_CLIPMAP_PROPOSAL_2026_10_27.md +0 -4306
  357. package/src/shade/renderer/global_illumination/probe_clipmap/PROBE_RAYS_VARIABLE_AND_SORTED_SCOPE_2026_10_30.md +0 -410
  358. package/src/shade/renderer/global_illumination/sharc/NOTES.md +0 -8
  359. package/src/shade/renderer/gpu_primitive/bvh/GPU_BVH_BUILD_PLAN.md +0 -1369
  360. package/src/shade/renderer/gpu_primitive/bvh/PHASE1_HANDOVER.md +0 -202
  361. package/src/shade/renderer/gpu_primitive/indirect/NOTES.md +0 -94
  362. package/src/shade/renderer/hiz/NOTES.md +0 -3
  363. package/src/shade/renderer/hiz/shader_hzb_reduce_mip0_clip.d.ts +0 -8
  364. package/src/shade/renderer/hiz/shader_hzb_reduce_mip0_clip.d.ts.map +0 -1
  365. package/src/shade/renderer/light/cluster/NOTES.md +0 -11
  366. package/src/shade/renderer/light/cluster/PROPOSAL_ALGORITHM_2026_10_16.md +0 -524
  367. package/src/shade/renderer/light/cluster/PROPOSAL_HIERARCHICAL_2026_10_16.md +0 -1101
  368. package/src/shade/renderer/material/resident/shader_resident_texture_means.d.ts +0 -24
  369. package/src/shade/renderer/material/resident/shader_resident_texture_means.d.ts.map +0 -1
  370. package/src/shade/renderer/material/resident/shader_resident_texture_means.js +0 -120
  371. package/src/shade/renderer/particles/DESIGN.md +0 -1011
  372. package/src/shade/renderer/particles/EMITTER_GLOBAL_STATE_PLAN_2026_10_29.md +0 -280
  373. package/src/shade/renderer/particles/ORIENTATION_PLAN_2026_10_15.md +0 -453
  374. package/src/shade/renderer/path_tracer/PATH_TRACED_MEDIA_PLAN_2026_10_02.md +0 -520
  375. package/src/shade/renderer/postprocess/bloom/NOTES.md +0 -6
  376. package/src/shade/renderer/postprocess/fsr/NOTES.md +0 -4
  377. package/src/shade/renderer/postprocess/gtao/NOTES.md +0 -6
  378. package/src/shade/renderer/postprocess/nss/NOTES.md +0 -332
  379. package/src/shade/renderer/postprocess/perspective/NOTES.md +0 -3
  380. package/src/shade/renderer/postprocess/sscs/NOTES.md +0 -5
  381. package/src/shade/renderer/postprocess/ssr/NOTES.md +0 -14
  382. package/src/shade/renderer/postprocess/ssr/REPROJECTION_PROPOSAL.md +0 -286
  383. package/src/shade/renderer/postprocess/ssr/prefilter/NOTES.md +0 -39
  384. package/src/shade/renderer/postprocess/taa/NOTES.md +0 -11
  385. package/src/shade/renderer/postprocess/upscale-dither/NOTES.md +0 -78
  386. package/src/shade/renderer/postprocess/vrs/NOTES.md +0 -4
  387. package/src/shade/renderer/rasterize/native/avboit/AVBOIT_LEDGER.md +0 -1218
  388. package/src/shade/renderer/rasterize/native/avboit/AVBOIT_PLAN_2026_09_03.md +0 -600
  389. package/src/shade/renderer/restir/reservoir/NOTES.md +0 -6
  390. package/src/shade/renderer/shader/chunk/atmosphere/NOTES.md +0 -6
  391. package/src/shade/renderer/shader/chunk/brdf/FRESNEL_BRIEF_2026_10_16.md +0 -391
  392. package/src/shade/renderer/shader/chunk/color/tonemap/ACES_TONE_MAPPING_BRIEF_2026_10_17.md +0 -153
  393. package/src/shade/renderer/shader/chunk/color/tonemap/HDR_TONE_MAPPING_FORMS_BRIEF_2026_10_16.md +0 -322
  394. package/src/shade/renderer/shader/chunk/color/tonemap/SDR_TONE_MAPPING_BRIEF_2026_10_16.md +0 -247
  395. package/src/shade/renderer/shader/chunk/fsr/NOTES.md +0 -3
  396. package/src/shade/renderer/shader/chunk/fsr/spd/NOTES.md +0 -4
  397. package/src/shade/renderer/shader/chunk/geometry/ray/NOTES.md +0 -4
  398. package/src/shade/renderer/shader/chunk/material/MULTISCATTER.md +0 -159
  399. package/src/shade/renderer/shader/chunk/mboit/NOTES.md +0 -38
  400. package/src/shade/renderer/shader/chunk/spherical_harmonics/l1i/NOTES.md +0 -3
  401. package/src/shade/renderer/shader/chunk/spherical_harmonics/sampling/NOTES.md +0 -8
  402. package/src/shade/renderer/shader/compiler/SHADER_SWITCH_PROPOSAL_2026_10_16.md +0 -927
  403. package/src/shade/renderer/shadow/contact/FINDINGS.md +0 -413
  404. package/src/shade/renderer/shadow/map/csm/NOTES.md +0 -5
  405. package/src/shade/renderer/shadow/ray/NOTES.md +0 -31
  406. package/src/shade/renderer/shadow/sdf/NOTES.md +0 -9
  407. package/src/shade/renderer/shadow/sdf/brixelizer/NOTES.md +0 -5
  408. package/src/shade/renderer/shadow/sdf/cascade/NOTES.md +0 -9
  409. package/src/shade/renderer/shadow/vsm/NOTES.md +0 -12
  410. package/src/shade/renderer/shadow/vsm/PLAN.md +0 -442
  411. package/src/shade/renderer/shadow/vsm/REVIEW_LEDGER.md +0 -43
  412. package/src/shade/renderer/texture/COMPRESSED_TEXTURE_PLAN_2026_09_01.md +0 -2444
  413. package/src/shade/renderer/texture/mipmaps/NOTES.md +0 -3
  414. package/src/shade/renderer/volumetrics/NOTES.md +0 -1329
  415. package/src/shade/renderer/volumetrics/VOLUMETRIC_NOISE_PLAN_2026_10_15.md +0 -336
  416. package/src/shade/renderer/water/medium/GPUWaterBodies.d.ts +0 -23
  417. package/src/shade/renderer/water/medium/GPUWaterBodies.d.ts.map +0 -1
  418. package/src/shade/renderer/water/medium/GPUWaterBodies.js +0 -75
  419. package/src/shade/wgsl/NOTES.md +0 -4
@@ -1,458 +0,0 @@
1
- # `shade/device/mock` — extension proposal, 2026-08-22
2
-
3
- Ranked work items for `SoftwareGPUDevice`, derived from
4
- [`REVIEW_2026_08_22.md`](./REVIEW_2026_08_22.md).
5
-
6
- Two ID spaces, kept distinct on purpose: `P1`…`P9` are the proposed items in this document, and
7
- `A1`, `B2`, `C7`, … are findings in the review.
8
-
9
- > **Status: all nine items built.** See [`IMPLEMENTATION_PLAN.md`](./IMPLEMENTATION_PLAN.md) for the
10
- > order they landed in, the commit for each, and what changed against the estimates here. This
11
- > document is kept as the record of why each item was chosen and what it was expected to cost.
12
-
13
- ---
14
-
15
- ## 0. What this proposal optimises for
16
-
17
- Three constraints, all of which an item must satisfy:
18
-
19
- 1. **It has to make the graphics engine testable.** Every item names the production code it unblocks
20
- and the test that proves it. An item that only makes the mock more complete is not on this list.
21
- 2. **It has to be low-hanging.** Nothing here needs a WGSL execution engine, a rasterizer, or a new
22
- architecture. The largest single item is roughly two hundred lines.
23
- 3. **It has to follow the spec.** Where the spec and convenience disagree, the spec wins — a mock
24
- that is convenient and wrong is worse than no mock, because the test that passes against it is
25
- evidence of nothing.
26
-
27
- A fourth constraint is implicit and worth stating: **it must not require touching Shade's
28
- architecture.** Every item below is additive inside this folder, with exactly two named exceptions:
29
- P7 adds two `Symbol.hasInstance` stubs to `shade/vitest.setup.mjs`, and P5 adds a *new* module beside
30
- `descriptor/texture/format/parse_gpu_texture_format.js` without rewriting it. No existing renderer
31
- module is restructured by anything here.
32
-
33
- ### The organising idea
34
-
35
- The review's conclusion is that the error-reporting machinery in this folder is complete and correct,
36
- and almost nothing uses it. `createBuffer`'s `maxBufferSize` check is the only validation the device
37
- performs, out of dozens the spec requires. Most of what follows is filling in the reports that
38
- machinery was built to carry.
39
-
40
- ---
41
-
42
- ## 1. Ranked items
43
-
44
- ### P1 — Buffer mapping · **highest value**
45
-
46
- *Addresses B1, B2, A3. Enables: readback, staging-pool parity.*
47
-
48
- Implement the mapping lifecycle on `SoftwareGPUBuffer`:
49
-
50
- - `mapAsync(mode, offset = 0, size)` — validates `mode` against `usage` (`GPUMapMode.READ` needs
51
- `MAP_READ`, `WRITE` needs `MAP_WRITE`), `offset % 8 === 0`, `size % 4 === 0`, range inside the
52
- buffer, `mapState === "unmapped"`, buffer valid and not destroyed. Sets `mapState` to `"pending"`,
53
- then `"mapped"`, and resolves. Rejects with an `OperationError` on a validation failure and raises
54
- a validation error on the device, which is what the spec does — both, not one.
55
- - `getMappedRange(offset = 0, size)` — returns a **distinct `ArrayBuffer` of exactly `size` bytes**,
56
- a copy of the mapped region. Validates `offset % 8`, `size % 4`, containment inside the mapped
57
- range, and non-overlap with a range already handed out. `OperationError` otherwise, including when
58
- `mapState !== "mapped"` — which is A3.
59
- - `unmap()` — copies every outstanding range back into the backing store (this is what makes
60
- `mappedAtCreation` and `MAP_WRITE` uploads real), then **detaches** them via
61
- `ArrayBuffer.prototype.transfer()`, which is available and behaves correctly on the Node in use
62
- (verified on v24). Sets `mapState` to `"unmapped"`.
63
-
64
- **Why copies rather than the current alias.** Today `getMappedRange` hands out the storage itself,
65
- so a range survives `unmap()` and keeps working — the source documents this as deliberate, and it is
66
- what makes `mappedAtCreation` readback convenient. It also makes use-after-unmap invisible, which is
67
- a real bug class in pooled-buffer code, and it makes the non-overlap and detach rules unimplementable.
68
- The copy-and-write-back model is what a driver actually does, costs one memcpy per mapped range in
69
- tests, and preserves the convenience for the case that motivated the alias: a `mappedAtCreation`
70
- buffer written and unmapped still reads back correctly through `.data`.
71
-
72
- **Blocked-on-this, today:** `inspect_gpu_buffer`, `inspect_gpu_buffer_typed`, `graph_read_buffer`,
73
- `download_texture_data`, `Uint32BufferSamplingStats`, `GPUTimer`, `GPUTimerArray`, and — the one that
74
- is actively distorting the suite — `GPUBufferStagingAllocator` recycling, and with it
75
- `ShadeGPUCommandContext.writeBuffer` / `writeValueBuffer`.
76
-
77
- **Acceptance:**
78
- - A host-side round trip with no shader in it: `queue.writeBuffer` → `copyBufferToBuffer` into a
79
- `MAP_READ | COPY_DST` buffer → `mapAsync` → `getMappedRange` returns the bytes. That is
80
- `inspect_gpu_buffer`'s `inspect_via_copy` path exactly, so the spec can call the production
81
- function rather than reimplement it.
82
- - Five identical staging requests through `GPUBufferStagingAllocator` allocate **one** buffer, not
83
- five, and the pool serves a 64-byte request from a pooled 256-byte buffer — the sub-range case
84
- that B2 currently refuses.
85
- - `GPUMeshSkinningContext.spec.js` produces zero `Not Implemented` lines (currently 104).
86
- - A range handed out by `getMappedRange` is detached after `unmap()`, and its contents reached the
87
- backing store.
88
-
89
- **Cost:** ~120 lines plus spec. **Risk:** low, but see §3 — fixing B1 exposes B2, so the two land
90
- together.
91
-
92
- ---
93
-
94
- ### P2 — Validation parity on the queue and the encoder
95
-
96
- *Addresses A1, A2, A4, A5, A6, A7.*
97
-
98
- Give the error machinery something to report. Each rule is a spec bullet and two to four lines:
99
-
100
- `queue.writeBuffer` — `COPY_DST` in usage; `bufferOffset % 4`; written size `% 4`;
101
- `bufferOffset + size <= buffer.size`; source range inside `data`; buffer valid, unmapped, not
102
- destroyed. **Remove the `Math.min` clamp on the default size** (`SoftwareGPUQueue.js:84`): the spec's
103
- default is `data.byteLength - dataOffset`, and a value that overruns the destination is a validation
104
- error, not something to quietly shorten (A1).
105
-
106
- `encoder.copyBufferToBuffer` — `COPY_SRC` / `COPY_DST`; all three of offset/offset/size `% 4`; both
107
- ranges in bounds; `source !== destination`; neither destroyed. Failures invalidate the encoder and
108
- surface from `finish()`, which is the path the encoder already implements.
109
-
110
- `encoder.clearBuffer` — `COPY_DST`; offset and size `% 4`; in bounds.
111
-
112
- `device.createBuffer` — `usage !== 0`; `MAP_READ` only with `COPY_DST`, `MAP_WRITE` only with
113
- `COPY_SRC`, never both; `mappedAtCreation` requires `size % 4`.
114
-
115
- `device.createTexture` — dimension against `maxTextureDimension1D/2D/3D`, layers against
116
- `maxTextureArrayLayers`, `mipLevelCount` against `floor(log2(max(w,h,d))) + 1`, `usage !== 0`,
117
- `sampleCount ∈ {1, 4}`. Returns an invalid texture on refusal, mirroring `SoftwareGPUBuffer.invalid`.
118
-
119
- `GPUBuffer` gains a destroyed-state check that every consumer honours, so A2 stops being possible.
120
-
121
- **Why this is safe to land:** a refused operation calls `generate_error`, and an error nobody is
122
- scoped for goes to `console.error` — it does not fail a vitest run. So the blast radius is console
123
- noise plus any test that explicitly opens a scope, not a red suite. That is also the argument for
124
- landing it *after* P1: P1 removes 104 lines of existing console noise, so new noise is legible.
125
-
126
- **Acceptance:** a `SoftwareGPUValidationError` for each rule, in a table-driven spec; plus a
127
- regression test that an over-long `writeBuffer` reports instead of truncating.
128
-
129
- **Cost:** ~200 lines, mostly a checklist. **Risk:** medium — see §3.
130
-
131
- ---
132
-
133
- ### P3 — Per-instance, frozen, overridable limits · **best value-to-cost ratio**
134
-
135
- *Addresses A9, A11, and unlocks the clamp paths behind A5.*
136
-
137
- ```js
138
- new SoftwareGPUDevice({ limits: { maxTextureDimension2D: 256 } })
139
- ```
140
-
141
- - Each device gets its own object; `Object.freeze` it, so an assignment is a no-op the way it is on a
142
- real device rather than a mutation everyone else sees (A9).
143
- - Correct the four stage-scoped storage limits to mirror `maxStorageBuffersPerShaderStage` (8) and
144
- `maxStorageTexturesPerShaderStage` (4), and add `maxImmediateSize: 0` (A11).
145
- - Reject an override that *exceeds* a real adapter's default, since that is what
146
- `requestDevice({requiredLimits})` does — a mock that grants a limit no hardware offers is a
147
- liability.
148
-
149
- **Why it earns its place:** Shade has at least seven sites that clamp an allocation against a texture
150
- dimension limit — `Renderer.js:1381`, `:1440`, `GPUProbeAtlas.js:112`, `:213`,
151
- `VirtualShadowMap.js:77`, `GPUSceneShadowmapContext.js:270` against `maxTextureDimension2D`, and
152
- `GPUGeometrySDFManager.js:71` against `maxTextureDimension3D`. Today the only way to reach the
153
- clamped branch is to actually request an 8192-pixel texture. With a lowered limit, each becomes a
154
- three-line test.
155
-
156
- **Acceptance:** a spec that lowers `maxTextureDimension2D` and asserts `VirtualShadowMap` clamps its
157
- resolution; a spec that two devices do not share limits.
158
-
159
- **Cost:** ~30 lines. **Risk:** none — additive, with a default that changes only the five values
160
- named in A11.
161
-
162
- ---
163
-
164
- ### P4 — Recording render pass encoder, and the missing copy commands
165
-
166
- *Addresses C2, C3, C5.*
167
-
168
- `SoftwareGPURenderPassEncoder`, modelled directly on the existing compute pass encoder: record, do
169
- not execute, and say so in the header the way that file already does.
170
-
171
- The surface is small because Shade is a vertex-pulling meshlet renderer. Counting calls made directly
172
- on a pass across all of `shade/`: `draw` (17), `setViewport` (4), `drawIndirect` (3),
173
- `setVertexBuffer` (1, and that one is in a `prototype*.js` file), plus `setPipeline`, `setBindGroup`,
174
- `end` and the debug markers. **No index buffers, no render bundles, no occlusion queries.**
175
-
176
- The leverage is better than those counts suggest: `ImageShader.draw()` funnels through
177
- `constructRenderPass` → `setViewport` → `draw(3)` → `end` (`renderer/shader/ImageShader.js:178-208`),
178
- and roughly two dozen further call sites go through *it*. One recording pass encoder therefore
179
- unblocks every full-screen pass in the renderer.
180
-
181
- Record `draws` the way the compute encoder records `dispatches`, and retain the descriptor's
182
- `colorAttachments` / `depthStencilAttachment` so a test can assert what a pass was pointed at — which
183
- is the actual question the frame graph raises.
184
-
185
- Alongside it, the three copy commands that execute against the texture storage that already exists:
186
- `copyTextureToTexture`, `copyBufferToTexture`, `copyTextureToBuffer`. These are row loops over
187
- `get_mip_data`, structurally identical to `queue.writeTexture`.
188
-
189
- **Unblocks:** any test of `ShadeGPUCommandContext.beginRenderPass` / `constructRenderPass`, the frame
190
- graph's pass wiring, attachment load/store configuration, and — with P1 — `download_texture_data`
191
- end to end.
192
-
193
- **Acceptance:** a spec that builds a two-pass frame through `ShadeGPUCommandContext` and asserts the
194
- passes, their order, and their attachments; a spec that round-trips texels through
195
- `writeTexture → copyTextureToBuffer → mapAsync`.
196
-
197
- **Cost:** ~150 lines for the pass encoder, ~80 for the copies. **Risk:** low; nothing existing calls
198
- these, so there is no behaviour to regress. Bounded by P5 below for depth formats.
199
-
200
- ---
201
-
202
- ### P5 — Texture format block table
203
-
204
- *Addresses the review's E1 (inherited).*
205
-
206
- A `gpu_texture_format_info(format) -> {blockWidth, blockHeight, bytesPerBlock, aspects}` table
207
- covering the spec's format list, as a **new module** in `descriptor/texture/format/` beside
208
- `parse_gpu_texture_format.js` rather than a rewrite of it. `SoftwareGPUTexture.bytes_per_texel` (and
209
- its block-aware successor) reads the table.
210
-
211
- `parse_gpu_texture_format`'s regular expression cannot express depth, stencil, packed or
212
- block-compressed formats — `depth24plus`, `stencil8`, `bc7-rgba-unorm` fail to parse and
213
- `rgb10a2unorm`, `rg11b10ufloat` parse into nonsense and throw. A table is the right shape for this
214
- data and a regex is not; and leaving the existing function alone keeps the change additive, which is
215
- how Shade prefers changes.
216
-
217
- **Unblocks:** every texture test involving a shadow map, the Hi-Z chain, the G-buffer, or any
218
- compressed asset — currently all of them throw at first write.
219
-
220
- **Acceptance:** a table-driven spec over the full format list asserting the block descriptor, checked
221
- against Dawn where Dawn exposes it.
222
-
223
- **Cost:** mechanical, ~90 rows plus ~40 lines. **Risk:** low, additive. The tedium is the cost.
224
-
225
- ---
226
-
227
- ### P6 — Resource lifetime, spec-shaped
228
-
229
- *Addresses B3, B4, A2's other half.*
230
-
231
- - `destroy()` becomes idempotent on `SoftwareGPUBuffer` and `SoftwareGPUTexture` — the source's own
232
- `// TODO should this fail silently instead?` answered in the spec's favour (B3).
233
- - `device.destroy()` implemented: idempotent, releases every resource the device handed out, resolves
234
- `device.lost` with reason `"destroyed"`, and makes subsequent work a validation error rather than
235
- an exception (B4, C7).
236
- - The device keeps a ledger of live resources so a test can assert **end state**: *"after this pass
237
- tore down, the device is holding nothing."*
238
-
239
- On that last point: the ledger is deliberately an end-state assertion and not a call counter.
240
- `GPUBufferAllocator.spec.js` currently monkey-patches `createBuffer` and `buffer.destroy` to count
241
- calls, which is the kind of white-box assertion the house style rejects; a leak check asks an
242
- observable question about the device instead.
243
-
244
- **Acceptance:** double-destroy is a no-op; a spec that a `ShadeGPUCommandContext` releases every
245
- transient buffer it took.
246
-
247
- **Cost:** ~80 lines. **Risk:** low.
248
-
249
- ---
250
-
251
- ### P7 — `instanceof` recognition for views and samplers
252
-
253
- *Addresses D1.*
254
-
255
- Two changes:
256
-
257
- 1. `createSampler` returns a `SoftwareGPUSampler` **class** instance rather than an object literal
258
- (it is the only resource here that is not a class, and `a.constructor` equality in
259
- `BindGroupDescriptor` therefore sees `Object`).
260
- 2. `vitest.setup.mjs` gives `GPUTextureView` and `GPUSampler` the same `Symbol.hasInstance` treatment
261
- `GPUBuffer` already has, recognising `isSoftwareGPUTextureView` / `isSoftwareGPUSampler`.
262
-
263
- Today both `instanceof` tests are false under the mock, so
264
- `BindGroupDescriptor.compute_binding_resource_hash` returns **0 for every texture-view and sampler
265
- binding** and its two dedicated branches are dead code in node. `BindGroupManager.spec.js` binds only
266
- buffers, so nothing covers them. The same two globals also gate
267
- `encoder_prepare_shader_binding.js:55`/`:66` and `ShaderResourceGroupDescriptor.js:132`.
268
-
269
- **Acceptance:** a spec that two bind groups differing only in bound texture view hash differently,
270
- and that a texture-view binding survives `encoder_prepare_shader_binding`.
271
-
272
- **Cost:** ~20 lines across two files. **Risk:** bind-group hash values change under the mock. Since
273
- no current test binds a view or a sampler, the measured blast radius is zero — but this is the one
274
- item that changes the behaviour of code paths outside this folder, so it lands on its own commit.
275
-
276
- ---
277
-
278
- ### P8 — Timestamp queries
279
-
280
- *Addresses C1, C4.*
281
-
282
- `createQuerySet`, `resolveQuerySet`, and acceptance of `timestampWrites` on pass descriptors — plus
283
- an opt-in `new SoftwareGPUDevice({ features: ['timestamp-query'] })` so `device.features.has(...)`
284
- answers truthfully for a device that has it. (`ShadeGPUCommandContext` already gates its timer
285
- plumbing on exactly that call, at `:344` and `:483`.)
286
-
287
- `resolveQuerySet` writes a deterministic, monotonically increasing `BigInt64` counter into the
288
- destination buffer, and the source **says in its header, unmissably, that these are not
289
- measurements.** The precedent is `dispatchWorkgroupsIndirect` recording `[-1, -1, -1]` rather than
290
- inventing a workgroup count: state the fiction rather than dress it up.
291
-
292
- What this actually tests is not timing but the plumbing that breaks: query-set sizing, resolve
293
- ranges, buffer offsets, the `BigInt64Array` decode in `GPUTimer` / `GPUTimerArray`, and pairing of
294
- begin/end writes. Combined with P1 the whole timing readback path runs in node.
295
-
296
- **Acceptance:** `GPUTimerArray` resolves N pairs and decodes N durations; a spec that a mismatched
297
- resolve range is a validation error.
298
-
299
- **Cost:** ~100 lines. **Risk:** low. Weighed against P4/P5 it is worth less, hence the position.
300
-
301
- ---
302
-
303
- ### P9 — The small change bundle
304
-
305
- *Addresses C6, C8, C9, A8, A10, B5, B6/B7.*
306
-
307
- Individually trivial, collectively the difference between a mock you can lean on and one you
308
- constantly work around:
309
-
310
- | Change | Finding |
311
- |---|---|
312
- | `createCommandEncoder(descriptor)` honours its descriptor; `SoftwareGPUCommandEncoder` extends `SoftwareGPUObjectBase` so it has a `label` | C8 |
313
- | `queue.onSubmittedWorkDone()` → a resolved promise (submission is synchronous here) | C6 |
314
- | `setBindGroup` records dynamic offsets, both overloads | C9 |
315
- | The encoder locks while a pass is open; a second `beginComputePass` or an encoder command before `end()` is a validation error | A8 |
316
- | `features` reports `core-features-and-limits`, which every core device has | A10 |
317
- | Re-submitting a command buffer is a validation error rather than `throw new Error('execute() called twice')` | B5 |
318
- | One header comment stating the folder's policy for illegal input, and naming its deliberate exceptions | B6, B7 |
319
-
320
- That last row is the one that matters beyond its size. The folder currently runs three policies —
321
- *report through the error scope* (A6, B5), *throw on a caller bug* (encode-after-finish), *throw for
322
- an unimplemented feature* (`copyExternalImageToTexture`) — and none is written down. Any of the three
323
- is defensible; not choosing is not.
324
-
325
- **Cost:** ~90 lines total. **Risk:** the encoder lock could surface existing pass-scoping violations
326
- in Shade. That is the point, and it is a validation error, not a thrown exception, so it will appear
327
- as console output rather than a red suite.
328
-
329
- ---
330
-
331
- ## 2. Considered and not proposed
332
-
333
- | | Why not |
334
- |---|---|
335
- | WGSL execution / a software rasterizer | The mock's value is that it is *not* one. Shader execution is `ComputeShaderEmulator`'s job and real execution is Dawn's; a third half-implementation would be the least trustworthy of the three. The compute pass encoder's header already makes this argument and it is correct. |
336
- | WebGPU CTS conformance | Wrong target. The engine needs the ~15% of the API it uses to be right, not the whole surface to be 60% right. |
337
- | `SoftwareGPUAdapter` / `navigator.gpu` (C10) | Only `ShadeDeviceFailure` cares about acquisition, and `ShadeDeviceFailure.spec.js` already covers the failure objects directly. Revisit if acquisition grows logic. |
338
- | Render bundles, occlusion queries, external textures, canvas context | Zero call sites in Shade. |
339
- | Multi-layer / 3D `writeTexture` (review E2) | Genuinely useful for the LPG volume and the SDF atlas, but it is a real generalisation of the addressing rather than a checklist, and it should follow P5 — there is no point generalising layers while depth formats still throw. |
340
- | Making `assert.*`-based refusals throw in production builds | The mock is test-only, so the stripped assertions cost nothing today. Worth one line in the policy comment from P9 rather than a code change. |
341
- | Fixing `probe_instance_animation.js`'s stale header (F1) | A one-line doc fix outside this folder; noted so it is not lost, not tracked here. |
342
-
343
- ---
344
-
345
- ## 3. Sequencing, and the risks that drive it
346
-
347
- ```
348
- P3 ─┐
349
- P7 ─┼─► (independent, land first: additive, near-zero risk)
350
- P9 ─┘
351
- P1 ──► P2 ──► P6
352
- │
353
- └───► P5 ──► P4 ──► P8
354
- ```
355
-
356
- **Phase 1 — P3, P7, P9.** Additive, no behaviour to regress, and P9's policy comment sets the rule
357
- every later item follows. P7 lands on its own commit because it is the only item that changes the
358
- behaviour of code outside this folder.
359
-
360
- **Phase 2 — P1.** The single biggest unlock, and it retires 104 lines of existing console noise,
361
- which is a precondition for reading the noise P2 creates.
362
-
363
- **Phase 3 — P2.** After P1, because of the coupling below.
364
-
365
- **Phase 4 — P5, then P4.** Formats before texture commands; there is no point implementing
366
- `copyTextureToBuffer` while `bytes_per_texel` throws for depth.
367
-
368
- **Phase 5 — P6, P8.**
369
-
370
- ### Risks worth naming before starting
371
-
372
- **P1 and P2 are coupled through a masking bug.** B2 (`getMappedRange` refuses sub-ranges) is
373
- invisible today only because B1 (`mapAsync` throws) stops `GPUBufferStagingAllocator` from ever
374
- recycling an oversized buffer. Implement `mapAsync` alone and the pool starts working, immediately
375
- hands back a buffer larger than requested, and `ShadeGPUCommandContext.writeBuffer` throws
376
- `Size not supported` on the next frame. **The two halves of P1 must land in one commit**, and the
377
- staging-pool spec is the test that proves it.
378
-
379
- **P2 will surface latent violations in Shade.** That is the purpose, but it is also a scope risk: an
380
- unknown number of existing call sites may be doing something the spec forbids. Two mitigations. First,
381
- the failure mode is a `console.error` from an unscoped validation error, not a test failure, so the
382
- suite does not go red on landing. Second, land the rules one entry point at a time —
383
- `writeBuffer` first, since A1 is the highest-consequence finding — and read the output before adding
384
- the next.
385
-
386
- **P7 changes hash values.** Only under the mock, and only for bindings no current test creates.
387
- Own commit, so a bisect lands cleanly on it if this is wrong.
388
-
389
- **Nothing here helps with what a shader computes.** Worth restating because it bounds every claim in
390
- this document: after all nine items, a dispatch still changes no bytes. These extensions make the
391
- *host* side of the renderer testable — allocation, lifetime, encoding, validation, upload, readback,
392
- pass structure. Shader output remains `ComputeShaderEmulator`'s and Dawn's territory, and a test that
393
- asserts on it against this device is meaningless regardless of how much of this proposal is built.
394
-
395
- ---
396
-
397
- ## 4. Adversarial review of this document
398
-
399
- Challenges raised against the draft, and what they changed.
400
-
401
- **"P1 is described as low-hanging but it changes the memory model of every mapped buffer."** Fair, and
402
- the item now argues the change rather than asserting it. The current alias-the-storage design is
403
- *documented as deliberate* in the source, so replacing it needs a reason: it makes use-after-unmap
404
- invisible and makes the spec's non-overlap and detach rules unimplementable. The convenience it was
405
- protecting (`mappedAtCreation` readback through `.data`) is preserved by the write-back. P1 is the
406
- largest item here and the ordering reflects that; "low-hanging" is claimed for the proposal as a
407
- whole against the alternative of a real emulator, not for P1 individually.
408
-
409
- **"P2 will break the suite and you have not measured how badly."** Correct — that is unmeasured and
410
- the document now says so plainly instead of implying safety. Two things were added: the mechanical
411
- reason a validation error cannot fail vitest (unscoped errors reach `console.error`, not the
412
- reporter), and a per-entry-point rollout so the unknown is discovered incrementally. The honest
413
- statement is that the size of the latent-violation set is unknown until `writeBuffer` validation
414
- lands.
415
-
416
- **"P8 fabricates timing data — the review's own standard rejects that."** The strongest objection
417
- raised. The item was rewritten to be explicit that the numbers are fiction, to require the header to
418
- say so, and to relocate the claimed value: what P8 tests is the *plumbing* (query-set sizing, resolve
419
- offsets, `BigInt64Array` decode, begin/end pairing), which is real and is what actually breaks. It
420
- was also moved down the ranking. If the fiction is still unacceptable, dropping P8 costs the least of
421
- any item here.
422
-
423
- **"P1's acceptance criterion — un-skipping `GPUDatabase.spec.js`'s `full-fat` test — assumes that
424
- test only needs mapping."** It does not, and the criterion was wrong. `GPUDatabase.update` uploads
425
- through a compute dispatch (`GPUDatabase.js:570`), which changes no bytes under this device, so no
426
- extension short of shader execution runs that test. It was replaced with three criteria that contain
427
- no shader at all — a host-side `writeBuffer → copy → mapAsync → getMappedRange` round trip through
428
- `inspect_via_copy`, the staging-pool allocation count, and detach-on-unmap. This is a good
429
- illustration of the trap the whole proposal has to avoid: *"the mock nearly runs this test"* is easy
430
- to believe and needs checking against what the code path actually does.
431
-
432
- **"The P1↔B2 coupling is asserted, not demonstrated."** Half true. That `getMappedRange` refuses
433
- `(0, 32)` on a 64-byte buffer is verified; that `GPUBufferStagingAllocator.get` returns a buffer with
434
- `size >= min_size_bytes` is read from its source and its own assertion; that
435
- `ShadeGPUCommandContext.writeBuffer` then calls `getMappedRange(0, size)` is read from `:660`. The
436
- conjunction is inference from three verified facts, not an observed failure — because the failure
437
- cannot be observed until `mapAsync` exists. That is precisely why it is called out as a sequencing
438
- risk with a named test rather than left to be discovered.
439
-
440
- **"Why is P3 not first if it is the best ratio?"** It is in Phase 1. The list is ranked by value, the
441
- diagram by dependency, and the two orderings differ; the document now states which is which rather
442
- than leaving a reader to reconcile them.
443
-
444
- **"P5 is 90 rows of table — that is not low-hanging."** It is mechanical rather than small, which is
445
- a different thing, and the item now says so. It stays because P4 is worth much less without it: today
446
- every depth, packed and block-compressed format throws at first write, which covers the shadow maps,
447
- the Hi-Z chain and the G-buffer.
448
-
449
- **"P9 bundles seven unrelated changes to look cheap."** True of the first six rows, which are genuinely
450
- independent one-liners and are listed as a table so they can be split. The seventh — the policy
451
- comment — is not filler: three contradictory conventions for illegal input currently coexist in this
452
- folder, and every later item has to pick one. It arguably deserves to be its own item ahead of
453
- everything else.
454
-
455
- **"'Zero call sites in Shade' is a weak reason to exclude render bundles."** Accepted as a limit on
456
- the argument. The exclusions in §2 are scoped to *this engine's current usage*, which is the stated
457
- optimisation target, and would need revisiting if the renderer's shape changes. The table says
458
- "Zero call sites in Shade" rather than "not useful" for that reason.