@woosh/meep-engine 3.25.0 → 3.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (295) hide show
  1. package/package.json +1 -1
  2. package/src/core/binary/lz4/LZ4_HIGH_COMPRESSION_PLAN_2026_09_14.md +542 -0
  3. package/src/core/binary/lz4/LZ4_LEVEL.d.ts +33 -0
  4. package/src/core/binary/lz4/LZ4_LEVEL.d.ts.map +1 -0
  5. package/src/core/binary/lz4/LZ4_LEVEL.js +32 -0
  6. package/src/core/binary/lz4/lz4_compress_block_at_level.d.ts +33 -0
  7. package/src/core/binary/lz4/lz4_compress_block_at_level.d.ts.map +1 -0
  8. package/src/core/binary/lz4/lz4_compress_block_at_level.js +47 -0
  9. package/src/core/binary/lz4/lz4_compress_block_hc.d.ts +40 -0
  10. package/src/core/binary/lz4/lz4_compress_block_hc.d.ts.map +1 -0
  11. package/src/core/binary/lz4/lz4_compress_block_hc.js +1382 -0
  12. package/src/core/binary/lz4/lz4_decompress_block.d.ts +2 -1
  13. package/src/core/binary/lz4/lz4_decompress_block.d.ts.map +1 -1
  14. package/src/core/binary/lz4/lz4_decompress_block.js +31 -6
  15. package/src/core/geom/3d/shape/HeightMapShape3D.d.ts +66 -0
  16. package/src/core/geom/3d/shape/HeightMapShape3D.d.ts.map +1 -1
  17. package/src/core/geom/3d/shape/HeightMapShape3D.js +314 -20
  18. package/src/core/geom/3d/shape/PosedShape3D.d.ts.map +1 -1
  19. package/src/core/geom/3d/shape/PosedShape3D.js +57 -0
  20. package/src/core/geom/3d/shape/TransformedShape3D.d.ts.map +1 -1
  21. package/src/core/geom/3d/shape/TransformedShape3D.js +102 -0
  22. package/src/core/geom/3d/shape/UnionShape3D.d.ts.map +1 -1
  23. package/src/core/geom/3d/shape/UnionShape3D.js +64 -0
  24. package/src/engine/physics/cloth/MEASUREMENTS.md +582 -0
  25. package/src/engine/physics/cloth/PLAN.md +330 -49
  26. package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts +84 -17
  27. package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts.map +1 -1
  28. package/src/engine/physics/cloth/collider/ClothColliderIndex.js +451 -42
  29. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts +65 -7
  30. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts.map +1 -1
  31. package/src/engine/physics/cloth/ecs/ClothInstance.js +72 -8
  32. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts +25 -4
  33. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts.map +1 -1
  34. package/src/engine/physics/cloth/ecs/ClothSystem.js +75 -8
  35. package/src/engine/physics/cloth/ecs/ClothWorld.d.ts +41 -4
  36. package/src/engine/physics/cloth/ecs/ClothWorld.d.ts.map +1 -1
  37. package/src/engine/physics/cloth/ecs/ClothWorld.js +207 -63
  38. package/src/engine/physics/cloth/ecs/WorkerClothSystem.d.ts +10 -0
  39. package/src/engine/physics/cloth/ecs/WorkerClothSystem.d.ts.map +1 -1
  40. package/src/engine/physics/cloth/ecs/WorkerClothSystem.js +17 -1
  41. package/src/engine/physics/cloth/ecs/cloth_dynamics_map.d.ts +27 -3
  42. package/src/engine/physics/cloth/ecs/cloth_dynamics_map.d.ts.map +1 -1
  43. package/src/engine/physics/cloth/ecs/cloth_dynamics_map.js +28 -3
  44. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts +75 -10
  45. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts.map +1 -1
  46. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.js +131 -12
  47. package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts +19 -0
  48. package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts.map +1 -1
  49. package/src/engine/physics/cloth/ecs/cloth_seed_rig.js +249 -201
  50. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts +21 -0
  51. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts.map +1 -1
  52. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.js +62 -1
  53. package/src/engine/physics/cloth/ecs/cloth_write_back.d.ts.map +1 -1
  54. package/src/engine/physics/cloth/ecs/cloth_write_back.js +18 -10
  55. package/src/engine/physics/cloth/playground/collide_main.js +1 -1
  56. package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts +29 -8
  57. package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts.map +1 -1
  58. package/src/engine/physics/cloth/solver/cloth_contact_find.js +37 -9
  59. package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts +12 -2
  60. package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts.map +1 -1
  61. package/src/engine/physics/cloth/solver/cloth_solver_constants.js +12 -2
  62. package/src/engine/physics/cloth/solver/cloth_step_instance.js +1 -1
  63. package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.d.ts +9 -2
  64. package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.d.ts.map +1 -1
  65. package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.js +9 -2
  66. package/src/engine/physics/cloth/wind/AbstractClothWind.d.ts +23 -9
  67. package/src/engine/physics/cloth/wind/AbstractClothWind.d.ts.map +1 -1
  68. package/src/engine/physics/cloth/wind/AbstractClothWind.js +23 -9
  69. package/src/engine/physics/cloth/wind/ClothAmbientWind.d.ts +7 -5
  70. package/src/engine/physics/cloth/wind/ClothAmbientWind.d.ts.map +1 -1
  71. package/src/engine/physics/cloth/wind/ClothAmbientWind.js +12 -9
  72. package/src/engine/physics/cloth/wind/ClothFluidWind.d.ts.map +1 -1
  73. package/src/engine/physics/cloth/wind/ClothFluidWind.js +5 -2
  74. package/src/engine/physics/cloth/wind/cloth_sample_air.d.ts +7 -2
  75. package/src/engine/physics/cloth/wind/cloth_sample_air.d.ts.map +1 -1
  76. package/src/engine/physics/cloth/wind/cloth_sample_air.js +12 -5
  77. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  78. package/src/shade/playground/vgeo_runtime/README.md +167 -22
  79. package/src/shade/playground/vgeo_runtime/index.html +112 -62
  80. package/src/shade/playground/vgeo_runtime/main.js +660 -83
  81. package/src/shade/playground/vgeo_viewer/sample_asset.d.ts.map +1 -1
  82. package/src/shade/playground/vgeo_viewer/sample_asset.js +19 -2
  83. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.d.ts +11 -0
  84. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.d.ts.map +1 -1
  85. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.js +16 -8
  86. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts.map +1 -1
  87. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.js +16 -11
  88. package/src/shade/renderer/geometry/virtual/VGEO_FORMAT.md +73 -5
  89. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md +26 -15
  90. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_PLAN.md +5 -3
  91. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts +18 -0
  92. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts.map +1 -1
  93. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.js +20 -0
  94. package/src/shade/renderer/geometry/virtual/build/vgeo_assemble_pages.d.ts.map +1 -1
  95. package/src/shade/renderer/geometry/virtual/build/vgeo_assemble_pages.js +56 -9
  96. package/src/shade/renderer/geometry/virtual/build/vgeo_build.d.ts.map +1 -1
  97. package/src/shade/renderer/geometry/virtual/build/vgeo_build.js +1 -0
  98. package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.d.ts +22 -0
  99. package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.d.ts.map +1 -1
  100. package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.js +24 -0
  101. package/src/shade/renderer/geometry/virtual/format/dag/VirtualGeometryCluster.d.ts +12 -0
  102. package/src/shade/renderer/geometry/virtual/format/dag/VirtualGeometryCluster.d.ts.map +1 -1
  103. package/src/shade/renderer/geometry/virtual/format/dag/VirtualGeometryCluster.js +13 -0
  104. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_encode_frame_blob.d.ts +8 -1
  105. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_encode_frame_blob.d.ts.map +1 -1
  106. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_encode_frame_blob.js +11 -3
  107. package/src/shade/renderer/geometry/virtual/format/header/VGEO_FORMAT_VERSION.d.ts +9 -0
  108. package/src/shade/renderer/geometry/virtual/format/header/VGEO_FORMAT_VERSION.d.ts.map +1 -1
  109. package/src/shade/renderer/geometry/virtual/format/header/VGEO_FORMAT_VERSION.js +10 -1
  110. package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_ENTRY_COUNT.d.ts +18 -0
  111. package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_ENTRY_COUNT.d.ts.map +1 -0
  112. package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_ENTRY_COUNT.js +17 -0
  113. package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_REF.d.ts +8 -0
  114. package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_REF.d.ts.map +1 -0
  115. package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_REF.js +7 -0
  116. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PAGE_OFFSET.d.ts +3 -0
  117. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PAGE_OFFSET.js +16 -0
  118. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_ENTRY_SIZE.d.ts +14 -0
  119. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_ENTRY_SIZE.d.ts.map +1 -0
  120. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_ENTRY_SIZE.js +13 -0
  121. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_PAGE_ENTRY_SIZE.d.ts +11 -0
  122. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_PAGE_ENTRY_SIZE.d.ts.map +1 -0
  123. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_PAGE_ENTRY_SIZE.js +10 -0
  124. package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.d.ts +20 -0
  125. package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.d.ts.map +1 -1
  126. package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.js +20 -2
  127. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerHeader.d.ts +4 -0
  128. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerHeader.d.ts.map +1 -1
  129. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerHeader.js +4 -0
  130. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.d.ts +29 -3
  131. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.d.ts.map +1 -1
  132. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.js +81 -122
  133. package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.d.ts +40 -0
  134. package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.d.ts.map +1 -1
  135. package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.js +44 -0
  136. package/src/shade/renderer/geometry/virtual/format/read/VGeoPageFetcherCore.d.ts +69 -0
  137. package/src/shade/renderer/geometry/virtual/format/read/VGeoPageFetcherCore.d.ts.map +1 -0
  138. package/src/shade/renderer/geometry/virtual/format/read/VGeoPageFetcherCore.js +236 -0
  139. package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.d.ts +14 -0
  140. package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.d.ts.map +1 -1
  141. package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.js +15 -0
  142. package/src/shade/renderer/geometry/virtual/format/read/vgeo_byte_source_from_descriptor.d.ts +31 -0
  143. package/src/shade/renderer/geometry/virtual/format/read/vgeo_byte_source_from_descriptor.d.ts.map +1 -0
  144. package/src/shade/renderer/geometry/virtual/format/read/vgeo_byte_source_from_descriptor.js +32 -0
  145. package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.d.ts +10 -0
  146. package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.d.ts.map +1 -1
  147. package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.js +21 -1
  148. package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_transfer.d.ts +15 -0
  149. package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_transfer.d.ts.map +1 -0
  150. package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_transfer.js +84 -0
  151. package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_worker_serve.d.ts +22 -0
  152. package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_worker_serve.d.ts.map +1 -0
  153. package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_worker_serve.js +96 -0
  154. package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_page.d.ts.map +1 -1
  155. package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_page.js +55 -0
  156. package/src/shade/renderer/geometry/virtual/format/vgeo_validate_container.d.ts.map +1 -1
  157. package/src/shade/renderer/geometry/virtual/format/vgeo_validate_container.js +202 -13
  158. package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.d.ts.map +1 -1
  159. package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.js +147 -10
  160. package/src/shade/renderer/geometry/virtual/runtime/CUT_PLAN_2026_09_14.md +637 -0
  161. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryPool.d.ts +33 -36
  162. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryPool.d.ts.map +1 -1
  163. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryPool.js +109 -193
  164. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.d.ts +58 -28
  165. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.d.ts.map +1 -1
  166. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.js +77 -105
  167. package/src/shade/renderer/geometry/virtual/runtime/REVIEW_LEDGER.md +37 -0
  168. package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN.md +105 -22
  169. package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN_2026_09_14.md +548 -0
  170. package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.d.ts +29 -50
  171. package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.d.ts.map +1 -1
  172. package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.js +47 -489
  173. package/src/shade/renderer/geometry/virtual/runtime/VGeoPageFetcher.d.ts +84 -0
  174. package/src/shade/renderer/geometry/virtual/runtime/VGeoPageFetcher.d.ts.map +1 -0
  175. package/src/shade/renderer/geometry/virtual/runtime/VGeoPageFetcher.js +393 -0
  176. package/src/shade/renderer/geometry/virtual/runtime/VGeoResidency.d.ts +234 -0
  177. package/src/shade/renderer/geometry/virtual/runtime/VGeoResidency.d.ts.map +1 -0
  178. package/src/shade/renderer/geometry/virtual/runtime/VGeoResidency.js +1363 -0
  179. package/src/shade/renderer/geometry/virtual/runtime/VGeoResidencyOptions.d.ts +81 -0
  180. package/src/shade/renderer/geometry/virtual/runtime/VGeoResidencyOptions.d.ts.map +1 -0
  181. package/src/shade/renderer/geometry/virtual/runtime/VGeoResidencyOptions.js +89 -0
  182. package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.d.ts +53 -34
  183. package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.d.ts.map +1 -1
  184. package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.js +407 -124
  185. package/src/shade/renderer/geometry/virtual/runtime/VGeoViewCut.d.ts +100 -0
  186. package/src/shade/renderer/geometry/virtual/runtime/VGeoViewCut.d.ts.map +1 -0
  187. package/src/shade/renderer/geometry/virtual/runtime/VGeoViewCut.js +219 -0
  188. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_EXPAND.d.ts +17 -0
  189. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_EXPAND.d.ts.map +1 -0
  190. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_EXPAND.js +47 -0
  191. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_FLAG_COARSEN.d.ts +20 -0
  192. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_FLAG_COARSEN.d.ts.map +1 -0
  193. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_FLAG_COARSEN.js +19 -0
  194. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_PARAMS_STRUCT.d.ts.map +1 -1
  195. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_PARAMS_STRUCT.js +30 -12
  196. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_access.d.ts.map +1 -1
  197. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_access.js +15 -0
  198. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_collect.d.ts.map +1 -1
  199. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_collect.js +18 -1
  200. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_prepare.d.ts.map +1 -1
  201. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_prepare.js +5 -15
  202. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_remainder.d.ts +3 -0
  203. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_remainder.d.ts.map +1 -0
  204. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_remainder.js +77 -0
  205. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_reseed.d.ts +3 -0
  206. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_reseed.d.ts.map +1 -0
  207. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_reseed.js +186 -0
  208. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_seed.d.ts.map +1 -1
  209. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_seed.js +20 -8
  210. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_traverse.d.ts.map +1 -1
  211. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_traverse.js +580 -188
  212. package/src/shade/renderer/geometry/virtual/runtime/cut/vgeo_cut_feedback_layout.d.ts +15 -18
  213. package/src/shade/renderer/geometry/virtual/runtime/cut/vgeo_cut_feedback_layout.d.ts.map +1 -1
  214. package/src/shade/renderer/geometry/virtual/runtime/cut/vgeo_cut_feedback_layout.js +19 -28
  215. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.d.ts.map +1 -1
  216. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.js +45 -25
  217. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT.d.ts +1 -0
  218. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT.js +11 -0
  219. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT_COUNT.js +1 -1
  220. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_FEEDBACK_OFFSET.d.ts +0 -1
  221. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_FEEDBACK_OFFSET.js +12 -10
  222. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_OFFSET.d.ts +1 -0
  223. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_OFFSET.js +8 -0
  224. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_WORDS.d.ts +7 -2
  225. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_WORDS.d.ts.map +1 -1
  226. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_WORDS.js +8 -3
  227. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_OFFSET.d.ts +2 -0
  228. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_OFFSET.js +19 -0
  229. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_WORDS.d.ts.map +1 -1
  230. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_WORDS.js +1 -1
  231. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_OFFSET.d.ts +5 -0
  232. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_OFFSET.d.ts.map +1 -0
  233. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_OFFSET.js +22 -0
  234. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_WORDS.d.ts +14 -0
  235. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_WORDS.d.ts.map +1 -0
  236. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_WORDS.js +13 -0
  237. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_TARGET_PARENT_BIT.d.ts +17 -0
  238. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_TARGET_PARENT_BIT.d.ts.map +1 -0
  239. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_TARGET_PARENT_BIT.js +16 -0
  240. package/src/shade/renderer/geometry/virtual/runtime/make_vgeo_page_worker.d.ts +15 -0
  241. package/src/shade/renderer/geometry/virtual/runtime/make_vgeo_page_worker.d.ts.map +1 -0
  242. package/src/shade/renderer/geometry/virtual/runtime/make_vgeo_page_worker.js +16 -0
  243. package/src/shade/renderer/geometry/virtual/runtime/vgeo_frontier_words.d.ts +23 -0
  244. package/src/shade/renderer/geometry/virtual/runtime/vgeo_frontier_words.d.ts.map +1 -0
  245. package/src/shade/renderer/geometry/virtual/runtime/vgeo_frontier_words.js +28 -0
  246. package/src/shade/renderer/geometry/virtual/runtime/vgeo_page.worker.d.ts +2 -0
  247. package/src/shade/renderer/geometry/virtual/runtime/vgeo_page.worker.d.ts.map +1 -0
  248. package/src/shade/renderer/geometry/virtual/runtime/vgeo_page.worker.js +13 -0
  249. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_block_words.d.ts +10 -5
  250. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_block_words.d.ts.map +1 -1
  251. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_block_words.js +15 -6
  252. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_write_page_block.d.ts +6 -1
  253. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_write_page_block.d.ts.map +1 -1
  254. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_write_page_block.js +38 -1
  255. package/src/shade/renderer/global_illumination/sharc/shader/shader_sharc_evict.d.ts.map +1 -1
  256. package/src/shade/renderer/global_illumination/sharc/shader/shader_sharc_evict.js +4 -3
  257. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  258. package/src/shade/renderer/particles/shaders/shader_particle_emit.d.ts.map +1 -1
  259. package/src/shade/renderer/particles/shaders/shader_particle_emit.js +6 -3
  260. package/src/shade/renderer/particles/shaders/shader_particle_simulate.d.ts.map +1 -1
  261. package/src/shade/renderer/particles/shaders/shader_particle_simulate.js +6 -3
  262. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
  263. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.d.ts.map +1 -1
  264. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.js +12 -4
  265. package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.d.ts +2 -0
  266. package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.d.ts.map +1 -1
  267. package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.js +58 -57
  268. package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_mesh_filter_2way.d.ts.map +1 -1
  269. package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_mesh_filter_2way.js +3 -5
  270. package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_meshlet_filter_1way_full.d.ts.map +1 -1
  271. package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_meshlet_filter_1way_full.js +3 -4
  272. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.d.ts.map +1 -1
  273. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.js +3 -4
  274. package/src/shade/renderer/rasterize/expand/pass0/pass_mesh_cull.d.ts.map +1 -1
  275. package/src/shade/renderer/rasterize/expand/pass0/pass_mesh_cull.js +7 -7
  276. package/src/shade/renderer/rasterize/fast/graph_extract_meshes_from_bucket.d.ts.map +1 -1
  277. package/src/shade/renderer/rasterize/fast/graph_extract_meshes_from_bucket.js +83 -78
  278. package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.d.ts.map +1 -1
  279. package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.js +7 -1
  280. package/src/shade/renderer/rasterize/standard/graph_rasterize_remaining_opaque.d.ts.map +1 -1
  281. package/src/shade/renderer/rasterize/standard/graph_rasterize_remaining_opaque.js +7 -1
  282. package/src/shade/renderer/scene/GPUSceneContext.d.ts +22 -2
  283. package/src/shade/renderer/scene/GPUSceneContext.d.ts.map +1 -1
  284. package/src/shade/renderer/scene/GPUSceneContext.js +59 -4
  285. package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.d.ts.map +1 -1
  286. package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.js +92 -16
  287. package/src/shade/renderer/view/GPUViewContext.d.ts +5 -0
  288. package/src/shade/renderer/view/GPUViewContext.d.ts.map +1 -1
  289. package/src/shade/renderer/view/GPUViewContext.js +21 -0
  290. package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
  291. package/src/shade/wgsl/emulator/WGSLLanguageCore.js +74 -3
  292. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyManager.js +0 -723
  293. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyOptions.js +0 -50
  294. package/src/shade/renderer/shader/chunk/jobs/NOTES.md +0 -47
  295. package/src/shade/renderer/shader/chunk/jobs/chunk_job_system.js +0 -102
