@woosh/meep-engine 3.13.0 → 3.14.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 (663) hide show
  1. package/README.md +257 -119
  2. package/editor/prototypeEditorShell.js +26 -2
  3. package/package.json +4 -3
  4. package/src/core/geom/3d/shape/ConvexHullShape3D.d.ts.map +1 -1
  5. package/src/core/geom/3d/shape/ConvexHullShape3D.js +41 -25
  6. package/src/core/geom/3d/shape/PosedShape3D.d.ts.map +1 -1
  7. package/src/core/geom/3d/shape/PosedShape3D.js +7 -2
  8. package/src/engine/graphics/ecs/highlight/system/ShadedGeometryHighlightSystem.d.ts +47 -0
  9. package/src/engine/graphics/ecs/highlight/system/ShadedGeometryHighlightSystem.d.ts.map +1 -0
  10. package/src/engine/graphics/ecs/highlight/system/ShadedGeometryHighlightSystem.js +109 -0
  11. package/src/engine/graphics/ecs/mesh-v2/aggregate/SGMeshHighlightSystem.d.ts +28 -16
  12. package/src/engine/graphics/ecs/mesh-v2/aggregate/SGMeshHighlightSystem.d.ts.map +1 -1
  13. package/src/engine/graphics/ecs/mesh-v2/aggregate/SGMeshHighlightSystem.js +111 -92
  14. package/src/engine/graphics3/FogOfWarSystem.d.ts +1 -1
  15. package/src/engine/graphics3/FogOfWarSystem.d.ts.map +1 -1
  16. package/src/engine/graphics3/FogOfWarSystem.js +1 -1
  17. package/src/engine/graphics3/HighlightOutlineSystem.d.ts +99 -0
  18. package/src/engine/graphics3/HighlightOutlineSystem.d.ts.map +1 -0
  19. package/src/engine/graphics3/HighlightOutlineSystem.js +240 -0
  20. package/src/engine/graphics3/HighlightSystem.d.ts +14 -77
  21. package/src/engine/graphics3/HighlightSystem.d.ts.map +1 -1
  22. package/src/engine/graphics3/HighlightSystem.js +19 -233
  23. package/src/engine/graphics3/HighlightSystem3.d.ts +7 -4
  24. package/src/engine/graphics3/HighlightSystem3.d.ts.map +1 -1
  25. package/src/engine/graphics3/HighlightSystem3.js +15 -10
  26. package/src/engine/graphics3/highlight/pack_highlight_table.d.ts +13 -8
  27. package/src/engine/graphics3/highlight/pack_highlight_table.d.ts.map +1 -1
  28. package/src/engine/graphics3/highlight/pack_highlight_table.js +14 -8
  29. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  30. package/src/shade/RENDERER_CONTRACT.md +579 -568
  31. package/src/shade/device/PASS_ENCODER_PROPOSAL_2026_08_31.md +19 -14
  32. package/src/shade/renderer/postprocess/eye/GPUCameraExposureManager.js +1 -1
  33. package/src/shade/renderer/scene/Mesh.d.ts.map +1 -1
  34. package/src/shade/renderer/scene/Mesh.js +4 -6
  35. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.d.ts +16 -7
  36. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.d.ts.map +1 -1
  37. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.js +1342 -1322
  38. package/src/shade/renderer/shadow/map/Shadowmap.d.ts +13 -0
  39. package/src/shade/renderer/shadow/map/Shadowmap.d.ts.map +1 -1
  40. package/src/shade/renderer/shadow/map/Shadowmap.js +14 -0
  41. package/src/shade/renderer/shadow/map/ShadowmapDrawSelector.d.ts +79 -0
  42. package/src/shade/renderer/shadow/map/ShadowmapDrawSelector.d.ts.map +1 -0
  43. package/src/shade/renderer/shadow/map/ShadowmapDrawSelector.js +196 -0
  44. package/src/shade/renderer/shadow/map/ShadowmapRegistry.d.ts +91 -0
  45. package/src/shade/renderer/shadow/map/ShadowmapRegistry.d.ts.map +1 -0
  46. package/src/shade/renderer/shadow/map/ShadowmapRegistry.js +156 -0
  47. package/src/engine/graphics/ecs/highlight/plugin/HighlightRenderElementSource.d.ts +0 -9
  48. package/src/engine/graphics/ecs/highlight/plugin/HighlightRenderElementSource.d.ts.map +0 -1
  49. package/src/engine/graphics/ecs/highlight/plugin/HighlightRenderElementSource.js +0 -12
  50. package/src/engine/graphics/ecs/highlight/renderer/HighlightRenderElement.d.ts +0 -16
  51. package/src/engine/graphics/ecs/highlight/renderer/HighlightRenderElement.d.ts.map +0 -1
  52. package/src/engine/graphics/ecs/highlight/renderer/HighlightRenderElement.js +0 -44
  53. package/src/engine/graphics/ecs/highlight/renderer/HighlightRenderGroup.d.ts +0 -20
  54. package/src/engine/graphics/ecs/highlight/renderer/HighlightRenderGroup.d.ts.map +0 -1
  55. package/src/engine/graphics/ecs/highlight/renderer/HighlightRenderGroup.js +0 -29
  56. package/src/engine/graphics/ecs/highlight/renderer/makeGaussianBlurShader.d.ts +0 -8
  57. package/src/engine/graphics/ecs/highlight/renderer/makeGaussianBlurShader.d.ts.map +0 -1
  58. package/src/engine/graphics/ecs/highlight/renderer/makeGaussianBlurShader.js +0 -58
  59. package/src/engine/graphics/ecs/highlight/renderer/traverseThreeObject.d.ts +0 -8
  60. package/src/engine/graphics/ecs/highlight/renderer/traverseThreeObject.d.ts.map +0 -1
  61. package/src/engine/graphics/ecs/highlight/renderer/traverseThreeObject.js +0 -18
  62. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1.mag.xy.png +0 -0
  63. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1.mag.xz.png +0 -0
  64. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_0.png +0 -0
  65. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_1.png +0 -0
  66. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_10.png +0 -0
  67. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_11.png +0 -0
  68. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_12.png +0 -0
  69. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_13.png +0 -0
  70. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_14.png +0 -0
  71. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_15.png +0 -0
  72. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_16.png +0 -0
  73. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_17.png +0 -0
  74. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_18.png +0 -0
  75. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_19.png +0 -0
  76. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_2.png +0 -0
  77. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_20.png +0 -0
  78. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_21.png +0 -0
  79. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_22.png +0 -0
  80. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_23.png +0 -0
  81. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_24.png +0 -0
  82. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_25.png +0 -0
  83. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_26.png +0 -0
  84. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_27.png +0 -0
  85. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_28.png +0 -0
  86. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_29.png +0 -0
  87. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_3.png +0 -0
  88. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_30.png +0 -0
  89. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_31.png +0 -0
  90. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_32.png +0 -0
  91. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_33.png +0 -0
  92. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_34.png +0 -0
  93. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_35.png +0 -0
  94. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_36.png +0 -0
  95. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_37.png +0 -0
  96. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_38.png +0 -0
  97. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_39.png +0 -0
  98. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_4.png +0 -0
  99. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_40.png +0 -0
  100. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_41.png +0 -0
  101. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_42.png +0 -0
  102. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_43.png +0 -0
  103. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_44.png +0 -0
  104. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_45.png +0 -0
  105. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_46.png +0 -0
  106. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_47.png +0 -0
  107. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_48.png +0 -0
  108. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_49.png +0 -0
  109. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_5.png +0 -0
  110. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_50.png +0 -0
  111. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_51.png +0 -0
  112. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_52.png +0 -0
  113. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_53.png +0 -0
  114. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_54.png +0 -0
  115. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_55.png +0 -0
  116. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_56.png +0 -0
  117. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_57.png +0 -0
  118. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_58.png +0 -0
  119. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_59.png +0 -0
  120. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_6.png +0 -0
  121. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_60.png +0 -0
  122. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_61.png +0 -0
  123. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_62.png +0 -0
  124. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_63.png +0 -0
  125. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_7.png +0 -0
  126. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_8.png +0 -0
  127. package/src/shade/renderer/texture/noise/stbn/images/stbn_scalar_2Dx1Dx1D_128x128x64x1_9.png +0 -0
  128. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64.dat +0 -0
  129. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64.mag.xy.png +0 -0
  130. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64.mag.xz.png +0 -0
  131. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_0.png +0 -0
  132. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_1.png +0 -0
  133. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_10.png +0 -0
  134. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_11.png +0 -0
  135. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_12.png +0 -0
  136. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_13.png +0 -0
  137. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_14.png +0 -0
  138. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_15.png +0 -0
  139. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_16.png +0 -0
  140. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_17.png +0 -0
  141. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_18.png +0 -0
  142. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_19.png +0 -0
  143. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_2.png +0 -0
  144. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_20.png +0 -0
  145. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_21.png +0 -0
  146. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_22.png +0 -0
  147. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_23.png +0 -0
  148. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_24.png +0 -0
  149. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_25.png +0 -0
  150. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_26.png +0 -0
  151. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_27.png +0 -0
  152. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_28.png +0 -0
  153. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_29.png +0 -0
  154. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_3.png +0 -0
  155. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_30.png +0 -0
  156. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_31.png +0 -0
  157. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_32.png +0 -0
  158. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_33.png +0 -0
  159. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_34.png +0 -0
  160. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_35.png +0 -0
  161. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_36.png +0 -0
  162. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_37.png +0 -0
  163. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_38.png +0 -0
  164. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_39.png +0 -0
  165. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_4.png +0 -0
  166. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_40.png +0 -0
  167. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_41.png +0 -0
  168. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_42.png +0 -0
  169. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_43.png +0 -0
  170. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_44.png +0 -0
  171. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_45.png +0 -0
  172. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_46.png +0 -0
  173. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_47.png +0 -0
  174. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_48.png +0 -0
  175. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_49.png +0 -0
  176. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_5.png +0 -0
  177. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_50.png +0 -0
  178. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_51.png +0 -0
  179. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_52.png +0 -0
  180. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_53.png +0 -0
  181. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_54.png +0 -0
  182. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_55.png +0 -0
  183. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_56.png +0 -0
  184. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_57.png +0 -0
  185. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_58.png +0 -0
  186. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_59.png +0 -0
  187. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_6.png +0 -0
  188. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_60.png +0 -0
  189. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_61.png +0 -0
  190. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_62.png +0 -0
  191. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_63.png +0 -0
  192. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_7.png +0 -0
  193. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_8.png +0 -0
  194. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec1_2Dx1D_128x128x64_9.png +0 -0
  195. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64.dat +0 -0
  196. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64.mag.xy.png +0 -0
  197. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64.mag.xz.png +0 -0
  198. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_0.png +0 -0
  199. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_1.png +0 -0
  200. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_10.png +0 -0
  201. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_11.png +0 -0
  202. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_12.png +0 -0
  203. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_13.png +0 -0
  204. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_14.png +0 -0
  205. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_15.png +0 -0
  206. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_16.png +0 -0
  207. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_17.png +0 -0
  208. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_18.png +0 -0
  209. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_19.png +0 -0
  210. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_2.png +0 -0
  211. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_20.png +0 -0
  212. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_21.png +0 -0
  213. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_22.png +0 -0
  214. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_23.png +0 -0
  215. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_24.png +0 -0
  216. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_25.png +0 -0
  217. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_26.png +0 -0
  218. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_27.png +0 -0
  219. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_28.png +0 -0
  220. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_29.png +0 -0
  221. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_3.png +0 -0
  222. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_30.png +0 -0
  223. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_31.png +0 -0
  224. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_32.png +0 -0
  225. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_33.png +0 -0
  226. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_34.png +0 -0
  227. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_35.png +0 -0
  228. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_36.png +0 -0
  229. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_37.png +0 -0
  230. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_38.png +0 -0
  231. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_39.png +0 -0
  232. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_4.png +0 -0
  233. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_40.png +0 -0
  234. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_41.png +0 -0
  235. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_42.png +0 -0
  236. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_43.png +0 -0
  237. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_44.png +0 -0
  238. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_45.png +0 -0
  239. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_46.png +0 -0
  240. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_47.png +0 -0
  241. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_48.png +0 -0
  242. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_49.png +0 -0
  243. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_5.png +0 -0
  244. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_50.png +0 -0
  245. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_51.png +0 -0
  246. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_52.png +0 -0
  247. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_53.png +0 -0
  248. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_54.png +0 -0
  249. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_55.png +0 -0
  250. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_56.png +0 -0
  251. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_57.png +0 -0
  252. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_58.png +0 -0
  253. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_59.png +0 -0
  254. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_6.png +0 -0
  255. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_60.png +0 -0
  256. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_61.png +0 -0
  257. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_62.png +0 -0
  258. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_63.png +0 -0
  259. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_7.png +0 -0
  260. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_8.png +0 -0
  261. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec2_2Dx1D_128x128x64_9.png +0 -0
  262. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64.dat +0 -0
  263. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64.mag.xy.png +0 -0
  264. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64.mag.xz.png +0 -0
  265. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_0.png +0 -0
  266. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_1.png +0 -0
  267. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_10.png +0 -0
  268. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_11.png +0 -0
  269. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_12.png +0 -0
  270. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_13.png +0 -0
  271. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_14.png +0 -0
  272. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_15.png +0 -0
  273. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_16.png +0 -0
  274. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_17.png +0 -0
  275. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_18.png +0 -0
  276. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_19.png +0 -0
  277. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_2.png +0 -0
  278. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_20.png +0 -0
  279. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_21.png +0 -0
  280. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_22.png +0 -0
  281. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_23.png +0 -0
  282. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_24.png +0 -0
  283. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_25.png +0 -0
  284. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_26.png +0 -0
  285. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_27.png +0 -0
  286. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_28.png +0 -0
  287. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_29.png +0 -0
  288. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_3.png +0 -0
  289. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_30.png +0 -0
  290. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_31.png +0 -0
  291. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_32.png +0 -0
  292. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_33.png +0 -0
  293. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_34.png +0 -0
  294. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_35.png +0 -0
  295. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_36.png +0 -0
  296. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_37.png +0 -0
  297. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_38.png +0 -0
  298. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_39.png +0 -0
  299. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_4.png +0 -0
  300. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_40.png +0 -0
  301. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_41.png +0 -0
  302. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_42.png +0 -0
  303. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_43.png +0 -0
  304. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_44.png +0 -0
  305. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_45.png +0 -0
  306. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_46.png +0 -0
  307. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_47.png +0 -0
  308. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_48.png +0 -0
  309. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_49.png +0 -0
  310. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_5.png +0 -0
  311. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_50.png +0 -0
  312. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_51.png +0 -0
  313. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_52.png +0 -0
  314. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_53.png +0 -0
  315. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_54.png +0 -0
  316. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_55.png +0 -0
  317. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_56.png +0 -0
  318. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_57.png +0 -0
  319. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_58.png +0 -0
  320. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_59.png +0 -0
  321. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_6.png +0 -0
  322. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_60.png +0 -0
  323. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_61.png +0 -0
  324. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_62.png +0 -0
  325. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_63.png +0 -0
  326. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_7.png +0 -0
  327. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_8.png +0 -0
  328. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_2Dx1D_128x128x64_9.png +0 -0
  329. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64.dat +0 -0
  330. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64.mag.xy.png +0 -0
  331. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64.mag.xz.png +0 -0
  332. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_0.png +0 -0
  333. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_1.png +0 -0
  334. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_10.png +0 -0
  335. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_11.png +0 -0
  336. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_12.png +0 -0
  337. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_13.png +0 -0
  338. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_14.png +0 -0
  339. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_15.png +0 -0
  340. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_16.png +0 -0
  341. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_17.png +0 -0
  342. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_18.png +0 -0
  343. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_19.png +0 -0
  344. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_2.png +0 -0
  345. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_20.png +0 -0
  346. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_21.png +0 -0
  347. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_22.png +0 -0
  348. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_23.png +0 -0
  349. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_24.png +0 -0
  350. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_25.png +0 -0
  351. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_26.png +0 -0
  352. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_27.png +0 -0
  353. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_28.png +0 -0
  354. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_29.png +0 -0
  355. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_3.png +0 -0
  356. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_30.png +0 -0
  357. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_31.png +0 -0
  358. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_32.png +0 -0
  359. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_33.png +0 -0
  360. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_34.png +0 -0
  361. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_35.png +0 -0
  362. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_36.png +0 -0
  363. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_37.png +0 -0
  364. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_38.png +0 -0
  365. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_39.png +0 -0
  366. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_4.png +0 -0
  367. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_40.png +0 -0
  368. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_41.png +0 -0
  369. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_42.png +0 -0
  370. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_43.png +0 -0
  371. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_44.png +0 -0
  372. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_45.png +0 -0
  373. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_46.png +0 -0
  374. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_47.png +0 -0
  375. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_48.png +0 -0
  376. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_49.png +0 -0
  377. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_5.png +0 -0
  378. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_50.png +0 -0
  379. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_51.png +0 -0
  380. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_52.png +0 -0
  381. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_53.png +0 -0
  382. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_54.png +0 -0
  383. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_55.png +0 -0
  384. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_56.png +0 -0
  385. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_57.png +0 -0
  386. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_58.png +0 -0
  387. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_59.png +0 -0
  388. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_6.png +0 -0
  389. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_60.png +0 -0
  390. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_61.png +0 -0
  391. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_62.png +0 -0
  392. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_63.png +0 -0
  393. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_7.png +0 -0
  394. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_8.png +0 -0
  395. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_cosine_2Dx1D_128x128x64_9.png +0 -0
  396. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64.dat +0 -1
  397. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64.mag.xy.png +0 -0
  398. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64.mag.xz.png +0 -0
  399. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_0.png +0 -0
  400. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_1.png +0 -0
  401. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_10.png +0 -0
  402. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_11.png +0 -0
  403. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_12.png +0 -0
  404. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_13.png +0 -0
  405. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_14.png +0 -0
  406. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_15.png +0 -0
  407. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_16.png +0 -0
  408. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_17.png +0 -0
  409. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_18.png +0 -0
  410. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_19.png +0 -0
  411. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_2.png +0 -0
  412. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_20.png +0 -0
  413. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_21.png +0 -0
  414. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_22.png +0 -0
  415. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_23.png +0 -0
  416. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_24.png +0 -0
  417. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_25.png +0 -0
  418. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_26.png +0 -0
  419. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_27.png +0 -0
  420. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_28.png +0 -0
  421. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_29.png +0 -0
  422. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_3.png +0 -0
  423. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_30.png +0 -0
  424. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_31.png +0 -0
  425. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_32.png +0 -0
  426. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_33.png +0 -0
  427. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_34.png +0 -0
  428. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_35.png +0 -0
  429. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_36.png +0 -0
  430. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_37.png +0 -0
  431. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_38.png +0 -0
  432. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_39.png +0 -0
  433. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_4.png +0 -0
  434. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_40.png +0 -0
  435. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_41.png +0 -0
  436. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_42.png +0 -0
  437. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_43.png +0 -0
  438. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_44.png +0 -0
  439. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_45.png +0 -0
  440. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_46.png +0 -0
  441. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_47.png +0 -0
  442. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_48.png +0 -0
  443. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_49.png +0 -0
  444. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_5.png +0 -0
  445. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_50.png +0 -0
  446. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_51.png +0 -0
  447. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_52.png +0 -0
  448. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_53.png +0 -0
  449. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_54.png +0 -0
  450. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_55.png +0 -0
  451. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_56.png +0 -0
  452. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_57.png +0 -0
  453. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_58.png +0 -0
  454. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_59.png +0 -0
  455. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_6.png +0 -0
  456. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_60.png +0 -0
  457. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_61.png +0 -0
  458. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_62.png +0 -0
  459. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_63.png +0 -0
  460. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_7.png +0 -0
  461. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_8.png +0 -0
  462. package/src/shade/renderer/texture/noise/stbn/images/stbn_unitvec3_forest_2Dx1D_128x128x64_9.png +0 -0
  463. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64.dat +0 -0
  464. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64.mag.xy.png +0 -0
  465. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64.mag.xz.png +0 -0
  466. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_0.png +0 -0
  467. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_1.png +0 -0
  468. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_10.png +0 -0
  469. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_11.png +0 -0
  470. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_12.png +0 -0
  471. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_13.png +0 -0
  472. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_14.png +0 -0
  473. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_15.png +0 -0
  474. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_16.png +0 -0
  475. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_17.png +0 -0
  476. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_18.png +0 -0
  477. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_19.png +0 -0
  478. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_2.png +0 -0
  479. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_20.png +0 -0
  480. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_21.png +0 -0
  481. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_22.png +0 -0
  482. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_23.png +0 -0
  483. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_24.png +0 -0
  484. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_25.png +0 -0
  485. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_26.png +0 -0
  486. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_27.png +0 -0
  487. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_28.png +0 -0
  488. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_29.png +0 -0
  489. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_3.png +0 -0
  490. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_30.png +0 -0
  491. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_31.png +0 -0
  492. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_32.png +0 -0
  493. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_33.png +0 -0
  494. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_34.png +0 -0
  495. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_35.png +0 -0
  496. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_36.png +0 -0
  497. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_37.png +0 -0
  498. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_38.png +0 -0
  499. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_39.png +0 -0
  500. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_4.png +0 -0
  501. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_40.png +0 -0
  502. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_41.png +0 -0
  503. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_42.png +0 -0
  504. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_43.png +0 -0
  505. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_44.png +0 -0
  506. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_45.png +0 -0
  507. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_46.png +0 -0
  508. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_47.png +0 -0
  509. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_48.png +0 -0
  510. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_49.png +0 -0
  511. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_5.png +0 -0
  512. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_50.png +0 -0
  513. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_51.png +0 -0
  514. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_52.png +0 -0
  515. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_53.png +0 -0
  516. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_54.png +0 -0
  517. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_55.png +0 -0
  518. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_56.png +0 -0
  519. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_57.png +0 -0
  520. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_58.png +0 -0
  521. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_59.png +0 -0
  522. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_6.png +0 -0
  523. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_60.png +0 -0
  524. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_61.png +0 -0
  525. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_62.png +0 -0
  526. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_63.png +0 -0
  527. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_7.png +0 -0
  528. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_8.png +0 -0
  529. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec1_2Dx1D_128x128x64_9.png +0 -0
  530. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64.dat +0 -0
  531. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64.mag.xy.png +0 -0
  532. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64.mag.xz.png +0 -0
  533. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_0.png +0 -0
  534. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_1.png +0 -0
  535. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_10.png +0 -0
  536. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_11.png +0 -0
  537. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_12.png +0 -0
  538. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_13.png +0 -0
  539. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_14.png +0 -0
  540. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_15.png +0 -0
  541. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_16.png +0 -0
  542. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_17.png +0 -0
  543. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_18.png +0 -0
  544. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_19.png +0 -0
  545. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_2.png +0 -0
  546. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_20.png +0 -0
  547. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_21.png +0 -0
  548. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_22.png +0 -0
  549. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_23.png +0 -0
  550. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_24.png +0 -0
  551. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_25.png +0 -0
  552. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_26.png +0 -0
  553. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_27.png +0 -0
  554. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_28.png +0 -0
  555. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_29.png +0 -0
  556. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_3.png +0 -0
  557. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_30.png +0 -0
  558. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_31.png +0 -0
  559. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_32.png +0 -0
  560. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_33.png +0 -0
  561. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_34.png +0 -0
  562. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_35.png +0 -0
  563. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_36.png +0 -0
  564. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_37.png +0 -0
  565. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_38.png +0 -0
  566. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_39.png +0 -0
  567. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_4.png +0 -0
  568. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_40.png +0 -0
  569. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_41.png +0 -0
  570. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_42.png +0 -0
  571. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_43.png +0 -0
  572. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_44.png +0 -0
  573. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_45.png +0 -0
  574. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_46.png +0 -0
  575. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_47.png +0 -0
  576. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_48.png +0 -0
  577. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_49.png +0 -0
  578. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_5.png +0 -0
  579. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_50.png +0 -0
  580. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_51.png +0 -0
  581. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_52.png +0 -0
  582. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_53.png +0 -0
  583. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_54.png +0 -0
  584. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_55.png +0 -0
  585. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_56.png +0 -0
  586. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_57.png +0 -0
  587. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_58.png +0 -0
  588. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_59.png +0 -0
  589. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_6.png +0 -0
  590. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_60.png +0 -0
  591. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_61.png +0 -0
  592. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_62.png +0 -0
  593. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_63.png +0 -0
  594. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_7.png +0 -0
  595. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_8.png +0 -0
  596. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec2_2Dx1D_128x128x64_9.png +0 -0
  597. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64.dat +0 -0
  598. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64.mag.xy.png +0 -0
  599. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64.mag.xz.png +0 -0
  600. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_0.png +0 -0
  601. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_1.png +0 -0
  602. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_10.png +0 -0
  603. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_11.png +0 -0
  604. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_12.png +0 -0
  605. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_13.png +0 -0
  606. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_14.png +0 -0
  607. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_15.png +0 -0
  608. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_16.png +0 -0
  609. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_17.png +0 -0
  610. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_18.png +0 -0
  611. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_19.png +0 -0
  612. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_2.png +0 -0
  613. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_20.png +0 -0
  614. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_21.png +0 -0
  615. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_22.png +0 -0
  616. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_23.png +0 -0
  617. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_24.png +0 -0
  618. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_25.png +0 -0
  619. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_26.png +0 -0
  620. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_27.png +0 -0
  621. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_28.png +0 -0
  622. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_29.png +0 -0
  623. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_3.png +0 -0
  624. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_30.png +0 -0
  625. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_31.png +0 -0
  626. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_32.png +0 -0
  627. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_33.png +0 -0
  628. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_34.png +0 -0
  629. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_35.png +0 -0
  630. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_36.png +0 -0
  631. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_37.png +0 -0
  632. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_38.png +0 -0
  633. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_39.png +0 -0
  634. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_4.png +0 -0
  635. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_40.png +0 -0
  636. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_41.png +0 -0
  637. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_42.png +0 -0
  638. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_43.png +0 -0
  639. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_44.png +0 -0
  640. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_45.png +0 -0
  641. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_46.png +0 -0
  642. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_47.png +0 -0
  643. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_48.png +0 -0
  644. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_49.png +0 -0
  645. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_5.png +0 -0
  646. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_50.png +0 -0
  647. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_51.png +0 -0
  648. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_52.png +0 -0
  649. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_53.png +0 -0
  650. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_54.png +0 -0
  651. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_55.png +0 -0
  652. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_56.png +0 -0
  653. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_57.png +0 -0
  654. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_58.png +0 -0
  655. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_59.png +0 -0
  656. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_6.png +0 -0
  657. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_60.png +0 -0
  658. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_61.png +0 -0
  659. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_62.png +0 -0
  660. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_63.png +0 -0
  661. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_7.png +0 -0
  662. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_8.png +0 -0
  663. package/src/shade/renderer/texture/noise/stbn/images/stbn_vec3_2Dx1D_128x128x64_9.png +0 -0
