@woosh/meep-engine 3.42.0 → 3.44.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (345) hide show
  1. package/editor/prototypeEditorShell.d.ts.map +1 -1
  2. package/editor/prototypeEditorShell.js +4 -2
  3. package/package.json +91 -96
  4. package/src/engine/Clock.d.ts +15 -0
  5. package/src/engine/Clock.d.ts.map +1 -1
  6. package/src/engine/Clock.js +29 -5
  7. package/src/engine/Engine.d.ts.map +1 -1
  8. package/src/engine/Engine.js +11 -19
  9. package/src/engine/graphics/ecs/mesh-v2/MeshSkin.d.ts +57 -0
  10. package/src/engine/graphics/ecs/mesh-v2/MeshSkin.d.ts.map +1 -0
  11. package/src/engine/graphics/ecs/mesh-v2/MeshSkin.js +84 -0
  12. package/src/engine/graphics3/AnimationGraphSystem.d.ts +23 -13
  13. package/src/engine/graphics3/AnimationGraphSystem.d.ts.map +1 -1
  14. package/src/engine/graphics3/AnimationGraphSystem.js +61 -64
  15. package/src/engine/graphics3/AnimationSystem.d.ts +24 -15
  16. package/src/engine/graphics3/AnimationSystem.d.ts.map +1 -1
  17. package/src/engine/graphics3/AnimationSystem.js +67 -61
  18. package/src/engine/graphics3/MeshSkinSystem.d.ts +56 -0
  19. package/src/engine/graphics3/MeshSkinSystem.d.ts.map +1 -0
  20. package/src/engine/graphics3/MeshSkinSystem.js +317 -0
  21. package/src/engine/graphics3/MeshSystem.d.ts +15 -35
  22. package/src/engine/graphics3/MeshSystem.d.ts.map +1 -1
  23. package/src/engine/graphics3/MeshSystem.js +21 -298
  24. package/src/engine/graphics3/RowChains.d.ts +76 -0
  25. package/src/engine/graphics3/RowChains.d.ts.map +1 -0
  26. package/src/engine/graphics3/RowChains.js +347 -0
  27. package/src/engine/graphics3/ShadedGeometrySystem.d.ts +6 -0
  28. package/src/engine/graphics3/ShadedGeometrySystem.d.ts.map +1 -1
  29. package/src/engine/graphics3/ShadedGeometrySystem.js +329 -309
  30. package/src/engine/graphics3/animation/AnimationClips.d.ts +56 -0
  31. package/src/engine/graphics3/animation/AnimationClips.d.ts.map +1 -0
  32. package/src/engine/graphics3/animation/AnimationClips.js +79 -0
  33. package/src/engine/graphics3/animation/ClipListPlayer.d.ts +13 -14
  34. package/src/engine/graphics3/animation/ClipListPlayer.d.ts.map +1 -1
  35. package/src/engine/graphics3/animation/ClipListPlayer.js +262 -263
  36. package/src/engine/graphics3/animation/write_clip_playback.d.ts +3 -3
  37. package/src/engine/graphics3/animation/write_clip_playback.js +4 -4
  38. package/src/engine/graphics3/pose/query_entity_node_world_pose.d.ts +5 -0
  39. package/src/engine/graphics3/pose/query_entity_node_world_pose.d.ts.map +1 -1
  40. package/src/engine/graphics3/pose/query_entity_node_world_pose.js +80 -75
  41. package/src/engine/graphics3/prefab/PrefabInstance.d.ts +4 -24
  42. package/src/engine/graphics3/prefab/PrefabInstance.d.ts.map +1 -1
  43. package/src/engine/graphics3/prefab/PrefabInstance.js +60 -80
  44. package/src/engine/graphics3/prefab/prefab_instantiate.d.ts +16 -3
  45. package/src/engine/graphics3/prefab/prefab_instantiate.d.ts.map +1 -1
  46. package/src/engine/graphics3/prefab/prefab_instantiate.js +49 -12
  47. package/src/engine/graphics3/prefab/prefab_place.d.ts +31 -17
  48. package/src/engine/graphics3/prefab/prefab_place.d.ts.map +1 -1
  49. package/src/engine/graphics3/prefab/prefab_place.js +175 -130
  50. package/src/engine/graphics3/register_clips.d.ts +64 -0
  51. package/src/engine/graphics3/register_clips.d.ts.map +1 -0
  52. package/src/engine/graphics3/register_clips.js +114 -0
  53. package/src/engine/physics/cloth/MEASUREMENTS.md +795 -0
  54. package/src/engine/physics/cloth/PLAN.md +339 -9
  55. package/src/engine/physics/cloth/build/ClothProxy.d.ts +113 -61
  56. package/src/engine/physics/cloth/build/ClothProxy.d.ts.map +1 -1
  57. package/src/engine/physics/cloth/build/ClothProxy.js +142 -77
  58. package/src/engine/physics/cloth/build/cloth_bind_in_frame.d.ts +22 -0
  59. package/src/engine/physics/cloth/build/cloth_bind_in_frame.d.ts.map +1 -0
  60. package/src/engine/physics/cloth/build/cloth_bind_in_frame.js +75 -0
  61. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.d.ts +43 -30
  62. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.d.ts.map +1 -1
  63. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.js +357 -284
  64. package/src/engine/physics/cloth/build/cloth_proxy_from_mesh.d.ts +62 -0
  65. package/src/engine/physics/cloth/build/cloth_proxy_from_mesh.d.ts.map +1 -0
  66. package/src/engine/physics/cloth/build/cloth_proxy_from_mesh.js +280 -0
  67. package/src/engine/physics/cloth/collider/cloth_collider_sdf.d.ts +1 -1
  68. package/src/engine/physics/cloth/collider/cloth_collider_sdf.js +1 -1
  69. package/src/engine/physics/cloth/ecs/Cloth.d.ts +17 -9
  70. package/src/engine/physics/cloth/ecs/Cloth.d.ts.map +1 -1
  71. package/src/engine/physics/cloth/ecs/Cloth.js +220 -212
  72. package/src/engine/physics/cloth/ecs/ClothDynamicsFlags.js +6 -0
  73. package/src/engine/physics/cloth/ecs/ClothHold.d.ts +91 -0
  74. package/src/engine/physics/cloth/ecs/ClothHold.d.ts.map +1 -0
  75. package/src/engine/physics/cloth/ecs/ClothHold.js +103 -0
  76. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts +254 -48
  77. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts.map +1 -1
  78. package/src/engine/physics/cloth/ecs/ClothInstance.js +277 -47
  79. package/src/engine/physics/cloth/ecs/ClothPin.d.ts +73 -0
  80. package/src/engine/physics/cloth/ecs/ClothPin.d.ts.map +1 -0
  81. package/src/engine/physics/cloth/ecs/ClothPin.js +92 -0
  82. package/src/engine/physics/cloth/ecs/ClothPinSerializationAdapter.d.ts +36 -0
  83. package/src/engine/physics/cloth/ecs/ClothPinSerializationAdapter.d.ts.map +1 -0
  84. package/src/engine/physics/cloth/ecs/ClothPinSerializationAdapter.js +61 -0
  85. package/src/engine/physics/cloth/ecs/ClothRig.d.ts +23 -17
  86. package/src/engine/physics/cloth/ecs/ClothRig.d.ts.map +1 -1
  87. package/src/engine/physics/cloth/ecs/ClothRig.js +29 -27
  88. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts +12 -14
  89. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts.map +1 -1
  90. package/src/engine/physics/cloth/ecs/ClothSystem.js +20 -15
  91. package/src/engine/physics/cloth/ecs/ClothWorld.d.ts +57 -36
  92. package/src/engine/physics/cloth/ecs/ClothWorld.d.ts.map +1 -1
  93. package/src/engine/physics/cloth/ecs/ClothWorld.js +816 -179
  94. package/src/engine/physics/cloth/ecs/WorkerClothSystem.d.ts +12 -13
  95. package/src/engine/physics/cloth/ecs/WorkerClothSystem.d.ts.map +1 -1
  96. package/src/engine/physics/cloth/ecs/WorkerClothSystem.js +20 -14
  97. package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts +63 -11
  98. package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts.map +1 -1
  99. package/src/engine/physics/cloth/ecs/cloth_build_rows.js +321 -84
  100. package/src/engine/physics/cloth/ecs/cloth_dynamics_map.d.ts +9 -7
  101. package/src/engine/physics/cloth/ecs/cloth_dynamics_map.d.ts.map +1 -1
  102. package/src/engine/physics/cloth/ecs/cloth_dynamics_map.js +9 -7
  103. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts +3 -3
  104. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.js +30 -30
  105. package/src/engine/physics/cloth/ecs/cloth_geodesic.d.ts +37 -0
  106. package/src/engine/physics/cloth/ecs/cloth_geodesic.d.ts.map +1 -0
  107. package/src/engine/physics/cloth/ecs/cloth_geodesic.js +142 -0
  108. package/src/engine/physics/cloth/ecs/cloth_holds.d.ts +97 -0
  109. package/src/engine/physics/cloth/ecs/cloth_holds.d.ts.map +1 -0
  110. package/src/engine/physics/cloth/ecs/cloth_holds.js +608 -0
  111. package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.d.ts +2 -2
  112. package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.d.ts.map +1 -1
  113. package/src/engine/physics/cloth/ecs/cloth_reconstruct_pose.js +160 -9
  114. package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts +17 -22
  115. package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts.map +1 -1
  116. package/src/engine/physics/cloth/ecs/cloth_seed_rig.js +55 -117
  117. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts +21 -6
  118. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts.map +1 -1
  119. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.js +44 -15
  120. package/src/engine/physics/cloth/ecs/cloth_write_back.d.ts +5 -0
  121. package/src/engine/physics/cloth/ecs/cloth_write_back.d.ts.map +1 -1
  122. package/src/engine/physics/cloth/ecs/cloth_write_back.js +60 -16
  123. package/src/engine/physics/cloth/ecs/cloth_write_back_rig.d.ts.map +1 -1
  124. package/src/engine/physics/cloth/ecs/cloth_write_back_rig.js +65 -58
  125. package/src/engine/physics/cloth/playground/collide_main.js +1 -1
  126. package/src/engine/physics/cloth/playground/garment_build.d.ts.map +1 -1
  127. package/src/engine/physics/cloth/playground/garment_build.js +17 -5
  128. package/src/engine/physics/cloth/playground/garment_main.js +1 -1
  129. package/src/engine/physics/cloth/playground/rig_build.d.ts.map +1 -1
  130. package/src/engine/physics/cloth/playground/rig_build.js +302 -296
  131. package/src/engine/physics/cloth/solver/ClothState.d.ts +45 -7
  132. package/src/engine/physics/cloth/solver/ClothState.d.ts.map +1 -1
  133. package/src/engine/physics/cloth/solver/ClothState.js +63 -7
  134. package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts +6 -1
  135. package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts.map +1 -1
  136. package/src/engine/physics/cloth/solver/cloth_contact_find.js +7 -2
  137. package/src/engine/physics/cloth/solver/cloth_hold_line.d.ts +114 -0
  138. package/src/engine/physics/cloth/solver/cloth_hold_line.d.ts.map +1 -0
  139. package/src/engine/physics/cloth/solver/cloth_hold_line.js +362 -0
  140. package/src/engine/physics/cloth/solver/cloth_self_find.d.ts +6 -2
  141. package/src/engine/physics/cloth/solver/cloth_self_find.d.ts.map +1 -1
  142. package/src/engine/physics/cloth/solver/cloth_self_find.js +13 -13
  143. package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts +24 -12
  144. package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts.map +1 -1
  145. package/src/engine/physics/cloth/solver/cloth_solver_constants.js +24 -12
  146. package/src/engine/physics/cloth/solver/cloth_step.d.ts +16 -0
  147. package/src/engine/physics/cloth/solver/cloth_step.d.ts.map +1 -1
  148. package/src/engine/physics/cloth/solver/cloth_step.js +183 -20
  149. package/src/engine/physics/cloth/solver/cloth_step_instance.d.ts +1 -0
  150. package/src/engine/physics/cloth/solver/cloth_step_instance.d.ts.map +1 -1
  151. package/src/engine/physics/cloth/solver/cloth_step_instance.js +10 -3
  152. package/src/engine/physics/cloth/solver/constraint/cloth_leash_row.d.ts +1 -1
  153. package/src/engine/physics/cloth/solver/constraint/cloth_leash_row.d.ts.map +1 -1
  154. package/src/engine/physics/cloth/solver/constraint/cloth_leash_row.js +353 -346
  155. package/src/engine/physics/cloth/solver/constraint/cloth_self_row.d.ts +7 -5
  156. package/src/engine/physics/cloth/solver/constraint/cloth_self_row.d.ts.map +1 -1
  157. package/src/engine/physics/cloth/solver/constraint/cloth_self_row.js +7 -5
  158. package/src/engine/physics/cloth/wind/cloth_sample_air.d.ts +9 -9
  159. package/src/engine/physics/cloth/wind/cloth_sample_air.d.ts.map +1 -1
  160. package/src/engine/physics/cloth/wind/cloth_sample_air.js +26 -26
  161. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  162. package/src/engine/simulation/Ticker.d.ts +13 -0
  163. package/src/engine/simulation/Ticker.d.ts.map +1 -1
  164. package/src/engine/simulation/Ticker.js +43 -8
  165. package/src/shade/RENDERER_CONTRACT.md +8 -2
  166. package/src/shade/playground/mesh_row_ceiling/main.js +2 -1
  167. package/src/shade/playground/skinned_blas_refit/main.d.ts.map +1 -1
  168. package/src/shade/playground/skinned_blas_refit/main.js +11 -19
  169. package/src/shade/playground/skinned_blas_refit/place_character.d.ts +6 -3
  170. package/src/shade/playground/skinned_blas_refit/place_character.d.ts.map +1 -1
  171. package/src/shade/playground/skinned_blas_refit/place_character.js +90 -90
  172. package/src/shade/playground/skinned_mesh_soup/main.d.ts.map +1 -1
  173. package/src/shade/playground/skinned_mesh_soup/main.js +502 -509
  174. package/src/shade/playground/texture_encode/README.md +129 -109
  175. package/src/shade/playground/texture_encode/main.js +1430 -1430
  176. package/src/shade/playground/vgeo_runtime/README.md +5 -4
  177. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  178. package/src/shade/renderer/Renderer.js +6 -5
  179. package/src/shade/renderer/animation/GPUAnimationManager.d.ts +45 -14
  180. package/src/shade/renderer/animation/GPUAnimationManager.d.ts.map +1 -1
  181. package/src/shade/renderer/animation/GPUAnimationManager.js +316 -64
  182. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.d.ts +5 -0
  183. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.d.ts.map +1 -1
  184. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.js +11 -1
  185. package/src/shade/renderer/atmosphere/GPUSky.d.ts +12 -0
  186. package/src/shade/renderer/atmosphere/GPUSky.d.ts.map +1 -1
  187. package/src/shade/renderer/atmosphere/GPUSky.js +162 -147
  188. package/src/shade/renderer/geometry/BoxGeometry.d.ts +1 -11
  189. package/src/shade/renderer/geometry/BoxGeometry.d.ts.map +1 -1
  190. package/src/shade/renderer/geometry/BoxGeometry.js +6 -13
  191. package/src/shade/renderer/geometry/CapsuleGeometry.d.ts +19 -0
  192. package/src/shade/renderer/geometry/CapsuleGeometry.d.ts.map +1 -0
  193. package/src/shade/renderer/geometry/CapsuleGeometry.js +24 -0
  194. package/src/shade/renderer/geometry/ConeGeometry.d.ts +20 -0
  195. package/src/shade/renderer/geometry/ConeGeometry.d.ts.map +1 -0
  196. package/src/shade/renderer/geometry/ConeGeometry.js +33 -0
  197. package/src/shade/renderer/geometry/CylinderGeometry.d.ts +21 -0
  198. package/src/shade/renderer/geometry/CylinderGeometry.d.ts.map +1 -0
  199. package/src/shade/renderer/geometry/CylinderGeometry.js +35 -0
  200. package/src/shade/renderer/geometry/PlaneGeometry.d.ts +17 -0
  201. package/src/shade/renderer/geometry/PlaneGeometry.d.ts.map +1 -0
  202. package/src/shade/renderer/geometry/PlaneGeometry.js +22 -0
  203. package/src/shade/renderer/geometry/TorusGeometry.d.ts +18 -0
  204. package/src/shade/renderer/geometry/TorusGeometry.d.ts.map +1 -0
  205. package/src/shade/renderer/geometry/TorusGeometry.js +23 -0
  206. package/src/shade/renderer/geometry/UVSphereGeometry.d.ts +21 -0
  207. package/src/shade/renderer/geometry/UVSphereGeometry.d.ts.map +1 -0
  208. package/src/shade/renderer/geometry/UVSphereGeometry.js +34 -0
  209. package/src/shade/renderer/geometry/primitives/make_capsule_geometry.d.ts +19 -0
  210. package/src/shade/renderer/geometry/primitives/make_capsule_geometry.d.ts.map +1 -0
  211. package/src/shade/renderer/geometry/primitives/make_capsule_geometry.js +205 -0
  212. package/src/shade/renderer/geometry/primitives/make_cone_geometry.d.ts +21 -0
  213. package/src/shade/renderer/geometry/primitives/make_cone_geometry.d.ts.map +1 -0
  214. package/src/shade/renderer/geometry/primitives/make_cone_geometry.js +36 -0
  215. package/src/shade/renderer/geometry/primitives/make_cylinder_geometry.d.ts +1 -1
  216. package/src/shade/renderer/geometry/primitives/make_cylinder_geometry.d.ts.map +1 -1
  217. package/src/shade/renderer/geometry/primitives/make_cylinder_geometry.js +44 -9
  218. package/src/shade/renderer/geometry/primitives/make_uv_sphere_geometry.d.ts +20 -0
  219. package/src/shade/renderer/geometry/primitives/make_uv_sphere_geometry.d.ts.map +1 -0
  220. package/src/shade/renderer/geometry/primitives/make_uv_sphere_geometry.js +190 -0
  221. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.d.ts.map +1 -1
  222. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.js +7 -2
  223. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/graph_prefix_scan_csdldf.d.ts +26 -8
  224. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/graph_prefix_scan_csdldf.d.ts.map +1 -1
  225. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/graph_prefix_scan_csdldf.js +56 -39
  226. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/shader_prefix_scan_csdldf.d.ts +7 -0
  227. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/shader_prefix_scan_csdldf.d.ts.map +1 -1
  228. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/shader_prefix_scan_csdldf.js +46 -4
  229. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/test_prefix_sum.d.ts.map +1 -1
  230. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/test_prefix_sum.js +4 -2
  231. package/src/shade/renderer/gpu_primitive/sort/defs.d.ts +2 -2
  232. package/src/shade/renderer/gpu_primitive/sort/defs.js +79 -79
  233. package/src/shade/renderer/gpu_primitive/sort/graph_radix_sort.d.ts +1 -1
  234. package/src/shade/renderer/gpu_primitive/sort/graph_radix_sort.d.ts.map +1 -1
  235. package/src/shade/renderer/gpu_primitive/sort/graph_radix_sort.js +7 -3
  236. package/src/shade/renderer/lightmap/bake/shader_lightmap_denoise_sh.d.ts.map +1 -1
  237. package/src/shade/renderer/lightmap/bake/shader_lightmap_denoise_sh.js +10 -3
  238. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  239. package/src/shade/renderer/particles/DESIGN.md +13 -9
  240. package/src/shade/renderer/particles/GPUParticleSystem.js +1 -1
  241. package/src/shade/renderer/particles/coherence/graph_particle_bucket.d.ts +4 -3
  242. package/src/shade/renderer/particles/coherence/graph_particle_bucket.d.ts.map +1 -1
  243. package/src/shade/renderer/particles/coherence/graph_particle_bucket.js +200 -194
  244. package/src/shade/renderer/particles/graph_particles.d.ts.map +1 -1
  245. package/src/shade/renderer/particles/graph_particles.js +6 -2
  246. package/src/shade/renderer/particles/shaders/chunk_particle_lighting.d.ts +1 -1
  247. package/src/shade/renderer/particles/shaders/chunk_particle_lighting.js +1 -1
  248. package/src/shade/renderer/particles/warmup/graph_particle_warmup.d.ts.map +1 -1
  249. package/src/shade/renderer/particles/warmup/graph_particle_warmup.js +334 -329
  250. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
  251. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.d.ts.map +1 -1
  252. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.js +7 -2
  253. package/src/shade/renderer/rasterize/expand/mesh/graph_expand_meshes_to_meshlets.d.ts.map +1 -1
  254. package/src/shade/renderer/rasterize/expand/mesh/graph_expand_meshes_to_meshlets.js +16 -4
  255. package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.d.ts +3 -2
  256. package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.d.ts.map +1 -1
  257. package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.js +3 -2
  258. package/src/shade/renderer/scene/GPUSceneContext.d.ts +9 -1
  259. package/src/shade/renderer/scene/GPUSceneContext.d.ts.map +1 -1
  260. package/src/shade/renderer/scene/GPUSceneContext.js +23 -1
  261. package/src/shade/renderer/texture/COMPRESSED_TEXTURE_PLAN_2026_09_01.md +2444 -2345
  262. package/src/shade/renderer/texture/encode/chunk_astc_encode_block_4x4_rgb.d.ts.map +1 -1
  263. package/src/shade/renderer/texture/encode/chunk_astc_encode_block_4x4_rgb.js +312 -310
  264. package/src/shade/renderer/texture/encode/chunk_bc1_encode_block.d.ts +3 -3
  265. package/src/shade/renderer/texture/encode/chunk_bc1_encode_block.d.ts.map +1 -1
  266. package/src/shade/renderer/texture/encode/chunk_bc1_encode_block.js +383 -375
  267. package/src/shade/renderer/texture/encode/chunk_bc6h_encode_block_mode11.d.ts.map +1 -1
  268. package/src/shade/renderer/texture/encode/chunk_bc6h_encode_block_mode11.js +349 -346
  269. package/src/shade/renderer/texture/encode/chunk_bc7_encode_block.d.ts +58 -0
  270. package/src/shade/renderer/texture/encode/chunk_bc7_encode_block.d.ts.map +1 -0
  271. package/src/shade/renderer/texture/encode/chunk_bc7_encode_block.js +536 -0
  272. package/src/shade/renderer/texture/encode/chunk_bc7_encode_block_mode6.d.ts +21 -7
  273. package/src/shade/renderer/texture/encode/chunk_bc7_encode_block_mode6.d.ts.map +1 -1
  274. package/src/shade/renderer/texture/encode/chunk_bc7_encode_block_mode6.js +291 -327
  275. package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode1.d.ts +25 -0
  276. package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode1.d.ts.map +1 -0
  277. package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode1.js +99 -0
  278. package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode6.d.ts +5 -3
  279. package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode6.d.ts.map +1 -1
  280. package/src/shade/renderer/texture/encode/chunk_bc7_pack_mode6.js +47 -71
  281. package/src/shade/renderer/texture/encode/chunk_bc7_partition_2.d.ts +10 -0
  282. package/src/shade/renderer/texture/encode/chunk_bc7_partition_2.d.ts.map +1 -0
  283. package/src/shade/renderer/texture/encode/chunk_bc7_partition_2.js +50 -0
  284. package/src/shade/renderer/texture/encode/shader_texture_encode_bc7.d.ts +4 -5
  285. package/src/shade/renderer/texture/encode/shader_texture_encode_bc7.d.ts.map +1 -1
  286. package/src/shade/renderer/texture/encode/shader_texture_encode_bc7.js +7 -8
  287. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.d.ts +4 -1
  288. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.d.ts.map +1 -1
  289. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.js +74 -3
  290. package/src/shade/renderer/volumetrics/NOTES.md +1023 -957
  291. package/src/shade/renderer/volumetrics/chunk_volumetrics_irradiance_sh.d.ts +5 -4
  292. package/src/shade/renderer/volumetrics/chunk_volumetrics_irradiance_sh.d.ts.map +1 -1
  293. package/src/shade/renderer/volumetrics/chunk_volumetrics_irradiance_sh.js +5 -4
  294. package/src/shade/renderer/volumetrics/gi/chunk_volumetrics_gi.d.ts +1 -1
  295. package/src/shade/renderer/volumetrics/gi/chunk_volumetrics_gi.js +1 -1
  296. package/src/shade/renderer/volumetrics/gi/graph_build_froxel_gi.d.ts +1 -1
  297. package/src/shade/renderer/volumetrics/gi/graph_build_froxel_gi.js +1 -1
  298. package/src/shade/renderer/volumetrics/graph_build_froxel_irradiance.d.ts +41 -0
  299. package/src/shade/renderer/volumetrics/graph_build_froxel_irradiance.d.ts.map +1 -0
  300. package/src/shade/renderer/volumetrics/graph_build_froxel_irradiance.js +112 -0
  301. package/src/shade/renderer/volumetrics/graph_build_volumetrics.d.ts +9 -23
  302. package/src/shade/renderer/volumetrics/graph_build_volumetrics.d.ts.map +1 -1
  303. package/src/shade/renderer/volumetrics/graph_build_volumetrics.js +18 -126
  304. package/src/shade/renderer/volumetrics/shader_volumetrics_build_irradiance.d.ts +22 -0
  305. package/src/shade/renderer/volumetrics/shader_volumetrics_build_irradiance.d.ts.map +1 -0
  306. package/src/shade/renderer/volumetrics/shader_volumetrics_build_irradiance.js +228 -0
  307. package/src/shade/renderer/volumetrics/shader_volumetrics_build_lighting.d.ts.map +1 -1
  308. package/src/shade/renderer/volumetrics/shader_volumetrics_build_lighting.js +0 -53
  309. package/src/shade/renderer/water/chunk_water_transport.d.ts.map +1 -1
  310. package/src/shade/renderer/water/chunk_water_transport.js +7 -5
  311. package/src/shade/renderer/water/medium/GPUWaterBodies.d.ts.map +1 -1
  312. package/src/shade/renderer/water/medium/GPUWaterBodies.js +8 -2
  313. package/src/shade/renderer/water/optics/chunk_water_receiver_downwelling.d.ts +3 -2
  314. package/src/shade/renderer/water/optics/chunk_water_receiver_downwelling.d.ts.map +1 -1
  315. package/src/shade/renderer/water/optics/chunk_water_receiver_downwelling.js +3 -2
  316. package/src/shade/renderer/water/shader_water.d.ts.map +1 -1
  317. package/src/shade/renderer/water/shader_water.js +3 -1
  318. package/src/shade/renderer/water/surface/GPUWaterSurface.d.ts.map +1 -1
  319. package/src/shade/renderer/water/surface/GPUWaterSurface.js +3 -1
  320. package/src/shade/renderer/water/surface/chunk_water_surface_sample.d.ts +4 -3
  321. package/src/shade/renderer/water/surface/chunk_water_surface_sample.d.ts.map +1 -1
  322. package/src/shade/renderer/water/surface/chunk_water_surface_sample.js +17 -7
  323. package/src/shade/renderer/water/surface/graph_water_tessellation.d.ts.map +1 -1
  324. package/src/shade/renderer/water/surface/graph_water_tessellation.js +11 -4
  325. package/src/shade/renderer/water/surface/particles/GPUWaterParticles.d.ts.map +1 -1
  326. package/src/shade/renderer/water/surface/particles/GPUWaterParticles.js +93 -30
  327. package/src/shade/renderer/water/surface/particles/WATER_PARTICLE_STRUCT.d.ts.map +1 -1
  328. package/src/shade/renderer/water/surface/particles/WATER_PARTICLE_STRUCT.js +13 -5
  329. package/src/shade/renderer/water/surface/particles/chunk_water_particle.d.ts +29 -8
  330. package/src/shade/renderer/water/surface/particles/chunk_water_particle.d.ts.map +1 -1
  331. package/src/shade/renderer/water/surface/particles/chunk_water_particle.js +155 -30
  332. package/src/shade/renderer/water/surface/particles/chunk_water_particle_step.d.ts +6 -1
  333. package/src/shade/renderer/water/surface/particles/chunk_water_particle_step.d.ts.map +1 -1
  334. package/src/shade/renderer/water/surface/particles/chunk_water_particle_step.js +157 -39
  335. package/src/shade/renderer/water/surface/particles/shader_water_particles.d.ts +91 -21
  336. package/src/shade/renderer/water/surface/particles/shader_water_particles.d.ts.map +1 -1
  337. package/src/shade/renderer/water/surface/particles/shader_water_particles.js +442 -70
  338. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +11 -3
  339. package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
  340. package/src/shade/wgsl/emulator/WGSLLanguageCore.js +3 -0
  341. package/src/shade/wgsl/validate_wgsl_source.d.ts.map +1 -1
  342. package/src/shade/wgsl/validate_wgsl_source.js +74 -3
  343. package/src/engine/graphics3/register_instance_animation.d.ts +0 -114
  344. package/src/engine/graphics3/register_instance_animation.d.ts.map +0 -1
  345. package/src/engine/graphics3/register_instance_animation.js +0 -201