@@ -12,36 +12,95 @@ proves the DAG, the format and the residency clamp, and by construction it prove
12
12
  engine. This page proves the engine seam and nothing about the DAG, because the DAG has its own
13
13
  tests and its own oracle.
14
14
 
15
+ And it proves one thing neither the specs nor the viewer can, which is what the surface **looks
16
+ like**. The viewer draws with `cullMode: 'none'` and colours its cut per cluster; this page draws
17
+ through a `Front`-sided standard material with a light on it. That is the difference that caught
18
+ the shared sample torus being wound inside-out — the near surface culled away, the far inner wall
19
+ showing through the hole where it should have been, and normals pointing into the tube so what
20
+ survived was lit from inside. Eighteen thousand specs and a second playground had drawn that
21
+ container without a single one of them being able to notice.
22
+
23
+ ## How it is lit, and why that is not decoration
24
+
25
+ A sun and an **environment map** (`load_default_environment`, the same octahedral sky eight other
26
+ playgrounds light themselves with), and **TAA on**.
27
+
28
+ Both are here for the geometry rather than for the picture. A directional light alone puts every
29
+ surface facing away from it at ambient zero, which is precisely the silhouette and the creases —
30
+ the places a cut is worth looking at — and a converted asset arrives with normals and no material
31
+ authoring, so the environment is most of what there is to shade it with. TAA is the other half: a
32
+ cut is re-selected every frame against a threshold in *pixels*, so the seams between two levels of
33
+ detail land on different pixels from one frame to the next, and without a temporal filter every one
34
+ of them is an aliased edge that crawls. The crawl reads as the cut being unstable when it is the
35
+ rasterizer being point-sampled.
36
+
37
+ Neither costs a reading. TAA runs downstream of the G-buffer, long after the cut has been selected
38
+ and drawn, and its sub-pixel jitter does not move the cut: the τ table below is identical with it on
39
+ and off. The environment is not awaited — `test_assets/` is gitignored, so a checkout without it
40
+ gets the sun alone and still draws every triangle the cut selected.
41
+
42
+ **Not the GPU sky, and that is worth writing down.** `renderer/atmosphere/GPUSky.js` and
43
+ `view/GPUViewSkyContext.js` would be the natural source for this and are **not reachable**: nothing
44
+ in the engine constructs either, `GPUSceneContext` has no `sky` for `GPUViewSkyContext.update` to
45
+ ask for, and `Renderer` does not mention the atmosphere at all. Reviving it is not a playground's
46
+ change — the sky produces an already-convolved GPU texture with `SPHERE_PROBE_MIPMAP_LEVELS` mips,
47
+ while `GPULightCollection` builds its environment privately from a CPU `ShadeTexture` and convolves
48
+ a full mip chain itself, so the two do not meet without a new way to hand that class a GPU-side
49
+ environment. That is a lighting change every scene in the engine would take, and it wants its own
50
+ piece of work.
51
+
15
52
  ## What it shows