@@ -1,569 +1,580 @@
1
- # Shade — the renderer contract
2
-
3
- meep 3.0 has one renderer, and this is what it promises.
4
-
5
- It is written for somebody who has never seen the inside of it: by the end of §3 you have a model on
6
- the screen, and by the end of §6 you have your own work in the frame. Everything here is the public
7
- surface — the types you construct, the calls you make, and the two or three places where the answer
8
- is "no, and here is why".
9
-
10
- If you are looking for how it works rather than what it promises, the design documents are next to
11
- the code they describe: `renderer/extension/RENDER_EXTENSION_DESIGN.md`,
12
- `renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md`, `renderer/geometry/meshlet/README.md`,
13
- `renderer/NOTES.md`.
14
-
15
- ---
16
-
17
- ## 1. What Shade is
18
-
19
- A **GPU-driven, visibility-buffer deferred renderer on WebGPU.** Geometry is clustered into meshlets
20
- ahead of time and lives in one large GPU buffer; culling runs on the GPU; the rasterizer writes a
21
- visibility buffer and a G-buffer rather than shading as it draws; lights are binned into froxels and
22
- applied deferred; and the result is temporally resolved, upscaled, tonemapped and presented.
23
-
24
- Three consequences that shape everything below:
25
-
26
- - **A mesh is a small GPU-resident record, not a draw call you own.** You add a `Mesh` to a `Scene`;
27
- what is drawn, in what order, and whether it is culled is the renderer's.
28
- - **Preparing geometry is a precompute.** Meshlet building, encoding and BVH construction happen
29
- once per geometry. Content that rewrites its vertices every frame goes down a separate path (§8).
30
- - **The frame is a closed sequence with declared injection points.** You do not insert a pass
31
- anywhere; you register an extension against a phase (§6).
32
-
33
- ### What is deliberately absent
34
-
35
- | | |
36
- |---|---|
37
- | **No RHI, no backend abstraction** | There is one target, WebGPU. There is no seam where a second one would go, and adding one is not a small change. |
38
- | **No WebGL fallback** | Below-floor hardware gets a clean failure message (§2), not a degraded picture. |
39
- | **No degradation tiers** | There is one pipeline. Individual features can be switched off (`feature_shadows_enabled`, `feature_taa_enabled`, the resolution scale), but there is no "low quality" build of the frame. |
40
- | **No double-sided drawing** | Back faces are always culled. `ShadeMaterial.draw_side` records intent and does not change what is drawn; a surface that must be visible from behind needs its geometry cloned with flipped normals. |
41
- | **No compressed textures** | DDS, Draco and Basis are not supported anywhere. glTF files carrying `MSFT_texture_dds` load from their base PNG source. |
42
-
43
- ---
44
-
45
- ## 2. The device floor
46
-
47
- Shade requires a WebGPU device that meets a fixed floor. There is no feature detection beyond it and
48
- no branch that produces a lesser frame.
49
-
50
- **Required features** — the adapter must have both, or startup fails:
51
-
52
- - `indirect-first-instance` — indirect draw is used throughout
53
- - `float32-blendable` — order-independent transparency
54
-
55
- **Required limits:**
56
-
57
- - `maxStorageBuffersPerShaderStage` **10** (checked against the adapter before the device is
58
- requested, so the failure names the number the adapter offered)
59
- - `maxColorAttachmentBytesPerSample` **32** the G-buffer is wide
60
- - `maxBufferSize` and `maxStorageBufferBindingSize` are requested at whatever the adapter offers,
61
- because the defaults are far too small
62
-
63
- **Taken when offered, never required:** `timestamp-query`, `subgroups`, `texture-formats-tier1`.
64
- `timestamp-query` drives GPU timers and nothing else, and some browsers withhold it on hardware that
65
- is otherwise fine — so the timers go quiet when it is absent rather than the renderer refusing to
66
- start.
67
-
68
- ### When it is not met
69
-
70
- `Renderer.initialize()` throws a `ShadeDeviceFailure`, whose `message` is written to be shown to a
71
- person rather than logged. It distinguishes:
72
-
73
- | | |
74
- |---|---|
75
- | `webgpu_unavailable` | no `navigator.gpu` WebGPU disabled or unsupported |
76
- | `adapter_unavailable` | no adapter at all |
77
- | `below_floor` | an adapter that does not meet §2, with the detail |
78
- | `device_request_failed` | the adapter refused the device |
79
- | `device_lost` | a working device went away while running |
80
-
81
- A device lost while running arrives on `Renderer.onDeviceFailure` instead of being thrown. **Shade
82
- does not recover a lost device.** Everything the renderer built lived on it, and the honest response
83
- is a message and a reload. The signal exists so an application can say so and save what it has.
84
-
85
- ---
86
-
87
- ## 3. Putting a model on the screen
88
-
89
- meep has no module aliases: every import is a relative path, and the ones below are written from
90
- `src/shade/` so they read like the tree in §10.
91
-
92
- ```js
93
- import { Renderer } from "./renderer/Renderer.js";
94
- import { Scene } from "./renderer/scene/Scene.js";
95
- import { PerspectiveCamera } from "./renderer/camera/PerspectiveCamera.js";
96
- import { make_sunlight } from "./renderer/light/make_sunlight.js";
97
- import { load_gltf } from "./renderer/loader/gltf/load_gltf.js";
98
- import { create_frame_loop } from "./renderer/create_frame_loop.js";
99
- import { DEG_TO_RAD } from "../core/math/DEG_TO_RAD.js";
100
- import Vector3 from "../core/geom/Vector3.js";
101
-
102
- const canvas = document.querySelector("canvas");
103
-
104
- const renderer = new Renderer();
105
-
106
- await renderer.initialize({ context: canvas.getContext("webgpu") });
107
-
108
- const camera = new PerspectiveCamera();
109
-
110
- camera.transform.position.set(0, 2, -5);
111
- camera.transform.lookAt(Vector3.zero);
112
- camera.near = 0.1;
113
- camera.far = 200;
114
- camera.fov = 72 * DEG_TO_RAD;
115
- camera.aspect = renderer.aspect_ratio;
116
-
117
- const scene = new Scene();
118
-
119
- // nothing is lit without one, and the deferred shading pass has no default light
120
- scene.lights.add(make_sunlight({ intensity: 2.2 }));
121
-
122
- const bundle = await load_gltf("model.glb", { assetManager });
123
-
124
- scene.add(bundle.scenes);
125
-
126
- create_frame_loop(dt => renderer.render(camera, scene, dt));
127
- ```
128
-
129
- That is the whole of it. Five things in it are worth stating outright.
130
-
131
- **`initialize` is asynchronous and may fail normally.** Acquiring a WebGPU device has no synchronous
132
- form and being refused one is an ordinary outcome, so it is a rejected promise carrying a
133
- `ShadeDeviceFailure` rather than a constructor that throws. Omit `context` and a full-viewport canvas
134
- is created for you; pass a `device` to share one you already have.
135
-
136
- **`assetManager` is required, and here is where one comes from.** A glTF is several files a
137
- container, its `.bin` buffers, its images and which of them are already in memory is not the
138
- parser's business to know. Every request the parse makes goes back through the manager, so they are
139
- cached, counted and cancellable like anything else the application loads. Two loaders are all
140
- `load_gltf` asks for:
141
-
142
- ```js
143
- const assetManager = new AssetManager({ context: {}, executor: new ConcurrentExecutor() });
144
-
145
- await assetManager.registerLoader(GameAssetType.ArrayBuffer, new ArrayBufferLoader());
146
- await assetManager.registerLoader(GameAssetType.ImageBitmap, new ImageBitmapAssetLoader());
147
-
148
- assetManager.startup();
149
- ```
150
-
151
- Pass a `scope` alongside it to tie a whole load to one cancellable unit, and a `fileMap` when the
152
- files come from a drop rather than from the network. An application already running meep's `Engine`
153
- has a configured manager on it and should use that one.
154
-
155
- **A model does not have to come from a file.** Everything `load_gltf` produces you can build
156
- directly, which is §4 in the other direction and needs no asset manager at all:
157
-
158
- ```js
159
- const mesh = new Mesh();
160
-
161
- mesh.geometry = meshlet_geometry_build_from_geometry(make_torus_knot_geometry(1, 0.3, 128, 16));
162
- mesh.material = new StandardShadeMaterial();
163
-
164
- mesh.transform_local.setTranslation(0, 1, 0);
165
- mesh.updateMatrices();
166
-
167
- scene.add(mesh);
168
- ```
169
-
170
- **`render` returns a boolean.** `false` means the previous frame has not finished and this one was
171
- not submitted. It is not an error.
172
-
173
- **`scene.add` takes a node or an array of them, and it recurses.** Nodes tagged `isLight` are routed
174
- to `scene.lights`, everything else into `scene.instances`; `scene.remove` mirrors it exactly.
175
-
176
- ---
177
-
178
- ## 4. The type model
179
-
180
- Everything in a scene is a **`Node3D`**: a TRS transform, a parent and children, and a row in the GPU
181
- scene-graph. `Scene` is itself a `Node3D` and occupies row 0, so posing the scene world-shifts
182
- everything under it.
183
-
184
- **A node is placed through `transform_local`, and everything else about where it is, is derived.**
185
- `transform_global` is recomputed from the local transform and the parent chain by `updateMatrices()`,
186
- which is also what refreshes a `Mesh`'s world-space bounds — so writing `transform_global` directly is
187
- undone the moment anything refreshes, and mutating `transform_local` without calling
188
- `updateMatrices()` leaves both the global transform and the bounds stale. A version counter on the
189
- node records the refresh, and the renderer compares against it.
190
-
191
- **A node's transform and a camera's are different types, deliberately, and this is the one place a
192
- newcomer will trip.** `Node3D.transform_local` is a `Transform64`: a flat `Float64Array` holding its
193
- own matrix, posed through `setTranslation(x, y, z)` / `setRotation(x, y, z, w)` / `setScale(x, y, z)`,
194
- with the buffer layout part of its contract so hot code can write it directly. A `Camera` is **not**
195
- a `Node3D` it carries meep's ECS `Transform`, whose `position`, `rotation` and `scale` are
196
- observable vectors you assign into. The two keep distinct shapes on purpose and neither has the
197
- other's accessors: `node.transform_local.position` is `undefined`, and so is
198
- `camera.transform.translation`.
199
-
200
- ```js
201
- node.transform_local.setTranslation(0, 1, 0); // Transform64 then updateMatrices()
202
- camera.transform.position.set(0, 2, -5); // Transform — reactive, no refresh call
203
- ```
204
-
205
- ```
206
- Scene (Node3D, row 0)
207
- ├── lights LightCollection — their own pipeline, not in the instance batch
208
- └── instances InstanceBatch
209
- ├── nodes every Node3D ever added, in insertion order
210
- └── instances the Mesh-bearing subset, which is what the rasterizer iterates
211
- ```
212
-
213
- A **`Mesh`** is a `Node3D` plus two fields:
214
-
215
- ```js
216
- mesh.geometry // MeshletGeometry what to draw
217
- mesh.material // ShadeMaterial — how to draw it
218
- ```
219
-
220
- and a world-space `bounding_box` / `bounding_sphere` the renderer keeps for culling.
221
-
222
- ### Geometry: two types, one of which is a precompute
223
-
224
- **`Geometry`** is the authoring form: named `Attribute`s over typed arrays, an optional index, a
225
- `bounding_box`/`bounding_sphere` computed on demand by `ensureBounds()`, and a `version` you bump
226
- through `needsUpdate = true` when you rewrite the arrays. Attributes are read by name:
227
-
228
- ```js
229
- geometry.getAttribute(StandardAttributes.Position).data // Float32Array
230
- geometry.index.data // Uint32Array
231
- ```
232
-
233
- Shade ships seven generators, all returning a `Geometry`, in `renderer/geometry/primitives/`:
234
- `make_box_geometry`, `make_plane_geometry`, `make_polyhedron_geometry`, `make_octahedron_geometry`,
235
- `make_torus_geometry`, `make_cylinder_geometry`, `make_torus_knot_geometry`.
236
-
237
- **`MeshletGeometry`** is the GPU form: triangles clustered into meshlets, attributes encoded, and a
238
- BVH over the clusters. This is what a `Mesh` carries, and it is what buys cluster culling and a
239
- compact residency.
240
-
241
- ```js
242
- const meshlets = meshlet_geometry_build_from_geometry(geometry);
243
- ```
244
-
245
- **That build is a precompute.** Do it once, when the content is created or loaded. If your vertices
246
- change every frame, you are on the wrong path — see §8.
247
-
248
- ### Materials
249
-
250
- `ShadeMaterial` is the base: `transparency_mode`, `draw_mode`, `draw_side` (which records intent and
251
- does not change what is drawn see §1). `StandardShadeMaterial` is the PBR one everything uses:
252
-
253
- | | |
254
- |---|---|
255
- | `texture_albedo` | base colour, alpha carries transparency |
256
- | `diffuse_color` | multiplied with the albedo |
257
- | `texture_normal` | tangent-space normals |
258
- | `texture_orm` | occlusion / roughness (G) / metalness (B), as glTF packs it |
259
- | `texture_emissive`, `emissive_factor` | |
260
- | `roughness_factor`, `metallic_factor` | multiplied with the ORM texture |
261
- | `transmission_factor`, `ior_factor` | |
262
- | `ambient_factors` | a `LinearModifier` over the indirect contribution |
263
- | `vt_stack` | opt-in virtual texturing; when set, albedo/normal/ORM come from streamed pages instead. Opaque materials only |
264
-
265
- ### Textures
266
-
267
- Two objects, and the split matters: **`ShadeImage`** is the pixels, **`ShadeTexture`** is how to
268
- sample them. Two materials sampling one image differently are two textures over one image, and the
269
- image is uploaded once.
270
-
271
- ```js
272
- const image = ShadeImage.fromImageBitmap(bitmap); // or fromSampler2D, or fromArrayBuffer
273
- const texture = ShadeTexture.from(image);
274
-
275
- texture.wrapS = TextureWrapType.Repeat;
276
- texture.magFilter = TextureFilterType.Linear;
277
- ```
278
-
279
- `ShadeTexture` carries filters, wrap modes and flags (mipmap generation is on by default), and both
280
- types answer `equals`/`hash`, which is what lets the renderer de-duplicate uploads.
281
-
282
- ### What a glTF becomes
283
-
284
- `load_gltf` returns a **`SceneBundle`** — three arrays out of the one file:
285
-
286
- ```js
287
- bundle.scenes // Node3D[] — the scene roots, ready for scene.add
288
- bundle.skins // Skin[] — for GPUAnimationManager.register_skin
289
- bundle.clips // ShadeAnimationClip[] — for register_clip
290
- ```
291
-
292
- The bundle is **the model as loaded, not a placement of it.** Adding one bundle's roots to two
293
- scenes, or twice to one scene, shares nodes. meep's ECS layer provides
294
- `instantiate_scene_bundle(bundle)` for the copy a second placement needs — its own nodes, its own
295
- skin and its own retargeted clips which is what makes two of one model possible.
296
-
297
- ---
298
-
299
- ## 5. The frame
300
-
301
- ```
302
- FrameStart view updated, nothing rasterized
303
-
304
- [ visibility buffer + G-buffer ]
305
- AfterGBuffer surface properties written and readable, nothing lit
306
-
307
- [ clustered lighting, deferred shading, volumetrics ]
308
- AfterLighting opaque lit and composited
309
-
310
- [ transparency ]
311
- AfterTransparency the complete scene, HDR, internal resolution
312
-
313
- [ TAA / NSS upscale ] ← resolution changes here
314
- BeforePresent HDR, output resolution, immediately before tonemapping
315
-
316
- [ tonemap canvas ]
317
- Overlay display space, drawing onto the canvas
318
- ```
319
-
320
- **The upscale is a phase boundary and it is the one thing about the frame you cannot assume away.**
321
- Three phases are before it and two are after. With `feature_taa_enabled === false` there is no
322
- upscale and the two sides are the same size. Nothing in this document states a resolution as a
323
- constant: ask `frame.resolution`, which is derived from the live handle and is right in every
324
- configuration, including under dynamic resolution scaling.
325
-
326
- ---
327
-
328
- ## 6. Adding your own work to the frame — render extensions
329
-
330
- An extension is **a named object with declarations and one method**.
331
-
332
- ```js
333
- import { RenderExtension } from "./renderer/extension/RenderExtension.js";
334
- import { FramePhase } from "./renderer/extension/FramePhase.js";
335
- import { SceneColor } from "./renderer/extension/SceneColor.js";
336
- import { ViewTextures } from "./renderer/extension/ViewTextures.js";
337
-
338
- class TrailExtension extends RenderExtension {
339
- name = "trails";
340
-
341
- phase = FramePhase.AfterTransparency;
342
-
343
- record(frame) {
344
- if (this.#batch.count === 0) {
345
- // nothing to draw, and the frame's colour is left exactly as it was
346
- return;
347
- }
348
-
349
- const scene = frame.get(SceneColor);
350
-
351
- scene.color = this.#renderer.graph_draw({
352
- graph: frame.graph,
353
- batch: this.#batch,
354
- color: scene.color,
355
- depth: frame.get(ViewTextures).depth,
356
- camera: frame.view.camera.buffer
357
- });
358
- }
359
- }
360
-
361
- const registered = renderer.add_extension(new TrailExtension());
362
- // ...
363
- renderer.remove_extension(registered);
364
- ```
365
-
366
- That is the whole mechanism. The rest of this section is what the four lines of it mean.
367
-
368
- ### Records are the channel
369
-
370
- `record(frame)` **returns nothing.** Everything an extension exchanges with the frame goes through
371
- typed **records**: you read a frame-graph handle out of one and write a replacement back, and
372
- **writing a field is publication** — everything after you carries what you left.
373
-
374
- There is no privileged resource. The scene colour is published exactly the way a G-buffer target is,
375
- and exactly the way a record of your own is.
376
-
377
- | record | carried at | writable |
378
- |---|---|---|
379
- | `SceneColor` `.color`, HDR | `AfterLighting` … `BeforePresent` | yes |
380
- | `GBufferTextures` — `.albedo` (AO in alpha), `.normal`, `.pbr`, `.emissive` | `AfterGBuffer` … `BeforePresent` | **`AfterGBuffer` only** |
381
- | `ViewTextures` `.depth`, `.depth_previous`, `.visibility_mesh`, `.visibility_triangle` | `AfterGBuffer` `BeforePresent` | yes |
382
- | `PresentTarget` `.canvas` | `Overlay` only | yes |
383
-
384
- Three of those rows are the whole reason phases exist:
385
-
386
- - **`SceneColor` is not carried at `Overlay`.** A texture may not be a render attachment and a
387
- sampled source in the same pass, so at `Overlay` the canvas is written and cannot be read. An
388
- effect that needs the finished image as *input* — a colour grade, a full-screen re-composite —
389
- belongs at `BeforePresent`. You find that out from `frame.get(SceneColor)`, which fails with a
390
- sentence naming the phases that do carry it, rather than from a `-1` failing inside a binding
391
- builder.
392
- - **`GBufferTextures` is in/out at `AfterGBuffer` and frozen afterwards.** Changing surface
393
- properties means reading the targets, writing replacements and publishing the new handles — two of
394
- the four are integer formats and cannot be blended, and nothing can be attachment and source at
395
- once. It stays *readable* to `BeforePresent` because outline and selection effects legitimately
396
- read it late; at that phase it is on the far side of the upscale and is therefore **a different
397
- size from the colour beside it**. `frame.describe(handle)` is how a pass working across that
398
- boundary learns the ratio.
399
- - **`PresentTarget` has one field and is not called `SceneColor` on purpose.** There is no colour
400
- there to be tempted by. Keep the existing contents with a `load` op, write only your own pixels,
401
- and publish the result back that is what lets two overlay extensions compose.
402
-
403
- ### Extending the vocabulary
404
-
405
- An extension can publish a record of its own for another extension to read, and doing so costs no
406
- edit to Shade:
407
-
408
- ```js
409
- class VisibilityGrid extends FrameRecord {
410
- #grid = -1;
411
-
412
- static is_present_at(phase) { return true; }
413
-
414
- get grid() { return this.read(this.#grid); }
415
- set grid(handle) { this.#grid = this.publish(handle); }
416
- }
417
-
418
- // at FrameStart
419
- frame.create(VisibilityGrid).grid = record_the_grid_update(frame.graph);
420
-
421
- // at AfterTransparency, in another extension
422
- if (frame.has(VisibilityGrid)) { … frame.get(VisibilityGrid).grid … }
423
- ```
424
-
425
- `has` / `get` / `create` are three calls rather than one `get_or_create` because **absent has to stay
426
- distinguishable from empty.**
427
-
428
- ### Ordering
429
-
430
- Order is **declared**, never emergent:
431
-
432
- ```js
433
- class DecalExtension extends RenderExtension {
434
- phase = FramePhase.AfterGBuffer;
435
- after = [TerrainSplatExtension]; // classes, not instances
436
- before = [];
437
- }
438
- ```
439
-
440
- Constraints name classes, so you do not need a reference to another system's object to state an
441
- order, and a class nobody registered is simply not a constraint. Two extensions on one phase with no
442
- path between them record in **ascending `name` order** — reproducible rather than correct, and chosen
443
- precisely so that adding an `await` to a system's startup cannot change the picture. A cycle is
444
- reported with the names on it.
445
-
446
- ### What keeps your work alive
447
-
448
- The graph elides work whose output nothing consumes, and that applies to an extension exactly as it
449
- does to a built-in pass. Thread a result into a record and it is consumed. Write something imported —
450
- the canvas, an imported texture — and it is a side effect. Want work that runs regardless and
451
- `make_side_effect()` on the pass builder says so.
452
-
453
- **An extension whose whole recording is elided is a correct, cheaper frame, not a failure**, and
454
- nothing reports it as one. It is a grey cluster with your extension's name on it in a graph dump.
455
-
456
- ### The rest of `FrameContext`
457
-
458
- | | |
459
- |---|---|
460
- | `frame.graph` | the frame's `FrameGraph`. Record into it with the `graph_*` helpers, exactly as the built-in passes do |
461
- | `frame.view` | the `GPUViewContext`camera, uniforms, frame index |
462
- | `frame.phase` | which phase this is |
463
- | `frame.resolution` | `[width, height]` of what you are drawing into, from the live handle |
464
- | `frame.describe(handle)` | the descriptor of any resource, for a pass that has to relate two of them |
465
- | `frame.is_open` | records are per-frame. A record held past the end of the frame is a retained handle by another name, and both reading and publishing through one say so |
466
-
467
- ### Not built yet
468
-
469
- Two pieces of the extension design are named in `RENDER_EXTENSION_DESIGN.md` and **do not exist**:
470
- `RenderExtensionRegistry.describe()` (printing the pipeline as data) and `FrameProduct` (opting into
471
- optional frame products such as velocity or a readable copy of the colour). Do not write against
472
- them.
473
-
474
- ---
475
-
476
- ## 7. Rendering somewhere other than the canvas
477
-
478
- ```js
479
- import { GPUTextureContext } from "./renderer/texture/GPUTextureContext.js";
480
-
481
- renderer.render_to_target(camera, scene, dt, GPUTextureContext.fromTexture(texture, renderer.device));
482
- ```
483
-
484
- `render()` *is* this call with the canvas's current texture as the target — the canvas is one target
485
- among others, not a privileged one.
486
-
487
- **The target says where the picture goes, not how big it is.** Everything the frame is built out of —
488
- the G-buffer, the visibility buffer, the depth ping-pong, the temporal history — is sized from
489
- `renderer.output_resolution`, so **the target must be that size**. A caller wanting a different one
490
- calls `renderer.resize()` first and puts the size back afterwards.
491
-
492
- This is what makes a frame readable at all: a canvas texture is configured by the presentation path
493
- and cannot carry `COPY_SRC`; a texture you own can. Thumbnails, asset previews and image-based tests
494
- all go through here.
495
-
496
- ---
497
-
498
- ## 8. Content whose vertices change the dynamic-mesh path
499
-
500
- A trail behind a projectile, a ribbon, a tube along a path, a batch of CPU-simulated particles, a
501
- debug line: content rewritten every frame cannot pay for a meshlet build, and rebuilding meshlets per
502
- frame to force it down the standard path is explicitly not the answer.
503
-
504
- ```js
505
- const mesh = DynamicMesh.from(geometry, [1, 0.5, 0, 1]); // Geometry, not MeshletGeometry
506
-
507
- batch.add(mesh); // DynamicMeshBatch, yours — not the Scene's
508
- mesh.visible = false; // hide without leaving the batch
509
- geometry.needsUpdate = true; // you say when the vertices changed; nothing watches the arrays
510
- ```
511
-
512
- This is **a separate path, not a variant of the standard one.** A `DynamicMesh` holds a plain
513
- `Geometry`, is never in the scene's instance batch, gets no row in the scene database, and is drawn
514
- by a pipeline of its own after the standard geometry path has finished with the frame.
515
-
516
- Drawing it is a `GPUDynamicMeshRenderer` inside an extension of yours (§6). Two things to know:
517
-
518
- **There is one vertex layout and it is fixed** 8 floats: position at `[0..2]`, one reserved slot at
519
- `[3]`, RGBA colour at `[4..7]`. A dynamic mesh is drawn by a single pipeline, so letting each geometry
520
- declare its own attribute set would buy nothing and cost either a pipeline per layout or a shader
521
- that branches per vertex. Your geometry needs a position attribute and an index; a colour attribute is
522
- optional and is multiplied by the mesh's flat `color`.
523
-
524
- **`GPUDynamicMeshRenderer.opaque` chooses blending or depth**, and it is a property of the pass
525
- rather than of a mesh the whole batch moves together. Left `false` the content is blended and only depth-tests,
526
- which is what effects want. Set it and the pass writes depth instead: a solid surface with no meshlet
527
- build behind it has no depth ordering otherwise, and no CPU sort can give it one, because a painter's
528
- order over triangles is wrong wherever two of them interpenetrate.
529
-
530
- Residency is keyed on **the geometry**, not on batch membership, so a mesh that blinks off for a
531
- frame or is removed and re-added keeps its buffers.
532
-
533
- ---
534
-
535
- ## 9. Frame-level switches
536
-
537
- | | |
538
- |---|---|
539
- | `feature_shadows_enabled` | |
540
- | `feature_taa_enabled` | when off, there is no upscale and the phases either side of it are the same size |
541
- | `internal_resolution_scale` | render internally below output resolution; `DynamicResolutionScaling` drives it from frame time |
542
- | `pixel_ratio`, `output_resolution`, `aspect_ratio`, `resize(x, y)` | |
543
- | `motion_blur`, `dof`, `dof_unreal`, `nss`, `restir_di`, `path_tracer` | sub-objects with their own settings |
1
+ # The renderer contract
2
+
3
+ meep 3.0 has one renderer, and this is what it promises.
4
+
5
+ It is written for somebody who has never seen the inside of it: by the end of §3 you have a model on
6
+ the screen, and by the end of §6 you have your own work in the frame. Everything here is the public
7
+ surface — the types you construct, the calls you make, and the two or three places where the answer
8
+ is "no, and here is why".
9
+
10
+ If you are looking for how it works rather than what it promises, the design documents are next to
11
+ the code they describe: `renderer/extension/RENDER_EXTENSION_DESIGN.md`,
12
+ `renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md`, `renderer/geometry/meshlet/README.md`,
13
+ `renderer/NOTES.md`.
14
+
15
+ ---
16
+
17
+ ## 1. What it is
18
+
19
+ A **GPU-driven, visibility-buffer deferred renderer on WebGPU.** Geometry is clustered into meshlets
20
+ ahead of time and lives in one large GPU buffer; culling runs on the GPU; the rasterizer writes a
21
+ visibility buffer and a G-buffer rather than shading as it draws; lights are binned into froxels and
22
+ applied deferred; and the result is temporally resolved, upscaled, tonemapped and presented.
23
+
24
+ Three consequences that shape everything below:
25
+
26
+ - **A mesh is a small GPU-resident record, not a draw call you own.** You add a `Mesh` to a `Scene`;
27
+ what is drawn, in what order, and whether it is culled is the renderer's.
28
+ - **Preparing geometry is a precompute.** Meshlet building, encoding and BVH construction happen
29
+ once per geometry. Content that rewrites its vertices every frame goes down a separate path (§8).
30
+ - **The frame is a closed sequence with declared injection points.** You do not insert a pass
31
+ anywhere; you register an extension against a phase (§6).
32
+
33
+ ### What is deliberately absent
34
+
35
+ | | |
36
+ |---|---|
37
+ | **No RHI, no backend abstraction** | There is one target, WebGPU. There is no seam where a second one would go, and adding one is not a small change. |
38
+ | **No WebGL fallback** | Below-floor hardware gets a clean failure message (§2), not a degraded picture. |
39
+ | **No degradation tiers** | There is one pipeline. Individual features can be switched off (`feature_shadows_enabled`, `feature_taa_enabled`, the resolution scale), but there is no "low quality" build of the frame. |
40
+ | **No compressed textures** | DDS, Draco and Basis are not supported anywhere. glTF files carrying `MSFT_texture_dds` load from their base PNG source. |
41
+
42
+ ---
43
+
44
+ ## 2. The device floor
45
+
46
+ The renderer requires a WebGPU device that meets a fixed floor. There is no feature detection
47
+ beyond it and no branch that produces a lesser frame.
48
+
49
+ **Required features** — the adapter must have both, or startup fails:
50
+
51
+ - `indirect-first-instance` — indirect draw is used throughout
52
+ - `float32-blendable` — order-independent transparency
53
+
54
+ **Required limits:**
55
+
56
+ - `maxStorageBuffersPerShaderStage` ≥ **10** (checked against the adapter before the device is
57
+ requested, so the failure names the number the adapter offered)
58
+ - `maxColorAttachmentBytesPerSample` **32** the G-buffer is wide
59
+ - `maxBufferSize` and `maxStorageBufferBindingSize` are requested at whatever the adapter offers,
60
+ because the defaults are far too small
61
+
62
+ **Taken when offered, never required:** `timestamp-query`, `subgroups`, `texture-formats-tier1`.
63
+ `timestamp-query` drives GPU timers and nothing else, and some browsers withhold it on hardware that
64
+ is otherwise fine — so the timers go quiet when it is absent rather than the renderer refusing to
65
+ start.
66
+
67
+ ### When it is not met
68
+
69
+ `Renderer.initialize()` throws a `ShadeDeviceFailure`, whose `message` is written to be shown to a
70
+ person rather than logged. It distinguishes:
71
+
72
+ | | |
73
+ |---|---|
74
+ | `webgpu_unavailable` | no `navigator.gpu` — WebGPU disabled or unsupported |
75
+ | `adapter_unavailable` | no adapter at all |
76
+ | `below_floor` | an adapter that does not meet §2, with the detail |
77
+ | `device_request_failed` | the adapter refused the device |
78
+ | `device_lost` | a working device went away while running |
79
+
80
+ A device lost while running arrives on `Renderer.onDeviceFailure` instead of being thrown. **The
81
+ renderer does not recover a lost device.** Everything it built lived on it, and the honest response
82
+ is a message and a reload. The signal exists so an application can say so and save what it has.
83
+
84
+ ---
85
+
86
+ ## 3. Putting a model on the screen
87
+
88
+ meep has no module aliases: every import is a relative path, and the ones below are written from
89
+ `src/shade/` so they read like the tree in §10.
90
+
91
+ ```js
92
+ import { Renderer } from "./renderer/Renderer.js";
93
+ import { Scene } from "./renderer/scene/Scene.js";
94
+ import { PerspectiveCamera } from "./renderer/camera/PerspectiveCamera.js";
95
+ import { make_sunlight } from "./renderer/light/make_sunlight.js";
96
+ import { load_gltf } from "./renderer/loader/gltf/load_gltf.js";
97
+ import { create_frame_loop } from "./renderer/create_frame_loop.js";
98
+ import { DEG_TO_RAD } from "../core/math/DEG_TO_RAD.js";
99
+ import Vector3 from "../core/geom/Vector3.js";
100
+
101
+ const canvas = document.querySelector("canvas");
102
+
103
+ const renderer = new Renderer();
104
+
105
+ await renderer.initialize({ context: canvas.getContext("webgpu") });
106
+
107
+ const camera = new PerspectiveCamera();
108
+
109
+ camera.transform.position.set(0, 2, -5);
110
+ camera.transform.lookAt(Vector3.zero);
111
+ camera.near = 0.1;
112
+ camera.far = 200;
113
+ camera.fov = 72 * DEG_TO_RAD;
114
+ camera.aspect = renderer.aspect_ratio;
115
+
116
+ const scene = new Scene();
117
+
118
+ // nothing is lit without one, and the deferred shading pass has no default light
119
+ scene.lights.add(make_sunlight({ intensity: 2.2 }));
120
+
121
+ const bundle = await load_gltf("model.glb", { assetManager });
122
+
123
+ scene.add(bundle.scenes);
124
+
125
+ create_frame_loop(dt => renderer.render(camera, scene, dt));
126
+ ```
127
+
128
+ That is the whole of it. Five things in it are worth stating outright.
129
+
130
+ **`initialize` is asynchronous and may fail normally.** Acquiring a WebGPU device has no synchronous
131
+ form and being refused one is an ordinary outcome, so it is a rejected promise carrying a
132
+ `ShadeDeviceFailure` rather than a constructor that throws. Omit `context` and a full-viewport canvas
133
+ is created for you; pass a `device` to share one you already have.
134
+
135
+ **`assetManager` is required, and here is where one comes from.** A glTF is several files — a
136
+ container, its `.bin` buffers, its images and which of them are already in memory is not the
137
+ parser's business to know. Every request the parse makes goes back through the manager, so they are
138
+ cached, counted and cancellable like anything else the application loads. Two loaders are all
139
+ `load_gltf` asks for:
140
+
141
+ ```js
142
+ const assetManager = new AssetManager({ context: {}, executor: new ConcurrentExecutor() });
143
+
144
+ await assetManager.registerLoader(GameAssetType.ArrayBuffer, new ArrayBufferLoader());
145
+ await assetManager.registerLoader(GameAssetType.ImageBitmap, new ImageBitmapAssetLoader());
146
+
147
+ assetManager.startup();
148
+ ```
149
+
150
+ Pass a `scope` alongside it to tie a whole load to one cancellable unit, and a `fileMap` when the
151
+ files come from a drop rather than from the network. An application already running meep's `Engine`
152
+ has a configured manager on it and should use that one.
153
+
154
+ **A model does not have to come from a file.** Everything `load_gltf` produces you can build
155
+ directly, which is §4 in the other direction and needs no asset manager at all:
156
+
157
+ ```js
158
+ const mesh = new Mesh();
159
+
160
+ mesh.geometry = meshlet_geometry_build_from_geometry(make_torus_knot_geometry(1, 0.3, 128, 16));
161
+ mesh.material = new StandardShadeMaterial();
162
+
163
+ mesh.transform_local.setTranslation(0, 1, 0);
164
+ mesh.updateMatrices();
165
+
166
+ scene.add(mesh);
167
+ ```
168
+
169
+ **`render` returns a boolean.** `false` means the previous frame has not finished and this one was
170
+ not submitted. It is not an error.
171
+
172
+ **`scene.add` takes a node or an array of them, and it recurses.** Nodes tagged `isLight` are routed
173
+ to `scene.lights`, everything else into `scene.instances`; `scene.remove` mirrors it exactly.
174
+
175
+ ---
176
+
177
+ ## 4. The type model
178
+
179
+ Everything in a scene is a **`Node3D`**: a TRS transform, a parent and children, and a row in the GPU
180
+ scene-graph. `Scene` is itself a `Node3D` and occupies row 0, so posing the scene world-shifts
181
+ everything under it.
182
+
183
+ **A node is placed through `transform_local`, and everything else about where it is, is derived.**
184
+ `transform_global` is recomputed from the local transform and the parent chain by `updateMatrices()`,
185
+ which is also what refreshes a `Mesh`'s world-space bounds so writing `transform_global` directly is
186
+ undone the moment anything refreshes, and mutating `transform_local` without calling
187
+ `updateMatrices()` leaves both the global transform and the bounds stale. A version counter on the
188
+ node records the refresh, and the renderer compares against it.
189
+
190
+ **A node's transform and a camera's are different types, deliberately, and this is the one place a
191
+ newcomer will trip.** `Node3D.transform_local` is a `Transform64`: a flat `Float64Array` holding its
192
+ own matrix, posed through `setTranslation(x, y, z)` / `setRotation(x, y, z, w)` / `setScale(x, y, z)`,
193
+ with the buffer layout part of its contract so hot code can write it directly. A `Camera` is **not**
194
+ a `Node3D` it carries meep's ECS `Transform`, whose `position`, `rotation` and `scale` are
195
+ observable vectors you assign into. The two keep distinct shapes on purpose and neither has the
196
+ other's accessors: `node.transform_local.position` is `undefined`, and so is
197
+ `camera.transform.translation`.
198
+
199
+ ```js
200
+ node.transform_local.setTranslation(0, 1, 0); // Transform64 — then updateMatrices()
201
+ camera.transform.position.set(0, 2, -5); // Transform reactive, no refresh call
202
+ ```
203
+
204
+ ```
205
+ Scene (Node3D, row 0)
206
+ ├── lights LightCollection — their own pipeline, not in the instance batch
207
+ └── instances InstanceBatch
208
+ ├── nodes every Node3D ever added, in insertion order
209
+ └── instances the Mesh-bearing subset, which is what the rasterizer iterates
210
+ ```
211
+
212
+ A **`Mesh`** is a `Node3D` plus two fields:
213
+
214
+ ```js
215
+ mesh.geometry // MeshletGeometry — what to draw
216
+ mesh.material // ShadeMaterial how to draw it
217
+ ```
218
+
219
+ and a world-space `bounding_box` / `bounding_sphere` the renderer keeps for culling.
220
+
221
+ ### Geometry: two types, one of which is a precompute
222
+
223
+ **`Geometry`** is the authoring form: named `Attribute`s over typed arrays, an optional index, a
224
+ `bounding_box`/`bounding_sphere` computed on demand by `ensureBounds()`, and a `version` you bump
225
+ through `needsUpdate = true` when you rewrite the arrays. Attributes are read by name:
226
+
227
+ ```js
228
+ geometry.getAttribute(StandardAttributes.Position).data // Float32Array
229
+ geometry.index.data // Uint32Array
230
+ ```
231
+
232
+ Seven generators ship, all returning a `Geometry`, in `renderer/geometry/primitives/`:
233
+ `make_box_geometry`, `make_plane_geometry`, `make_polyhedron_geometry`, `make_octahedron_geometry`,
234
+ `make_torus_geometry`, `make_cylinder_geometry`, `make_torus_knot_geometry`.
235
+
236
+ **`MeshletGeometry`** is the GPU form: triangles clustered into meshlets, attributes encoded, and a
237
+ BVH over the clusters. This is what a `Mesh` carries, and it is what buys cluster culling and a
238
+ compact residency.
239
+
240
+ ```js
241
+ const meshlets = meshlet_geometry_build_from_geometry(geometry);
242
+ ```
243
+
244
+ **That build is a precompute.** Do it once, when the content is created or loaded. If your vertices
245
+ change every frame, you are on the wrong path see §8.
246
+
247
+ ### Materials
248
+
249
+ `ShadeMaterial` is the base: `transparency_mode`, `draw_mode` and `draw_side`.
250
+
251
+ **`draw_side` is part of the rasterization bucket key, and it changes what is drawn.** `Front` (the
252
+ default) culls back faces, `Back` culls front faces, and `Double` culls neither — the three map
253
+ straight onto the pipeline's cull mode, so a bucket exists per side that any material in the scene
254
+ asks for. A face seen from behind is shaded with its normal flipped, so `Double` is a working
255
+ double-sided material and not a hint. glTF `doubleSided: true` arrives as `Double` and stays that
256
+ way; the loader's fix-up pass only rewrites `Back` to `Front`, by flipping the geometry.
257
+
258
+ Shadow passes invert the mapping `Front` culls *front* faces there so a one-sided surface casts
259
+ from its back face and does not shadow-acne against its own lit side. `Double` has no opposite and
260
+ stays unculled in both.
261
+
262
+ `StandardShadeMaterial` is the PBR one everything uses:
263
+
264
+ | | |
265
+ |---|---|
266
+ | `texture_albedo` | base colour, alpha carries transparency |
267
+ | `diffuse_color` | multiplied with the albedo |
268
+ | `texture_normal` | tangent-space normals |
269
+ | `texture_orm` | occlusion / roughness (G) / metalness (B), as glTF packs it |
270
+ | `texture_emissive`, `emissive_factor` | |
271
+ | `roughness_factor`, `metallic_factor` | multiplied with the ORM texture |
272
+ | `transmission_factor`, `ior_factor` | |
273
+ | `ambient_factors` | a `LinearModifier` over the indirect contribution |
274
+ | `vt_stack` | opt-in virtual texturing; when set, albedo/normal/ORM come from streamed pages instead. Opaque materials only |
275
+
276
+ ### Textures
277
+
278
+ Two objects, and the split matters: **`ShadeImage`** is the pixels, **`ShadeTexture`** is how to
279
+ sample them. Two materials sampling one image differently are two textures over one image, and the
280
+ image is uploaded once.
281
+
282
+ ```js
283
+ const image = ShadeImage.fromImageBitmap(bitmap); // or fromSampler2D, or fromArrayBuffer
284
+ const texture = ShadeTexture.from(image);
285
+
286
+ texture.wrapS = TextureWrapType.Repeat;
287
+ texture.magFilter = TextureFilterType.Linear;
288
+ ```
289
+
290
+ `ShadeTexture` carries filters, wrap modes and flags (mipmap generation is on by default), and both
291
+ types answer `equals`/`hash`, which is what lets the renderer de-duplicate uploads.
292
+
293
+ ### What a glTF becomes
294
+
295
+ `load_gltf` returns a **`SceneBundle`**three arrays out of the one file:
296
+
297
+ ```js
298
+ bundle.scenes // Node3D[] — the scene roots, ready for scene.add
299
+ bundle.skins // Skin[] — for GPUAnimationManager.register_skin
300
+ bundle.clips // ShadeAnimationClip[] — for register_clip
301
+ ```
302
+
303
+ The bundle is **the model as loaded, not a placement of it.** Adding one bundle's roots to two
304
+ scenes, or twice to one scene, shares nodes. meep's ECS layer provides
305
+ `instantiate_scene_bundle(bundle)` for the copy a second placement needs — its own nodes, its own
306
+ skin and its own retargeted clips — which is what makes two of one model possible.
307
+
308
+ ---
309
+
310
+ ## 5. The frame
311
+
312
+ ```
313
+ FrameStart view updated, nothing rasterized
314
+
315
+ [ visibility buffer + G-buffer ]
316
+ AfterGBuffer surface properties written and readable, nothing lit
317
+
318
+ [ clustered lighting, deferred shading, volumetrics ]
319
+ AfterLighting opaque lit and composited
320
+
321
+ [ transparency ]
322
+ AfterTransparency the complete scene, HDR, internal resolution
323
+
324
+ [ TAA / NSS upscale ] ← resolution changes here
325
+ BeforePresent HDR, output resolution, immediately before tonemapping
326
+
327
+ [ tonemap → canvas ]
328
+ Overlay display space, drawing onto the canvas
329
+ ```
330
+
331
+ **The upscale is a phase boundary and it is the one thing about the frame you cannot assume away.**
332
+ Three phases are before it and two are after. With `feature_taa_enabled === false` there is no
333
+ upscale and the two sides are the same size. Nothing in this document states a resolution as a
334
+ constant: ask `frame.resolution`, which is derived from the live handle and is right in every
335
+ configuration, including under dynamic resolution scaling.
336
+
337
+ ---
338
+
339
+ ## 6. Adding your own work to the frame — render extensions
340
+
341
+ An extension is **a named object with declarations and one method**.
342
+
343
+ ```js
344
+ import { RenderExtension } from "./renderer/extension/RenderExtension.js";
345
+ import { FramePhase } from "./renderer/extension/FramePhase.js";
346
+ import { SceneColor } from "./renderer/extension/SceneColor.js";
347
+ import { ViewTextures } from "./renderer/extension/ViewTextures.js";
348
+
349
+ class TrailExtension extends RenderExtension {
350
+ name = "trails";
351
+
352
+ phase = FramePhase.AfterTransparency;
353
+
354
+ record(frame) {
355
+ if (this.#batch.count === 0) {
356
+ // nothing to draw, and the frame's colour is left exactly as it was
357
+ return;
358
+ }
359
+
360
+ const scene = frame.get(SceneColor);
361
+
362
+ scene.color = this.#renderer.graph_draw({
363
+ graph: frame.graph,
364
+ batch: this.#batch,
365
+ color: scene.color,
366
+ depth: frame.get(ViewTextures).depth,
367
+ camera: frame.view.camera.buffer
368
+ });
369
+ }
370
+ }
371
+
372
+ const registered = renderer.add_extension(new TrailExtension());
373
+ // ...
374
+ renderer.remove_extension(registered);
375
+ ```
376
+
377
+ That is the whole mechanism. The rest of this section is what the four lines of it mean.
378
+
379
+ ### Records are the channel
380
+
381
+ `record(frame)` **returns nothing.** Everything an extension exchanges with the frame goes through
382
+ typed **records**: you read a frame-graph handle out of one and write a replacement back, and
383
+ **writing a field is publication** — everything after you carries what you left.
384
+
385
+ There is no privileged resource. The scene colour is published exactly the way a G-buffer target is,
386
+ and exactly the way a record of your own is.
387
+
388
+ | record | carried at | writable |
389
+ |---|---|---|
390
+ | `SceneColor` `.color`, HDR | `AfterLighting` `BeforePresent` | yes |
391
+ | `GBufferTextures` — `.albedo` (AO in alpha), `.normal`, `.pbr`, `.emissive` | `AfterGBuffer` … `BeforePresent` | **`AfterGBuffer` only** |
392
+ | `ViewTextures` `.depth`, `.depth_previous`, `.visibility_mesh`, `.visibility_triangle` | `AfterGBuffer` `BeforePresent` | yes |
393
+ | `PresentTarget` `.canvas` | `Overlay` only | yes |
394
+
395
+ Three of those rows are the whole reason phases exist:
396
+
397
+ - **`SceneColor` is not carried at `Overlay`.** A texture may not be a render attachment and a
398
+ sampled source in the same pass, so at `Overlay` the canvas is written and cannot be read. An
399
+ effect that needs the finished image as *input* a colour grade, a full-screen re-composite
400
+ belongs at `BeforePresent`. You find that out from `frame.get(SceneColor)`, which fails with a
401
+ sentence naming the phases that do carry it, rather than from a `-1` failing inside a binding
402
+ builder.
403
+ - **`GBufferTextures` is in/out at `AfterGBuffer` and frozen afterwards.** Changing surface
404
+ properties means reading the targets, writing replacements and publishing the new handles — two of
405
+ the four are integer formats and cannot be blended, and nothing can be attachment and source at
406
+ once. It stays *readable* to `BeforePresent` because outline and selection effects legitimately
407
+ read it late; at that phase it is on the far side of the upscale and is therefore **a different
408
+ size from the colour beside it**. `frame.describe(handle)` is how a pass working across that
409
+ boundary learns the ratio.
410
+ - **`PresentTarget` has one field and is not called `SceneColor` on purpose.** There is no colour
411
+ there to be tempted by. Keep the existing contents with a `load` op, write only your own pixels,
412
+ and publish the result back — that is what lets two overlay extensions compose.
413
+
414
+ ### Extending the vocabulary
415
+
416
+ An extension can publish a record of its own for another extension to read, and doing so costs no
417
+ edit to the renderer:
418
+
419
+ ```js
420
+ class VisibilityGrid extends FrameRecord {
421
+ #grid = -1;
422
+
423
+ static is_present_at(phase) { return true; }
424
+
425
+ get grid() { return this.read(this.#grid); }
426
+ set grid(handle) { this.#grid = this.publish(handle); }
427
+ }
428
+
429
+ // at FrameStart
430
+ frame.create(VisibilityGrid).grid = record_the_grid_update(frame.graph);
431
+
432
+ // at AfterTransparency, in another extension
433
+ if (frame.has(VisibilityGrid)) { frame.get(VisibilityGrid).grid … }
434
+ ```
435
+
436
+ `has` / `get` / `create` are three calls rather than one `get_or_create` because **absent has to stay
437
+ distinguishable from empty.**
438
+
439
+ ### Ordering
440
+
441
+ Order is **declared**, never emergent:
442
+
443
+ ```js
444
+ class DecalExtension extends RenderExtension {
445
+ phase = FramePhase.AfterGBuffer;
446
+ after = [TerrainSplatExtension]; // classes, not instances
447
+ before = [];
448
+ }
449
+ ```
450
+
451
+ Constraints name classes, so you do not need a reference to another system's object to state an
452
+ order, and a class nobody registered is simply not a constraint. Two extensions on one phase with no
453
+ path between them record in **ascending `name` order** reproducible rather than correct, and chosen
454
+ precisely so that adding an `await` to a system's startup cannot change the picture. A cycle is
455
+ reported with the names on it.
456
+
457
+ ### What keeps your work alive
458
+
459
+ The graph elides work whose output nothing consumes, and that applies to an extension exactly as it
460
+ does to a built-in pass. Thread a result into a record and it is consumed. Write something imported
461
+ the canvas, an imported textureand it is a side effect. Want work that runs regardless and
462
+ `make_side_effect()` on the pass builder says so.
463
+
464
+ **An extension whose whole recording is elided is a correct, cheaper frame, not a failure**, and
465
+ nothing reports it as one. It is a grey cluster with your extension's name on it in a graph dump.
466
+
467
+ ### The rest of `FrameContext`
468
+
469
+ | | |
470
+ |---|---|
471
+ | `frame.graph` | the frame's `FrameGraph`. Record into it with the `graph_*` helpers, exactly as the built-in passes do |
472
+ | `frame.view` | the `GPUViewContext` — camera, uniforms, frame index |
473
+ | `frame.phase` | which phase this is |
474
+ | `frame.resolution` | `[width, height]` of what you are drawing into, from the live handle |
475
+ | `frame.describe(handle)` | the descriptor of any resource, for a pass that has to relate two of them |
476
+ | `frame.is_open` | records are per-frame. A record held past the end of the frame is a retained handle by another name, and both reading and publishing through one say so |
477
+
478
+ ### Not built yet
479
+
480
+ Two pieces of the extension design are named in `RENDER_EXTENSION_DESIGN.md` and **do not exist**:
481
+ `RenderExtensionRegistry.describe()` (printing the pipeline as data) and `FrameProduct` (opting into
482
+ optional frame products such as velocity or a readable copy of the colour). Do not write against
483
+ them.
484
+
485
+ ---
486
+
487
+ ## 7. Rendering somewhere other than the canvas
488
+
489
+ ```js
490
+ import { GPUTextureContext } from "./renderer/texture/GPUTextureContext.js";
491
+
492
+ renderer.render_to_target(camera, scene, dt, GPUTextureContext.fromTexture(texture, renderer.device));
493
+ ```
494
+
495
+ `render()` *is* this call with the canvas's current texture as the target — the canvas is one target
496
+ among others, not a privileged one.
497
+
498
+ **The target says where the picture goes, not how big it is.** Everything the frame is built out of —
499
+ the G-buffer, the visibility buffer, the depth ping-pong, the temporal history — is sized from
500
+ `renderer.output_resolution`, so **the target must be that size**. A caller wanting a different one
501
+ calls `renderer.resize()` first and puts the size back afterwards.
502
+
503
+ This is what makes a frame readable at all: a canvas texture is configured by the presentation path
504
+ and cannot carry `COPY_SRC`; a texture you own can. Thumbnails, asset previews and image-based tests
505
+ all go through here.
506
+
507
+ ---
508
+
509
+ ## 8. Content whose vertices change the dynamic-mesh path
510
+
511
+ A trail behind a projectile, a ribbon, a tube along a path, a batch of CPU-simulated particles, a
512
+ debug line: content rewritten every frame cannot pay for a meshlet build, and rebuilding meshlets per
513
+ frame to force it down the standard path is explicitly not the answer.
514
+
515
+ ```js
516
+ const mesh = DynamicMesh.from(geometry, [1, 0.5, 0, 1]); // Geometry, not MeshletGeometry
517
+
518
+ batch.add(mesh); // DynamicMeshBatch, yoursnot the Scene's
519
+ mesh.visible = false; // hide without leaving the batch
520
+ geometry.needsUpdate = true; // you say when the vertices changed; nothing watches the arrays
521
+ ```
522
+
523
+ This is **a separate path, not a variant of the standard one.** A `DynamicMesh` holds a plain
524
+ `Geometry`, is never in the scene's instance batch, gets no row in the scene database, and is drawn
525
+ by a pipeline of its own after the standard geometry path has finished with the frame.
526
+
527
+ Drawing it is a `GPUDynamicMeshRenderer` inside an extension of yours (§6). Two things to know:
528
+
529
+ **There is one vertex layout and it is fixed** — 8 floats: position at `[0..2]`, one reserved slot at
530
+ `[3]`, RGBA colour at `[4..7]`. A dynamic mesh is drawn by a single pipeline, so letting each geometry
531
+ declare its own attribute set would buy nothing and cost either a pipeline per layout or a shader
532
+ that branches per vertex. Your geometry needs a position attribute and an index; a colour attribute is
533
+ optional and is multiplied by the mesh's flat `color`.
534
+
535
+ **`GPUDynamicMeshRenderer.opaque` chooses blending or depth**, and it is a property of the pass
536
+ rather than of a mesh — the whole batch moves together. Left `false` the content is blended and only depth-tests,
537
+ which is what effects want. Set it and the pass writes depth instead: a solid surface with no meshlet
538
+ build behind it has no depth ordering otherwise, and no CPU sort can give it one, because a painter's
539
+ order over triangles is wrong wherever two of them interpenetrate.
540
+
541
+ Residency is keyed on **the geometry**, not on batch membership, so a mesh that blinks off for a
542
+ frame or is removed and re-added keeps its buffers.
543
+
544
+ ---
545
+
546
+ ## 9. Frame-level switches
547
+
548
+ | | |
549
+ |---|---|
550
+ | `feature_shadows_enabled` | |
551
+ | `feature_taa_enabled` | when off, there is no upscale and the phases either side of it are the same size |
552
+ | `internal_resolution_scale` | render internally below output resolution; `DynamicResolutionScaling` drives it from frame time |
553
+ | `pixel_ratio`, `output_resolution`, `aspect_ratio`, `resize(x, y)` | |
554
+ | `motion_blur`, `dof`, `dof_unreal`, `nss`, `restir_di`, `path_tracer` | sub-objects with their own settings |
544
555
  | `frame_count` | |