@@ -1,109 +1,129 @@
1
- # GPU block encoder
2
-
3
- A sampleable texture in, a block-compressed texture out, on the device — the runtime compression of
4
- the compressed-texture plan's §4.5, driven here on real hardware.
5
-
6
- This is tier 8 of the plan's testing ladder for the encoder, and the only tier with a GPU in it.
7
- Everything below runs device-free: the encoder chunk in the WGSL emulator against an exhaustive
8
- optimum, the whole kernel in the emulator against the chunk, the orchestration on the software
9
- device with its copies executing over host-written bytes. What none of that can answer is whether a
10
- real device takes the format and the padded rows, whether the texture ends up holding the blocks the
11
- shader wrote, and whether the hardware's own BC decoder agrees with the test decoder every number
12
- below is judged with.
13
-
14
- ## Running it
15
-
16
- ```bash
17
- npm run dev --workspace @woosh/meep-engine
18
- ```
19
-
20
- Then open `/src/shade/playground/texture_encode/index.html`, pick a target and press **Encode**. The
21
- synthetic source is the three spec fixtures — smooth, rough, mask — in the red, green and blue
22
- channels at 512x512 with a CPU-built mip chain, so the numbers here can be held against the ones the
23
- specs pin. Any image file can be dropped in through the file input instead.
24
-
25
- The page does not use the renderer: the renderer's frame loop needs immediate data, which not every
26
- browser build offers, and the encoder needs no frame. A `GraphicsContext` and a command context over
27
- a bare device are enough to record the encode, and everything else is readback.
28
-
29
- ## What it checks
30
-
31
- 1. **The device accepts the work.** `createTexture` with the block format, one dispatch, one
32
- `copyBufferToTexture` per level with rows padded to 256 bytes — inside a validation error scope,
33
- so a refusal is a message rather than a black texture.
34
- 2. **The texture holds the buffer.** Every level is copied back out with `copyTextureToBuffer` and
35
- compared byte for byte with the block buffer the shader wrote.
36
- 3. **The hardware decodes what the CPU decoder predicts.** Every level is read back through a
37
- `textureLoad` pass — the GPU's own decoder — and compared texel for texel with the test
38
- decoder. The specification writes BC4's interpolation in real arithmetic and leaves the
39
- precision to the hardware, which the probe below found up to seven levels from the test decoder
40
- on the widest six-value spans, so the verdict is the picture rather than a texel count: a level
41
- whose hardware decode is decibels under the CPU decoder's reading of the same bytes, one
42
- rounding forgiven, holds a wrong block. BC7 and BC6H decoders are bit-exact by specification and
43
- matched on every sample.
44
- 4. **The device against the emulator.** Level 0 is encoded a second time by the same chunk in the
45
- WGSL emulator, in f64, and the blocks are compared. A block that differs is not wrong: the f32
46
- arithmetic rounds a tie the other way, and the page says whether the device's choice decoded
47
- better, worse or the same.
48
-
49
- And the numbers the specs already pin, on the same fixtures: PSNR and worst texel against the source,
50
- per level — once against the CPU decoder's reading of the blocks and once against the hardware's.
51
-
52
- The third panel is **FLIP** — the tree's own `sampler2d_flip_ldr`, the renderer's regression gate —
53
- of the hardware's picture against the source at level 0, drawn through the magma map: black where
54
- a viewer flipping between the two would see nothing, yellow where they certainly would. Its pooled
55
- mean and weighted median are in the report. It compares the displayed bytes, which for BC6H is the
56
- tone-mapped picture and for a signed format the mid-grey-centred one, because FLIP judges what is
57
- seen. It runs whatever the size: it is a CPU pass on the page's own thread, half a second at
58
- 512x512 and twenty-two seconds at 2048x2048 here, the status says so while it runs, and the report
59
- line carries how long it took.
60
-
61
- The three panels share one view — the wheel zooms about the pointer, a drag pans, a double click
62
- refits — and one cursor: the open circle is the same texel on all three, and the line under the
63
- panels is what each holds there, in the format's own units, with the FLIP value beside them.
64
-
65
- **Probe hardware decoder** does the fourth check on its own, exhaustively: a 1024x1024 BC4 texture
66
- holding every pair of endpoints, read back at full precision, from which the interpolation weight at
67
- every index is fitted and the difference from the CPU decoder tabulated.
68
-
69
- ## What it measured
70
-
71
- NVIDIA Lovelace through Dawn, 2026-09-02:
72
-
73
- | target | source | blocks | PSNR, CPU / hardware decode | wall, record to done | first run, with pipeline compile |
74
- |---|---|---|---|---|---|
75
- | `bc4-r-unorm` | 512x512, 10 levels | 21,847 | 53.15 / 52.59 dB | 5.3 ms | 212 ms |
76
- | `bc4-r-unorm` | 2048x2048, 12 levels | 349,527 | 53.23 / 52.66 dB | 8.6 ms (650 MP/s) | 21 ms |
77
- | `bc5-rg-unorm` | 512x512, 10 levels | 21,847 | 45.24 / 44.69 dB | 4.1 ms | 504 ms |
78
- | `bc1-rgba-unorm` | 512x512 correlated colour | 21,847 | 41.53 / 41.51 dB | 7.2 ms | 526 ms |
79
- | `bc1-rgba-unorm` | 512x512 unrelated channels | 21,847 | 31.55 / 31.53 dB | 4.3 ms | 316 ms |
80
- | `bc7-rgba-unorm` | 512x512 correlated colour, cut out | 21,847 | 46.04 / 46.04 dB | 3.6 ms | 257 ms |
81
- | `bc7-rgba-unorm` | 2048x2048 unrelated channels | 349,527 | 33.41 / 33.41 dB | 8.2 ms (682 MP/s) | 20 ms |
82
- | `bc5-rg-unorm` | 512x512 normal map | 21,847 | 37.40 / 37.01 dB | 4.3 ms | 397 ms |
83
- | `bc5-rg-snorm` | 512x512 normal map, signed bytes | 21,847 | 31.43 / 30.96 dB (peak 127) | 3.9 ms | 453 ms |
84
- | `bc6h-rgb-ufloat` | 512x512 HDR, fourteen stops and a sun | 21,847 | 47.05 / 47.05 dB (over half bits) | 3.6 ms | 364 ms |
85
-
86
- BC6H's hardware decode, like BC7's, matched the CPU decoder on every sample: the format requires a
87
- bit-accurate decoder.
88
-
89
- `astc-4x4-unorm` is on the list and refused by this device before a texture is created — it
90
- samples no ASTC format. An ASTC device is the first thing to point the page at.
91
-
92
- BC7's hardware decode matched the CPU decoder on every sample of every level: its interpolation is
93
- fully specified, where BC4's is left to the implementation.
94
-
95
- Validation clean. Every level's blocks read back from the texture byte-identical to the block
96
- buffer, the tails included. Against the source at 2048², level 0: 53.23 dB by the CPU decoder,
97
- 52.66 dB as the hardware decodes it. The device and the f64 emulator chose the same block for 13,675
98
- of the 16,384 level-0 blocks of the 512² source; of the rest, 2,428 decode to the same error, 120
99
- better on the device, 161 worse.
100
-
101
- The hardware's BC4 decoder is `A + (B − A) · c / 257` over 16-bit endpoints, with c = 36, 72, 113,
102
- 144, 185, 221 for the eight-value mode and 48, 96, 161, 209 for the six-value one. Rounded to eight
103
- bits it agrees with the CPU decoder on 62.6% of palette entries, is one level off on 22.9%, and up
104
- to seven off on 0.04% — the widest six-value spans.
105
-
106
- Two things this page found that no device-free tier had, both about the same rule: a copy of a
107
- compressed level is sized in whole blocks against the level's *physical* extent, so a 2x2 mip is
108
- copied as 4x4 and a 2x2 copy is refused. The encoder's copies were wrong that way for one run, and
109
- `texture_write_level` had been wrong that way for every BC chain's tail since it was written.
1
+ # GPU block encoder
2
+
3
+ A sampleable texture in, a block-compressed texture out, on the device — the runtime compression of
4
+ the compressed-texture plan's §4.5, driven here on real hardware.
5
+
6
+ This is tier 8 of the plan's testing ladder for the encoder, and the only tier with a GPU in it.
7
+ Everything below runs device-free: the encoder chunk in the WGSL emulator against an exhaustive
8
+ optimum, the whole kernel in the emulator against the chunk, the orchestration on the software
9
+ device with its copies executing over host-written bytes. What none of that can answer is whether a
10
+ real device takes the format and the padded rows, whether the texture ends up holding the blocks the
11
+ shader wrote, and whether the hardware's own BC decoder agrees with the test decoder every number
12
+ below is judged with.
13
+
14
+ ## Running it
15
+
16
+ ```bash
17
+ npm run dev --workspace @woosh/meep-engine
18
+ ```
19
+
20
+ Then open `/src/shade/playground/texture_encode/index.html`, pick a target and press **Encode**. The
21
+ synthetic source is the three spec fixtures — smooth, rough, mask — in the red, green and blue
22
+ channels at 512x512 with a CPU-built mip chain, so the numbers here can be held against the ones the
23
+ specs pin. Any image file can be dropped in through the file input instead.
24
+
25
+ The page does not use the renderer: the renderer's frame loop needs immediate data, which not every
26
+ browser build offers, and the encoder needs no frame. A `GraphicsContext` and a command context over
27
+ a bare device are enough to record the encode, and everything else is readback.
28
+
29
+ ## What it checks
30
+
31
+ 1. **The device accepts the work.** `createTexture` with the block format, one dispatch, one
32
+ `copyBufferToTexture` per level with rows padded to 256 bytes — inside a validation error scope,
33
+ so a refusal is a message rather than a black texture.
34
+ 2. **The texture holds the buffer.** Every level is copied back out with `copyTextureToBuffer` and
35
+ compared byte for byte with the block buffer the shader wrote.
36
+ 3. **The hardware decodes what the CPU decoder predicts.** Every level is read back through a
37
+ `textureLoad` pass — the GPU's own decoder — and compared texel for texel with the test
38
+ decoder. The specification writes BC4's interpolation in real arithmetic and leaves the
39
+ precision to the hardware, which the probe below found up to seven levels from the test decoder
40
+ on the widest six-value spans, so the verdict is the picture rather than a texel count: a level
41
+ whose hardware decode is decibels under the CPU decoder's reading of the same bytes, one
42
+ rounding forgiven, holds a wrong block. BC7 and BC6H decoders are bit-exact by specification and
43
+ matched on every sample.
44
+ 4. **The device against the emulator.** Level 0 is encoded a second time by the same chunk in the
45
+ WGSL emulator, in f64, and the blocks are compared. A block that differs is not wrong: the f32
46
+ arithmetic rounds a tie the other way, and the page says whether the device's choice decoded
47
+ better, worse or the same.
48
+
49
+ And the numbers the specs already pin, on the same fixtures: PSNR and worst texel against the source,
50
+ per level — once against the CPU decoder's reading of the blocks and once against the hardware's.
51
+
52
+ The third panel is **FLIP** — the tree's own `sampler2d_flip_ldr`, the renderer's regression gate —
53
+ of the hardware's picture against the source at level 0, drawn through the magma map: black where
54
+ a viewer flipping between the two would see nothing, yellow where they certainly would. Its pooled
55
+ mean and weighted median are in the report. It compares the displayed bytes, which for BC6H is the
56
+ tone-mapped picture and for a signed format the mid-grey-centred one, because FLIP judges what is
57
+ seen. It runs whatever the size: it is a CPU pass on the page's own thread, half a second at
58
+ 512x512 and twenty-two seconds at 2048x2048 here, the status says so while it runs, and the report
59
+ line carries how long it took.
60
+
61
+ The three panels share one view — the wheel zooms about the pointer, a drag pans, a double click
62
+ refits — and one cursor: the open circle is the same texel on all three, and the line under the
63
+ panels is what each holds there, in the format's own units, with the FLIP value beside them.
64
+
65
+ **Probe hardware decoder** does the fourth check on its own, exhaustively: a 1024x1024 BC4 texture
66
+ holding every pair of endpoints, read back at full precision, from which the interpolation weight at
67
+ every index is fitted and the difference from the CPU decoder tabulated.
68
+
69
+ ## What it measured
70
+
71
+ NVIDIA Lovelace through Dawn, 2026-09-02:
72
+
73
+ | target | source | blocks | PSNR, CPU / hardware decode | wall, record to done | first run, with pipeline compile |
74
+ |---|---|---|---|---|---|
75
+ | `bc4-r-unorm` | 512x512, 10 levels | 21,847 | 53.15 / 52.59 dB | 5.3 ms | 212 ms |
76
+ | `bc4-r-unorm` | 2048x2048, 12 levels | 349,527 | 53.23 / 52.66 dB | 8.6 ms (650 MP/s) | 21 ms |
77
+ | `bc5-rg-unorm` | 512x512, 10 levels | 21,847 | 45.24 / 44.69 dB | 4.1 ms | 504 ms |
78
+ | `bc1-rgba-unorm` | 512x512 correlated colour | 21,847 | 41.52 / 41.50 dB | 5.2 ms | 360 ms |
79
+ | `bc1-rgba-unorm` | 512x512 unrelated channels | 21,847 | 31.54 / 31.52 dB | 5.7 ms | 471 ms |
80
+ | `bc7-rgba-unorm` | 512x512 correlated colour | 21,847 | 50.92 / 50.92 dB | 4.3 ms | 414 ms |
81
+ | `bc7-rgba-unorm` | 2048x2048 unrelated channels | 349,527 | 40.13 / 40.13 dB | 6.8 ms (822 MP/s) | 682 ms |
82
+ | `bc5-rg-unorm` | 512x512 normal map | 21,847 | 37.40 / 37.01 dB | 4.3 ms | 397 ms |
83
+ | `bc5-rg-snorm` | 512x512 normal map, signed bytes | 21,847 | 31.43 / 30.96 dB (peak 127) | 3.9 ms | 453 ms |
84
+ | `bc6h-rgb-ufloat` | 512x512 HDR, fourteen stops and a sun | 21,847 | 47.05 / 47.05 dB (over half bits) | 3.6 ms | 364 ms |
85
+
86
+ The `bc1-rgba-unorm` and `bc7-rgba-unorm` rows are from 2026-10-10, each in a fresh browser
87
+ profile, after the encoders' search was cut to fit (the plan's §9.20): PSNR moved by 0.01 dB for
88
+ BC1 and by 0.01 to 0.08 dB for BC7, and the code before the cut gave the September figures to the
89
+ hundredth the same day. The wall time does not show the cut. Record to done is mostly submission
90
+ and readback at these sizes — the 2048x2048 BC7 encode read from 5.9 to 14.3 ms across that day's
91
+ runs, before and after, and a 512x512 BC1 one from 3.2 to 6.5 — while by the plan's 4096²
92
+ timings the cut saves about a millisecond of kernel on a 2048x2048 chain. BC7's first run is
93
+ shorter, 293 to 308 ms before the cut and 210 to 238 after: a smaller shader to compile. The
94
+ September 2048x2048 BC7 row's 20 ms first run is too short to hold a compile, so that pipeline had
95
+ been built by an earlier run in the page; and its 512x512 row said "cut out" of a source that was
96
+ the opaque correlated colour, the only one the page has.
97
+
98
+ The `bc7-rgba-unorm` rows were measured again that evening, each in a fresh profile, once the
99
+ encoder chose between mode 6 and the partitioned mode 1 by estimate (the plan's §9.20): 45.96 to
100
+ 50.92 dB on the correlated colour and 33.40 to 40.13 on the unrelated channels, the hardware decode
101
+ equal to the CPU decoder's on every sample. The first run's compile is longer, 414 and 682 ms
102
+ against 238 and 210: the shader is bigger. The device-against-emulator check was skipped on those
103
+ runs, because a worktree's dev server does not serve the parser's wasm; the kernel's spec holds the
104
+ shader to the chunk block for block in the emulator instead.
105
+
106
+ BC6H's hardware decode, like BC7's, matched the CPU decoder on every sample: the format requires a
107
+ bit-accurate decoder.
108
+
109
+ `astc-4x4-unorm` is on the list and refused by this device before a texture is created — it
110
+ samples no ASTC format. An ASTC device is the first thing to point the page at.
111
+
112
+ BC7's hardware decode matched the CPU decoder on every sample of every level: its interpolation is
113
+ fully specified, where BC4's is left to the implementation.
114
+
115
+ Validation clean. Every level's blocks read back from the texture byte-identical to the block
116
+ buffer, the tails included. Against the source at 2048², level 0: 53.23 dB by the CPU decoder,
117
+ 52.66 dB as the hardware decodes it. The device and the f64 emulator chose the same block for 13,675
118
+ of the 16,384 level-0 blocks of the 512² source; of the rest, 2,428 decode to the same error, 120
119
+ better on the device, 161 worse.
120
+
121
+ The hardware's BC4 decoder is `A + (B − A) · c / 257` over 16-bit endpoints, with c = 36, 72, 113,
122
+ 144, 185, 221 for the eight-value mode and 48, 96, 161, 209 for the six-value one. Rounded to eight
123
+ bits it agrees with the CPU decoder on 62.6% of palette entries, is one level off on 22.9%, and up
124
+ to seven off on 0.04% — the widest six-value spans.
125
+
126
+ Two things this page found that no device-free tier had, both about the same rule: a copy of a
127
+ compressed level is sized in whole blocks against the level's *physical* extent, so a 2x2 mip is
128
+ copied as 4x4 and a 2x2 copy is refused. The encoder's copies were wrong that way for one run, and
129
+ `texture_write_level` had been wrong that way for every BC chain's tail since it was written.