16
53
 
17
- The container is built in the page and opened holding **only its root page**. Everything else
18
- arrives because the cut asked for it: a clamped cluster emits a want, the want names the page it
19
- was discovered through, the feedback readback resolves it to a byte range out of that page's own
20
- child table, and the page installs. Nothing is prefetched and no directory is read.
54
+ A container is opened holding **only its root page**. Everything else arrives because the cut asked
55
+ for it: a clamped cluster emits a want, the want names the page it was discovered through, the
56
+ feedback readback resolves it to a byte range out of that page's own child table, and the page
57
+ installs. Nothing is prefetched and no directory is read.
58
+
59
+ The one the page loads itself is built in the page, so there is something to look at without a file.
60
+ It is not what the page is *for*: **drop a `.vgeo` on the window**, or open the page at
61
+ `?file=<url>`, and that container is swapped for a real one. A sample torus is thirteen pages and a
62
+ converted asset is thousands, and the claim being made here is about the second.
21
63
 
22
- Measured on an nvidia/lovelace adapter, a 128×48 torus at 64 KB pages — 13 pages, built in ~0.5 s
23
- in-page — and **re-measured on the same adapter after the review campaign**, which rewrote the VRAM
24
- tier onto fixed-stride page slots, moved selectability off the RAM tier, corrected the near plane's
25
- sign and replaced the scale correction. Every row is identical:
64
+ Measured on an nvidia/lovelace adapter, a 128×48 torus at 64 KB pages — 13 pages, built in ~0.4 s
65
+ in-page — at a render target of 978×546. **The viewport is part of the measurement now**: τ is a
66
+ count of render-target pixels, the canvas follows the window, so a row of this table without the
67
+ resolution beside it is half a reading.
26
68
 