545
- | `profile_session` | assign a `GPUProfileSession` to record GPU timings; null when nothing is profiling |
546
-
547
- ---
548
-
549
- ## 10. Where things live
550
-
551
- ```
552
- shade/renderer/
553
- ├── Renderer.js the whole surface in §2, §7, §9
554
- ├── scene/ Scene, Node3D, Mesh, SkinnedMesh, DynamicMesh, InstanceBatch
555
- ├── geometry/ Geometry, MeshletGeometry, the builders, primitives/
556
- ├── material/ ShadeMaterial, StandardShadeMaterial
557
- ├── texture/ ShadeTexture, GPUTextureContext, source/ShadeImage
558
- ├── light/ LightCollection, make_sunlight, model/{Light,DirectionalLight,PointLight,SpotLight}
559
- ├── camera/ PerspectiveCamera
560
- ├── loader/gltf/ load_gltf, SceneBundle
561
- ├── extension/ RenderExtension, FrameContext, FrameRecord, the four records
562
- ├── dynamic/ GPUDynamicMeshRenderer and its one vertex layout
563
- └── animation/ GPUAnimationManager — skins and clips
564
- ```
565
-
566
- `shade/device/mock/` holds a **validating software device**: no shader execution, but real validation
567
- of bindings, passes, resources and texture copies. It is how Shade's own tests run without a GPU, and
568
- it is available to yours. Specs must never acquire a real device — see `vitest.config.mjs`, which
569
- explains at length why.
556
+ | `profile_session` | assign a `GPUProfileSession` to record GPU timings; null when nothing is profiling |
557
+
558
+ ---
559
+
560
+ ## 10. Where things live
561
+
562
+ ```
563
+ shade/renderer/
564
+ ├── Renderer.js the whole surface in §2, §7, §9
565
+ ├── scene/ Scene, Node3D, Mesh, SkinnedMesh, DynamicMesh, InstanceBatch
566
+ ├── geometry/ Geometry, MeshletGeometry, the builders, primitives/
567
+ ├── material/ ShadeMaterial, StandardShadeMaterial
568
+ ├── texture/ ShadeTexture, GPUTextureContext, source/ShadeImage
569
+ ├── light/ LightCollection, make_sunlight, model/{Light,DirectionalLight,PointLight,SpotLight}
570
+ ├── camera/ PerspectiveCamera
571
+ ├── loader/gltf/ load_gltf, SceneBundle
572
+ ├── extension/ RenderExtension, FrameContext, FrameRecord, the four records
573
+ ├── dynamic/ GPUDynamicMeshRenderer and its one vertex layout
574
+ └── animation/ GPUAnimationManager — skins and clips
575
+ ```
576
+
577
+ `shade/device/mock/` holds a **validating software device**: no shader execution, but real validation
578
+ of bindings, passes, resources and texture copies. It is how the renderer's own tests run without a
579
+ GPU, and it is available to yours. Specs must never acquire a real device — see `vitest.config.mjs`,
580
+ which explains at length why.