27
69
  | τ (px) | drawn clusters | pages visited | clamped | wavefronts | queue remaining |
28
70
  |---:|---:|---:|---:|---:|---:|
29
- | 0.5 | 50 | 9 | 0 | 14 | 0 |
30
- | 1 | 31 | 8 | 0 | 14 | 0 |
31
- | 2 | 18 | 6 | 0 | 11 | 0 |
32
- | 4 | 17 | 6 | 0 | 11 | 0 |
33
- | 8 | 9 | 5 | 0 | 8 | 0 |
34
- | 16 | 8 | 5 | 0 | 8 | 0 |
71
+ | 0.5 | 38 | 9 | 0 | 14 | 0 |
72
+ | 1 | 18 | 6 | 0 | 11 | 0 |
73
+ | 2 | 15 | 6 | 0 | 11 | 0 |
74
+ | 4 | 9 | 5 | 0 | 8 | 0 |
75
+ | 8 | 6 | 5 | 0 | 8 | 0 |
76
+ | 16 | 4 | 3 | 0 | 6 | 0 |
35
77
 
36
- The last two columns are new and are what the review's M8 was about: the descent ran fourteen
37
- wavefronts at its deepest against a budget of 64, and stopped with nothing still queued. A non-zero
38
- `queue remaining` is the one reading here that means a **hole** rather than a coarser surface.
78
+ The last two columns are what the review's M8 was about: the descent ran fourteen wavefronts at its
79
+ deepest against a budget of 64, and stopped with nothing still queued. A non-zero `queue remaining`
80
+ is the one reading here that means a **hole** rather than a coarser surface.
39
81
 
40
82
  The cut is monotone in τ and it is a *fraction* of the asset at every setting, which is design §1's
41
83
  whole claim: rendering cost is a function of the threshold and the resolution, not of the source
42
- triangle count. Residency settles at 9 of 13 pages and 230 KB — the four it never fetches are the
84
+ triangle count. Residency settles at 9 of 13 pages and 231 KB — the four it never fetches are the
43
85
  ones the cut never wanted.
44
86
 
87
+ The same claim, on the largest container of a converted 2,975-asset set — 920 MB, 17,172 pages,
88
+ 27,960,383 source triangles, served over HTTP by range requests at `?file=`:
89
+
90
+ | | |
91
+ |---|---:|
92
+ | drawn clusters | 10,766 |
93
+ | pages resident | 1,691 of 17,172 |
94
+ | bytes read | 87.6 MB of 920.7 MB |
95
+ | clamped | 0 |
96
+ | refused installs | 0 |
97
+ | opened in | 5 ms |
98
+
99
+ Nine and a half per cent of the file, and the container was on screen five milliseconds after its
100
+ first range came back. `clamped` reaching zero is the streaming having finished rather than the
101
+ budget having given up — which is a distinction the panel can now make, because `refused` is beside
102
+ it.
103
+
45
104
  Two readings are worth watching for what they say about the loop rather than the picture:
46
105
 
47
106
  - **`clamped` goes to zero.** The first frames draw a coarse, watertight surface because the pages
@@ -52,11 +111,87 @@ Two readings are worth watching for what they say about the loop rather than the
52
111
  costs streaming latency and nothing on screen, and a loop that insisted on a reading every frame
53
112
  would stall the frame it was reading.
54
113
 
114
+ ## What residency costs, and what it used to
115
+
116
+ The numbers above were taken with the tier nowhere near full. The reading that matters for a
117
+ runtime is the one with the tier full and the camera moving, and until 2026-09-14 it was
118
+ disqualifying: on this same container at 4,096 slots, zoomed in on a rosette, a DevTools trace had
119
+ twenty-four main-thread tasks over 50 ms in five and a half seconds, the longest 637 ms, `refused`
120
+ at 4.1 million and `pages visited` at 4,044 of 4,096 — every resident page touched every frame, so
121
+ nothing could be evicted, while selectability was recomputed over the whole geometry on every
122
+ install and every evict. `RUNTIME_PLAN_2026_09_14.md` in `runtime/` is the diagnosis and the
123
+ rebuild.
124
+
125
+ Measured after it, on an nvidia/lovelace adapter at 1258×646, a tour of eight rosettes held five
126
+ seconds each, twice round, then the rosette at rest:
127
+
128
+ | | before | after |
129
+ |---|---:|---:|
130
+ | main-thread tasks over 50 ms | 24 in 5.5 s, longest 637 ms | 4 in 150 s, longest 115 ms |
131
+ | `refused`, whole run | 4,166,982 | 999, over 3,009 evictions |
132
+ | `clamped` at rest, zoomed in | 1,334 | 0 |
133
+ | `pages visited` zoomed in | 4,044 of 4,096 | 2,000–3,200 of 4,096 |
134
+ | frame time zoomed in | — | p50 8.3 ms, p95 12.6 ms |
135
+ | page fetches on workers | 0 | all of them |
136
+
137
+ The panel's `RAM evicted`, `fetching` and `worker fetches` rows are new with it, and `refused` is
138
+ the reading to keep watching: it climbs only while the tier is full of pages the cut still draws
139
+ from, which is a budget saying no and not a tier scanning.
140
+
141
+ Two things the tour still shows. The four long tasks left are `GPUMeshletManager` compactions —
142
+ a refused allocation with free space behind it rebuilds every batch, which is the one O(resident)
143
+ event the rebuild deferred. And under a vite dev server the first seconds after a container opens
144
+ stall while the four page-fetch workers' module graphs are served; a bundled build does not pay
145
+ that.
146
+
147
+ ## Putting an asset in it
148
+
149
+ Drop a `.vgeo` anywhere on the window, or open the page at `?file=/some/asset.vgeo` — a URL source
150
+ reads by `Range` request, so a container is opened out of its header and root page rather than
151
+ downloaded. Either way the asset on screen is retired first: its mesh row, its entity, its VRAM
152
+ pages and its place in the RAM tier's budget all go back, and the camera reframes on the new
153
+ container's own bounding sphere, which is the difference between a torus a unit across and a
154
+ building thirty metres up.
155
+
156
+ Two refusals are worth recognising, because both leave what is on screen exactly as it was and say
157
+ so in the panel rather than clearing the page:
158
+
159
+ - **"this container makes no promise about its own [page size]"** — built before `FORMAT` §11.14, so
160
+ its pages may be over the size its header names, and this tier lays out fixed-stride slots.
161
+ Rebuild it.
162
+ - **"this container's pages are bounded at N and this pool holds pages of 65536"** — right format,
163
+ wrong size. The pool's page size is fixed for the life of the page, because there is no slot-size
164
+ class table; build the asset at 64 KB.
165
+
166
+ The VRAM tier here is built with **4,096 page slots** rather than the engine default of 1,024,
167
+ which is a decision this page takes on its own and worth knowing when reading its numbers against
168
+ another host's. At the default, an asset over a thousand pages fills the tier and `refused` starts
169
+ climbing — and the cut then clamps against a budget instead of against τ, which is the one thing
170
+ this page is not supposed to be showing you. `refused` is in the panel so that when it *is* the
171
+ budget, you can see it is.
172
+
173
+ ## Profiling it
174
+
175
+ **`T` records a GPU capture, `T` again stops it and downloads an `.sgpt`** — the same key and the
176
+ same module (`playground/profile_hotkey.js`) the other playgrounds bind, so there is one
177
+ implementation of the drain and the naming rather than one per page. The level is `WORKLOAD`: pass
178
+ spans, the frame graph, and dispatch/draw counts, which measures around 14 KB a frame here.
179
+
180
+ It answers the question the panel cannot. Every reading above is a **count** — clusters drawn, pages
181
+ visited, wavefronts run — and not one of them is a cost. What is worth knowing is how the seed, the
182
+ traverse loop, the collect and the expansion compare against the rasterization they feed, and
183
+ whether the descent's wavefront count shows up as time or disappears into occupancy.
184
+
185
+ The capture's note carries **τ, the asset and the cut it selected**, next to the adapter and the
186
+ resolution, because the same 0.4 ms is a triumph at ten thousand clusters and a scandal at nine. A
187
+ capture without those is a number with nothing to divide it by.
188
+
55
189
  ## Driving it
56
190
 
57
- `__state()` is the whole surface a headless session needs — frames, the cut's counters, and both
58
- residency tiers. `__page.runtime.tau` is the threshold. The panel shows nothing `__state()` does
59
- not.
191
+ `__state()` is the whole surface a headless session needs — frames, the cut's counters, the asset,
192
+ the render target's size, and both residency tiers. `__page.runtime.tau` is the threshold,
193
+ `__load_url(url)` opens a container without a pointer to drop with. The panel shows nothing
194
+ `__state()` does not.
60
195
 
61
196
  ```
62
197
  npm run dev --workspace @woosh/meep-engine
@@ -68,7 +203,7 @@ rhetorical claim: 18,569 passing specs did not notice it failing to boot at all,
68
203
  `scene.add(make_sunlight())` had outlived `Scene.add` and the page threw before defining
69
204
  `__state`. Treat a green suite without a drive as unverified.
70
205
 
71
- ### The headless recipe, and the two things that cost an hour
206
+ ### The headless recipe, and the four things that cost an hour
72
207
 
73
208
  Start the dev server, then launch Chrome with a debugging port and connect over CDP:
74
209
 
@@ -88,6 +223,16 @@ chrome --headless=new --enable-unsafe-webgpu --remote-debugging-port=9333 \
88
223
  `chrome://omnibox-popup` targets as well, and the first entry is routinely not the page. Attaching
89
224
  to one of those and asking it for `navigator.gpu` answers `undefined`, which reads exactly like a
90
225
  browser without WebGPU.
226
+ - **Resize the window, not the viewport.** `Emulation.setDeviceMetricsOverride` moves `innerWidth`
227
+ and leaves `document.documentElement.clientWidth` where it was, so the page never resizes and the
228
+ override reads as the fix not working. `Browser.getWindowForTarget` then `Browser.setWindowBounds`
229
+ is a real resize and the canvas follows it.
230
+ - **A drop is dispatchable.** `new DataTransfer()`, `items.add(new File([bytes], name))`, then
231
+ `window.dispatchEvent(new DragEvent('drop', { dataTransfer }))` goes through the page's own
232
+ handler — no pointer, and no separate code path to keep honest. `?file=` needs a server that
233
+ answers `Range` with a `206`; vite refuses `/@fs/` outside the workspace, so an asset off the
234
+ tree wants twenty lines of `http.createServer` with `Access-Control-Expose-Headers:
235
+ Content-Range`.
91
236
 
92
237
  Open the page as Chrome's startup URL rather than with `Page.navigate` — the `load` event is not a
93
238
  reliable signal here, so poll for `__state` itself. Then set `__page.runtime.tau` and read
@@ -1,62 +1,112 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="utf-8">
5
- <title>meep — virtual geometry runtime</title>
6
-
7
- <link rel="icon" href="data:,">
8
-
9
- <style>
10
- :root { color-scheme: dark; }
11
-
12
- html, body { height: 100%; margin: 0; overflow: hidden; background: #070b10; }
13
-
14
- #panel {
15
- position: absolute; top: 0; right: 0; width: 320px; max-height: 100vh; overflow-y: auto;
16
- z-index: 10; padding: 12px 14px; box-sizing: border-box;
17
- font: 12px/1.45 ui-monospace, "Cascadia Mono", Consolas, monospace;
18
- color: #dfe6ee; background: rgba(12, 16, 22, 0.88);
19
- border-left: 1px solid #2b3947;
20
- }
21
-
22
- #panel h1 { margin: 0 0 8px; font-size: 13px; letter-spacing: 0.06em; color: #7fd2ff; }
23
-
24
- #panel h2 {
25
- margin: 14px 0 6px; font-size: 11px; letter-spacing: 0.12em; text-transform: uppercase;
26
- color: #6b7c8d; border-bottom: 1px solid #24313d; padding-bottom: 3px;
27
- }
28
-
29
- #panel .row { display: flex; justify-content: space-between; gap: 8px; }
30
- #panel .row span:last-child { color: #f2f6fa; text-align: right; }
31
- #panel .muted { color: #6b7c8d; }
32
- #panel .bad { color: #ff8a7a; }
33
- #panel .good { color: #8fe388; }
34
- #panel input[type=range] { width: 100%; }
35
- #panel label { display: block; margin: 6px 0 2px; }
36
-
37
- #status { white-space: pre-wrap; }
38
- #status.error { color: #ff8a7a; }
39
- </style>
40
- </head>
41
- <body tabindex="0">
42
-
43
- <div id="panel">
44
- <h1>virtual geometry runtime</h1>
45
- <div id="status" class="muted">starting…</div>
46
-
47
- <label>threshold τ <span id="tau-value">1.0</span> px</label>
48
- <input id="tau" type="range" min="0.25" max="16" step="0.25" value="1">
49
-
50
- <h2>cut</h2>
51
- <div id="cut"></div>
52
-
53
- <h2>residency</h2>
54
- <div id="residency"></div>
55
- </div>
56
-
57
- <canvas id="view" width="960" height="600"></canvas>
58
-
59
- <script type="module" src="./main.js"></script>
60
-
61
- </body>
62
- </html>
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>meep — virtual geometry runtime</title>
6
+
7
+ <link rel="icon" href="data:,">
8
+
9
+ <style>
10
+ :root { color-scheme: dark; }
11
+
12
+ html, body { height: 100%; margin: 0; overflow: hidden; background: #070b10; }
13
+
14
+ /* Placed, not sized. `Renderer` owns both of the canvas's sizes — it writes `width`/`height`
15
+ in device pixels and an **inline** `style.width`/`style.height` in CSS pixels every time
16
+ it configures the context — and an inline style beats a rule in here. So a `width: 100%`
17
+ on this selector would look like it was doing the work while the renderer quietly pinned
18
+ the canvas to whatever it was first told, and `main.js` measures the window rather than
19
+ the canvas for exactly that reason. */
20
+ #view { position: absolute; top: 0; left: 0; display: block; }
21
+
22
+ #panel {
23
+ position: absolute; top: 0; right: 0; width: 320px; max-height: 100vh; overflow-y: auto;
24
+ z-index: 10; padding: 12px 14px; box-sizing: border-box;
25
+ font: 12px/1.45 ui-monospace, "Cascadia Mono", Consolas, monospace;
26
+ color: #dfe6ee; background: rgba(12, 16, 22, 0.88);
27
+ border-left: 1px solid #2b3947;
28
+ }
29
+
30
+ #panel h1 { margin: 0 0 8px; font-size: 13px; letter-spacing: 0.06em; color: #7fd2ff; }
31
+
32
+ #panel h2 {
33
+ margin: 14px 0 6px; font-size: 11px; letter-spacing: 0.12em; text-transform: uppercase;
34
+ color: #6b7c8d; border-bottom: 1px solid #24313d; padding-bottom: 3px;
35
+ }
36
+
37
+ #panel .row { display: flex; justify-content: space-between; gap: 8px; }
38
+
39
+ /* A dropped file's name is as long as the file's name, and a converter's names are hashes.
40
+ Clipped rather than wrapped so the rows stay one line each, and `min-width: 0` because a
41
+ flex item refuses to shrink below its content without it — which is what put a horizontal
42
+ scrollbar across the whole panel. The full name is in the tooltip. */
43
+ #panel .row span:last-child {
44
+ color: #f2f6fa; text-align: right;
45
+ min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
46
+ }
47
+
48
+ #panel .row span:first-child { flex: none; }
49
+ #panel .muted { color: #6b7c8d; }
50
+ #panel .bad { color: #ff8a7a; }
51
+ #panel .good { color: #8fe388; }
52
+ #panel input[type=range] { width: 100%; }
53
+ #panel label { display: block; margin: 6px 0 2px; }
54
+
55
+ /* `overflow-wrap` as well as the wrap, because the status carries a URL and a URL has no
56
+ spaces to break at — one `?file=` was enough to push a scrollbar across the panel. */
57
+ #status { white-space: pre-wrap; overflow-wrap: anywhere; }
58
+ #status.error { color: #ff8a7a; }
59
+
60
+ #hint, #profile-note { margin-top: 10px; color: #6b7c8d; }
61
+
62
+ #profile-status { margin-top: 4px; color: #dfe6ee; word-break: break-word; }
63
+ #profile-status.recording { color: #ff8a7a; }
64
+
65
+ /* Shown only while something is being dragged over the window. `inset: 0` rather than the
66
+ canvas's box because a file dropped on the panel is a file dropped on the page. */
67
+ #drop {
68
+ position: absolute; inset: 0; z-index: 20;
69
+ display: none; align-items: center; justify-content: center;
70
+ font: 20px ui-monospace, monospace; color: #7fd2ff;
71
+ background: rgba(6, 12, 20, 0.82); border: 3px dashed #7fd2ff; box-sizing: border-box;
72
+ }
73
+
74
+ #drop.active { display: flex; }
75
+ </style>
76
+ </head>
77
+ <body tabindex="0">
78
+
79
+ <canvas id="view"></canvas>
80
+
81
+ <div id="drop">drop a .vgeo file</div>
82
+
83
+ <div id="panel">
84
+ <h1>virtual geometry runtime</h1>
85
+ <div id="status" class="muted">starting…</div>
86
+
87
+ <label>threshold τ <span id="tau-value">1.0</span> px</label>
88
+ <input id="tau" type="range" min="0.25" max="16" step="0.25" value="1">
89
+
90
+ <h2>asset</h2>
91
+ <div id="asset"></div>
92
+
93
+ <h2>cut</h2>
94
+ <div id="cut"></div>
95
+
96
+ <h2>residency</h2>
97
+ <div id="residency"></div>
98
+
99
+ <h2>profiling</h2>
100
+ <div id="profile-status">idle · T to record</div>
101
+ <div id="profile-note"><strong>T</strong> starts a GPU capture and <strong>T</strong> again
102
+ stops it and downloads an <code>.sgpt</code>. The capture's note carries τ and the cut it
103
+ selected, because a pass timing here means nothing without them.</div>
104
+
105
+ <div id="hint">drop a <code>.vgeo</code> file anywhere on the page, or open
106
+ <code>?file=/some/asset.vgeo</code></div>
107
+ </div>
108
+
109
+ <script type="module" src="./main.js"></script>
110
+
111
+ </body>
112
+ </html>