@woosh/meep-engine 3.8.0 → 3.10.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 (735) hide show
  1. package/build/bundle-worker-image-decoder.js +1 -1
  2. package/build/bundle-worker-terrain.js +1 -1
  3. package/package.json +3 -2
  4. package/src/avif/encode_image_source.d.ts +70 -0
  5. package/src/avif/encode_image_source.d.ts.map +1 -0
  6. package/src/avif/encode_image_source.js +117 -0
  7. package/src/avif/encoder_worker.js +15 -126
  8. package/src/avif/index.d.ts +4 -2
  9. package/src/avif/index.js +21 -2
  10. package/src/avif/native/DECISIONS.md +537 -0
  11. package/src/avif/native/NOTICE.md +61 -0
  12. package/src/avif/native/api/AvifDecoder.d.ts +67 -0
  13. package/src/avif/native/api/AvifDecoder.d.ts.map +1 -0
  14. package/src/avif/native/api/AvifDecoder.js +121 -0
  15. package/src/avif/native/api/apply_transformations.d.ts +30 -0
  16. package/src/avif/native/api/apply_transformations.d.ts.map +1 -0
  17. package/src/avif/native/api/apply_transformations.js +120 -0
  18. package/src/avif/native/api/avif_to_sampler2d.d.ts +25 -0
  19. package/src/avif/native/api/avif_to_sampler2d.d.ts.map +1 -0
  20. package/src/avif/native/api/avif_to_sampler2d.js +42 -0
  21. package/src/avif/native/api/convert_to_rgba.d.ts +54 -0
  22. package/src/avif/native/api/convert_to_rgba.d.ts.map +1 -0
  23. package/src/avif/native/api/convert_to_rgba.js +204 -0
  24. package/src/avif/native/api/decode_avif.d.ts +24 -0
  25. package/src/avif/native/api/decode_avif.d.ts.map +1 -0
  26. package/src/avif/native/api/decode_avif.js +111 -0
  27. package/src/avif/native/api/decode_image_item.d.ts +18 -0
  28. package/src/avif/native/api/decode_image_item.d.ts.map +1 -0
  29. package/src/avif/native/api/decode_image_item.js +234 -0
  30. package/src/avif/native/api/encode_avif.d.ts +73 -0
  31. package/src/avif/native/api/encode_avif.d.ts.map +1 -0
  32. package/src/avif/native/api/encode_avif.js +488 -0
  33. package/src/avif/native/api/sampler2d_to_avif.d.ts +22 -0
  34. package/src/avif/native/api/sampler2d_to_avif.d.ts.map +1 -0
  35. package/src/avif/native/api/sampler2d_to_avif.js +108 -0
  36. package/src/avif/native/av1/decode/Av1FrameContext.d.ts +286 -0
  37. package/src/avif/native/av1/decode/Av1FrameContext.d.ts.map +1 -0
  38. package/src/avif/native/av1/decode/Av1FrameContext.js +622 -0
  39. package/src/avif/native/av1/decode/block_decoded.d.ts +27 -0
  40. package/src/avif/native/av1/decode/block_decoded.d.ts.map +1 -0
  41. package/src/avif/native/av1/decode/block_decoded.js +59 -0
  42. package/src/avif/native/av1/decode/decode_av1_still.d.ts +22 -0
  43. package/src/avif/native/av1/decode/decode_av1_still.d.ts.map +1 -0
  44. package/src/avif/native/av1/decode/decode_av1_still.js +309 -0
  45. package/src/avif/native/av1/decode/decode_coefficients.d.ts +20 -0
  46. package/src/avif/native/av1/decode/decode_coefficients.d.ts.map +1 -0
  47. package/src/avif/native/av1/decode/decode_coefficients.js +259 -0
  48. package/src/avif/native/av1/decode/decode_palette.d.ts +28 -0
  49. package/src/avif/native/av1/decode/decode_palette.d.ts.map +1 -0
  50. package/src/avif/native/av1/decode/decode_palette.js +442 -0
  51. package/src/avif/native/av1/decode/decode_tile.d.ts +14 -0
  52. package/src/avif/native/av1/decode/decode_tile.d.ts.map +1 -0
  53. package/src/avif/native/av1/decode/decode_tile.js +1213 -0
  54. package/src/avif/native/av1/decode/get_scan.d.ts +16 -0
  55. package/src/avif/native/av1/decode/get_scan.d.ts.map +1 -0
  56. package/src/avif/native/av1/decode/get_scan.js +138 -0
  57. package/src/avif/native/av1/decode/read_lr.d.ts +35 -0
  58. package/src/avif/native/av1/decode/read_lr.d.ts.map +1 -0
  59. package/src/avif/native/av1/decode/read_lr.js +277 -0
  60. package/src/avif/native/av1/decode/read_transform_type.d.ts +19 -0
  61. package/src/avif/native/av1/decode/read_transform_type.d.ts.map +1 -0
  62. package/src/avif/native/av1/decode/read_transform_type.js +92 -0
  63. package/src/avif/native/av1/decode/reconstruct.d.ts +36 -0
  64. package/src/avif/native/av1/decode/reconstruct.d.ts.map +1 -0
  65. package/src/avif/native/av1/decode/reconstruct.js +241 -0
  66. package/src/avif/native/av1/decode/transform_type.d.ts +49 -0
  67. package/src/avif/native/av1/decode/transform_type.d.ts.map +1 -0
  68. package/src/avif/native/av1/decode/transform_type.js +137 -0
  69. package/src/avif/native/av1/encode/Av1BlockSnapshot.d.ts +81 -0
  70. package/src/avif/native/av1/encode/Av1BlockSnapshot.d.ts.map +1 -0
  71. package/src/avif/native/av1/encode/Av1BlockSnapshot.js +299 -0
  72. package/src/avif/native/av1/encode/Av1EncodeContext.d.ts +384 -0
  73. package/src/avif/native/av1/encode/Av1EncodeContext.d.ts.map +1 -0
  74. package/src/avif/native/av1/encode/Av1EncodeContext.js +590 -0
  75. package/src/avif/native/av1/encode/build_headers.d.ts +50 -0
  76. package/src/avif/native/av1/encode/build_headers.d.ts.map +1 -0
  77. package/src/avif/native/av1/encode/build_headers.js +359 -0
  78. package/src/avif/native/av1/encode/choose_chroma_alpha.d.ts +26 -0
  79. package/src/avif/native/av1/encode/choose_chroma_alpha.d.ts.map +1 -0
  80. package/src/avif/native/av1/encode/choose_chroma_alpha.js +90 -0
  81. package/src/avif/native/av1/encode/choose_filters.d.ts +21 -0
  82. package/src/avif/native/av1/encode/choose_filters.d.ts.map +1 -0
  83. package/src/avif/native/av1/encode/choose_filters.js +318 -0
  84. package/src/avif/native/av1/encode/choose_restoration.d.ts +35 -0
  85. package/src/avif/native/av1/encode/choose_restoration.d.ts.map +1 -0
  86. package/src/avif/native/av1/encode/choose_restoration.js +616 -0
  87. package/src/avif/native/av1/encode/decode_effort.d.ts +57 -0
  88. package/src/avif/native/av1/encode/decode_effort.d.ts.map +1 -0
  89. package/src/avif/native/av1/encode/decode_effort.js +59 -0
  90. package/src/avif/native/av1/encode/encode_av1_still.d.ts +17 -0
  91. package/src/avif/native/av1/encode/encode_av1_still.d.ts.map +1 -0
  92. package/src/avif/native/av1/encode/encode_av1_still.js +194 -0
  93. package/src/avif/native/av1/encode/encode_effort.d.ts +56 -0
  94. package/src/avif/native/av1/encode/encode_effort.d.ts.map +1 -0
  95. package/src/avif/native/av1/encode/encode_effort.js +97 -0
  96. package/src/avif/native/av1/encode/encode_tile.d.ts +26 -0
  97. package/src/avif/native/av1/encode/encode_tile.d.ts.map +1 -0
  98. package/src/avif/native/av1/encode/encode_tile.js +2331 -0
  99. package/src/avif/native/av1/encode/quantise.d.ts +51 -0
  100. package/src/avif/native/av1/encode/quantise.d.ts.map +1 -0
  101. package/src/avif/native/av1/encode/quantise.js +212 -0
  102. package/src/avif/native/av1/encode/write_coefficients.d.ts +42 -0
  103. package/src/avif/native/av1/encode/write_coefficients.d.ts.map +1 -0
  104. package/src/avif/native/av1/encode/write_coefficients.js +367 -0
  105. package/src/avif/native/av1/encode/write_lr.d.ts +33 -0
  106. package/src/avif/native/av1/encode/write_lr.d.ts.map +1 -0
  107. package/src/avif/native/av1/encode/write_lr.js +174 -0
  108. package/src/avif/native/av1/encode/write_transform_type.d.ts +21 -0
  109. package/src/avif/native/av1/encode/write_transform_type.d.ts.map +1 -0
  110. package/src/avif/native/av1/encode/write_transform_type.js +70 -0
  111. package/src/avif/native/av1/entropy/CdfContext.d.ts +167 -0
  112. package/src/avif/native/av1/entropy/CdfContext.d.ts.map +1 -0
  113. package/src/avif/native/av1/entropy/CdfContext.js +433 -0
  114. package/src/avif/native/av1/entropy/SymbolReader.d.ts +103 -0
  115. package/src/avif/native/av1/entropy/SymbolReader.d.ts.map +1 -0
  116. package/src/avif/native/av1/entropy/SymbolReader.js +317 -0
  117. package/src/avif/native/av1/entropy/SymbolWriter.d.ts +107 -0
  118. package/src/avif/native/av1/entropy/SymbolWriter.d.ts.map +1 -0
  119. package/src/avif/native/av1/entropy/SymbolWriter.js +352 -0
  120. package/src/avif/native/av1/entropy/coefficient_context.d.ts +71 -0
  121. package/src/avif/native/av1/entropy/coefficient_context.d.ts.map +1 -0
  122. package/src/avif/native/av1/entropy/coefficient_context.js +325 -0
  123. package/src/avif/native/av1/entropy/partition_cdf.d.ts +54 -0
  124. package/src/avif/native/av1/entropy/partition_cdf.d.ts.map +1 -0
  125. package/src/avif/native/av1/entropy/partition_cdf.js +98 -0
  126. package/src/avif/native/av1/entropy/symbol_cost.d.ts +37 -0
  127. package/src/avif/native/av1/entropy/symbol_cost.d.ts.map +1 -0
  128. package/src/avif/native/av1/entropy/symbol_cost.js +76 -0
  129. package/src/avif/native/av1/filter/cdef.d.ts +15 -0
  130. package/src/avif/native/av1/filter/cdef.d.ts.map +1 -0
  131. package/src/avif/native/av1/filter/cdef.js +313 -0
  132. package/src/avif/native/av1/filter/loop_filter.d.ts +14 -0
  133. package/src/avif/native/av1/filter/loop_filter.d.ts.map +1 -0
  134. package/src/avif/native/av1/filter/loop_filter.js +377 -0
  135. package/src/avif/native/av1/filter/loop_restoration.d.ts +42 -0
  136. package/src/avif/native/av1/filter/loop_restoration.d.ts.map +1 -0
  137. package/src/avif/native/av1/filter/loop_restoration.js +451 -0
  138. package/src/avif/native/av1/filter/superres.d.ts +18 -0
  139. package/src/avif/native/av1/filter/superres.d.ts.map +1 -0
  140. package/src/avif/native/av1/filter/superres.js +86 -0
  141. package/src/avif/native/av1/grain/FilmGrainState.d.ts +62 -0
  142. package/src/avif/native/av1/grain/FilmGrainState.d.ts.map +1 -0
  143. package/src/avif/native/av1/grain/FilmGrainState.js +87 -0
  144. package/src/avif/native/av1/grain/film_grain.d.ts +16 -0
  145. package/src/avif/native/av1/grain/film_grain.d.ts.map +1 -0
  146. package/src/avif/native/av1/grain/film_grain.js +623 -0
  147. package/src/avif/native/av1/obu/FrameHeader.d.ts +248 -0
  148. package/src/avif/native/av1/obu/FrameHeader.d.ts.map +1 -0
  149. package/src/avif/native/av1/obu/FrameHeader.js +381 -0
  150. package/src/avif/native/av1/obu/ObuHeader.d.ts +53 -0
  151. package/src/avif/native/av1/obu/ObuHeader.d.ts.map +1 -0
  152. package/src/avif/native/av1/obu/ObuHeader.js +62 -0
  153. package/src/avif/native/av1/obu/SequenceHeader.d.ts +157 -0
  154. package/src/avif/native/av1/obu/SequenceHeader.d.ts.map +1 -0
  155. package/src/avif/native/av1/obu/SequenceHeader.js +225 -0
  156. package/src/avif/native/av1/obu/for_each_obu.d.ts +24 -0
  157. package/src/avif/native/av1/obu/for_each_obu.d.ts.map +1 -0
  158. package/src/avif/native/av1/obu/for_each_obu.js +50 -0
  159. package/src/avif/native/av1/obu/parse_frame_header.d.ts +18 -0
  160. package/src/avif/native/av1/obu/parse_frame_header.d.ts.map +1 -0
  161. package/src/avif/native/av1/obu/parse_frame_header.js +841 -0
  162. package/src/avif/native/av1/obu/parse_obu_header.d.ts +23 -0
  163. package/src/avif/native/av1/obu/parse_obu_header.d.ts.map +1 -0
  164. package/src/avif/native/av1/obu/parse_obu_header.js +69 -0
  165. package/src/avif/native/av1/obu/parse_sequence_header.d.ts +17 -0
  166. package/src/avif/native/av1/obu/parse_sequence_header.d.ts.map +1 -0
  167. package/src/avif/native/av1/obu/parse_sequence_header.js +263 -0
  168. package/src/avif/native/av1/obu/write_frame_header.d.ts +16 -0
  169. package/src/avif/native/av1/obu/write_frame_header.d.ts.map +1 -0
  170. package/src/avif/native/av1/obu/write_frame_header.js +579 -0
  171. package/src/avif/native/av1/obu/write_sequence_header.d.ts +17 -0
  172. package/src/avif/native/av1/obu/write_sequence_header.d.ts.map +1 -0
  173. package/src/avif/native/av1/obu/write_sequence_header.js +189 -0
  174. package/src/avif/native/av1/predict/IntraPredictionState.d.ts +49 -0
  175. package/src/avif/native/av1/predict/IntraPredictionState.d.ts.map +1 -0
  176. package/src/avif/native/av1/predict/IntraPredictionState.js +58 -0
  177. package/src/avif/native/av1/predict/intra_filter_type.d.ts +17 -0
  178. package/src/avif/native/av1/predict/intra_filter_type.d.ts.map +1 -0
  179. package/src/avif/native/av1/predict/intra_filter_type.js +79 -0
  180. package/src/avif/native/av1/predict/predict_chroma_from_luma.d.ts +50 -0
  181. package/src/avif/native/av1/predict/predict_chroma_from_luma.d.ts.map +1 -0
  182. package/src/avif/native/av1/predict/predict_chroma_from_luma.js +153 -0
  183. package/src/avif/native/av1/predict/predict_intra.d.ts +42 -0
  184. package/src/avif/native/av1/predict/predict_intra.d.ts.map +1 -0
  185. package/src/avif/native/av1/predict/predict_intra.js +803 -0
  186. package/src/avif/native/av1/predict/predict_palette.d.ts +23 -0
  187. package/src/avif/native/av1/predict/predict_palette.d.ts.map +1 -0
  188. package/src/avif/native/av1/predict/predict_palette.js +36 -0
  189. package/src/avif/native/av1/tables/av1_symbols.d.ts +411 -0
  190. package/src/avif/native/av1/tables/av1_symbols.d.ts.map +1 -0
  191. package/src/avif/native/av1/tables/av1_symbols.js +419 -0
  192. package/src/avif/native/av1/tables/block_tables.d.ts +181 -0
  193. package/src/avif/native/av1/tables/block_tables.d.ts.map +1 -0
  194. package/src/avif/native/av1/tables/block_tables.js +270 -0
  195. package/src/avif/native/av1/tables/cdf_tables.d.ts +961 -0
  196. package/src/avif/native/av1/tables/cdf_tables.d.ts.map +1 -0
  197. package/src/avif/native/av1/tables/cdf_tables.js +1893 -0
  198. package/src/avif/native/av1/tables/coefficient_tables.d.ts +41 -0
  199. package/src/avif/native/av1/tables/coefficient_tables.d.ts.map +1 -0
  200. package/src/avif/native/av1/tables/coefficient_tables.js +82 -0
  201. package/src/avif/native/av1/tables/derived_block_tables.d.ts +15 -0
  202. package/src/avif/native/av1/tables/derived_block_tables.d.ts.map +1 -0
  203. package/src/avif/native/av1/tables/derived_block_tables.js +23 -0
  204. package/src/avif/native/av1/tables/filter_tables.d.ts +171 -0
  205. package/src/avif/native/av1/tables/filter_tables.d.ts.map +1 -0
  206. package/src/avif/native/av1/tables/filter_tables.js +313 -0
  207. package/src/avif/native/av1/tables/grain_tables.d.ts +11 -0
  208. package/src/avif/native/av1/tables/grain_tables.d.ts.map +1 -0
  209. package/src/avif/native/av1/tables/grain_tables.js +190 -0
  210. package/src/avif/native/av1/tables/prediction_tables.d.ts +141 -0
  211. package/src/avif/native/av1/tables/prediction_tables.d.ts.map +1 -0
  212. package/src/avif/native/av1/tables/prediction_tables.js +223 -0
  213. package/src/avif/native/av1/tables/quantizer_matrix_tables.d.ts +21 -0
  214. package/src/avif/native/av1/tables/quantizer_matrix_tables.d.ts.map +1 -0
  215. package/src/avif/native/av1/tables/quantizer_matrix_tables.js +38 -0
  216. package/src/avif/native/av1/tables/quantizer_tables.d.ts +21 -0
  217. package/src/avif/native/av1/tables/quantizer_tables.d.ts.map +1 -0
  218. package/src/avif/native/av1/tables/quantizer_tables.js +160 -0
  219. package/src/avif/native/av1/tables/scan_tables.d.ts +321 -0
  220. package/src/avif/native/av1/tables/scan_tables.d.ts.map +1 -0
  221. package/src/avif/native/av1/tables/scan_tables.js +727 -0
  222. package/src/avif/native/av1/tables/segmentation_tables.d.ts +31 -0
  223. package/src/avif/native/av1/tables/segmentation_tables.d.ts.map +1 -0
  224. package/src/avif/native/av1/tables/segmentation_tables.js +48 -0
  225. package/src/avif/native/av1/tables/transform_tables.d.ts +91 -0
  226. package/src/avif/native/av1/tables/transform_tables.d.ts.map +1 -0
  227. package/src/avif/native/av1/tables/transform_tables.js +140 -0
  228. package/src/avif/native/av1/tables/unpack_table.d.ts +33 -0
  229. package/src/avif/native/av1/tables/unpack_table.d.ts.map +1 -0
  230. package/src/avif/native/av1/tables/unpack_table.js +73 -0
  231. package/src/avif/native/av1/transform/forward_transform_2d.d.ts +61 -0
  232. package/src/avif/native/av1/transform/forward_transform_2d.d.ts.map +1 -0
  233. package/src/avif/native/av1/transform/forward_transform_2d.js +574 -0
  234. package/src/avif/native/av1/transform/inverse_transform_1d.d.ts +76 -0
  235. package/src/avif/native/av1/transform/inverse_transform_1d.d.ts.map +1 -0
  236. package/src/avif/native/av1/transform/inverse_transform_1d.js +590 -0
  237. package/src/avif/native/av1/transform/inverse_transform_2d.d.ts +46 -0
  238. package/src/avif/native/av1/transform/inverse_transform_2d.d.ts.map +1 -0
  239. package/src/avif/native/av1/transform/inverse_transform_2d.js +180 -0
  240. package/src/avif/native/av1/util/ceil_log2.d.ts +13 -0
  241. package/src/avif/native/av1/util/ceil_log2.d.ts.map +1 -0
  242. package/src/avif/native/av1/util/ceil_log2.js +18 -0
  243. package/src/avif/native/av1/util/floor_log2.d.ts +20 -0
  244. package/src/avif/native/av1/util/floor_log2.d.ts.map +1 -0
  245. package/src/avif/native/av1/util/floor_log2.js +20 -0
  246. package/src/avif/native/av1/util/round2.d.ts +22 -0
  247. package/src/avif/native/av1/util/round2.d.ts.map +1 -0
  248. package/src/avif/native/av1/util/round2.js +27 -0
  249. package/src/avif/native/av1/util/round2_signed.d.ts +14 -0
  250. package/src/avif/native/av1/util/round2_signed.d.ts.map +1 -0
  251. package/src/avif/native/av1/util/round2_signed.js +17 -0
  252. package/src/avif/native/av1/util/tile_log2.d.ts +16 -0
  253. package/src/avif/native/av1/util/tile_log2.d.ts.map +1 -0
  254. package/src/avif/native/av1/util/tile_log2.js +23 -0
  255. package/src/avif/native/bitstream/BitReader.d.ts +174 -0
  256. package/src/avif/native/bitstream/BitReader.d.ts.map +1 -0
  257. package/src/avif/native/bitstream/BitReader.js +391 -0
  258. package/src/avif/native/bitstream/BitWriter.d.ts +122 -0
  259. package/src/avif/native/bitstream/BitWriter.d.ts.map +1 -0
  260. package/src/avif/native/bitstream/BitWriter.js +351 -0
  261. package/src/avif/native/color/ColourTransform.d.ts +62 -0
  262. package/src/avif/native/color/ColourTransform.d.ts.map +1 -0
  263. package/src/avif/native/color/ColourTransform.js +189 -0
  264. package/src/avif/native/color/YuvImage.d.ts +51 -0
  265. package/src/avif/native/color/YuvImage.d.ts.map +1 -0
  266. package/src/avif/native/color/YuvImage.js +66 -0
  267. package/src/avif/native/color/clamp_sample.d.ts +18 -0
  268. package/src/avif/native/color/clamp_sample.d.ts.map +1 -0
  269. package/src/avif/native/color/clamp_sample.js +25 -0
  270. package/src/avif/native/color/linear_to_transfer.d.ts +24 -0
  271. package/src/avif/native/color/linear_to_transfer.d.ts.map +1 -0
  272. package/src/avif/native/color/linear_to_transfer.js +126 -0
  273. package/src/avif/native/color/primaries.d.ts +20 -0
  274. package/src/avif/native/color/primaries.d.ts.map +1 -0
  275. package/src/avif/native/color/primaries.js +94 -0
  276. package/src/avif/native/color/rgb_row_to_ycbcr.d.ts +20 -0
  277. package/src/avif/native/color/rgb_row_to_ycbcr.d.ts.map +1 -0
  278. package/src/avif/native/color/rgb_row_to_ycbcr.js +78 -0
  279. package/src/avif/native/color/transfer_to_linear.d.ts +49 -0
  280. package/src/avif/native/color/transfer_to_linear.d.ts.map +1 -0
  281. package/src/avif/native/color/transfer_to_linear.js +171 -0
  282. package/src/avif/native/color/upsample_chroma_row.d.ts +35 -0
  283. package/src/avif/native/color/upsample_chroma_row.d.ts.map +1 -0
  284. package/src/avif/native/color/upsample_chroma_row.js +89 -0
  285. package/src/avif/native/color/ycbcr_row_to_rgb.d.ts +23 -0
  286. package/src/avif/native/color/ycbcr_row_to_rgb.d.ts.map +1 -0
  287. package/src/avif/native/color/ycbcr_row_to_rgb.js +78 -0
  288. package/src/avif/native/heif/AvifFile.d.ts +112 -0
  289. package/src/avif/native/heif/AvifFile.d.ts.map +1 -0
  290. package/src/avif/native/heif/AvifFile.js +142 -0
  291. package/src/avif/native/heif/ItemProperty.d.ts +244 -0
  292. package/src/avif/native/heif/ItemProperty.d.ts.map +1 -0
  293. package/src/avif/native/heif/ItemProperty.js +321 -0
  294. package/src/avif/native/heif/find_item_property.d.ts +17 -0
  295. package/src/avif/native/heif/find_item_property.d.ts.map +1 -0
  296. package/src/avif/native/heif/find_item_property.js +28 -0
  297. package/src/avif/native/heif/find_item_references.d.ts +16 -0
  298. package/src/avif/native/heif/find_item_references.d.ts.map +1 -0
  299. package/src/avif/native/heif/find_item_references.js +29 -0
  300. package/src/avif/native/heif/find_items_referencing.d.ts +17 -0
  301. package/src/avif/native/heif/find_items_referencing.d.ts.map +1 -0
  302. package/src/avif/native/heif/find_items_referencing.js +36 -0
  303. package/src/avif/native/heif/parse_avif_file.d.ts +15 -0
  304. package/src/avif/native/heif/parse_avif_file.d.ts.map +1 -0
  305. package/src/avif/native/heif/parse_avif_file.js +383 -0
  306. package/src/avif/native/heif/parse_image_grid.d.ts +18 -0
  307. package/src/avif/native/heif/parse_image_grid.d.ts.map +1 -0
  308. package/src/avif/native/heif/parse_image_grid.js +48 -0
  309. package/src/avif/native/heif/parse_item_property.d.ts +18 -0
  310. package/src/avif/native/heif/parse_item_property.d.ts.map +1 -0
  311. package/src/avif/native/heif/parse_item_property.js +243 -0
  312. package/src/avif/native/heif/read_item_data.d.ts +22 -0
  313. package/src/avif/native/heif/read_item_data.d.ts.map +1 -0
  314. package/src/avif/native/heif/read_item_data.js +97 -0
  315. package/src/avif/native/heif/write_avif_file.d.ts +50 -0
  316. package/src/avif/native/heif/write_avif_file.d.ts.map +1 -0
  317. package/src/avif/native/heif/write_avif_file.js +348 -0
  318. package/src/avif/native/heif/write_item_property.d.ts +16 -0
  319. package/src/avif/native/heif/write_item_property.d.ts.map +1 -0
  320. package/src/avif/native/heif/write_item_property.js +182 -0
  321. package/src/avif/native/index.d.ts +14 -0
  322. package/src/avif/native/index.d.ts.map +1 -0
  323. package/src/avif/native/index.js +56 -0
  324. package/src/avif/native/isobmff/BoxHeader.d.ts +50 -0
  325. package/src/avif/native/isobmff/BoxHeader.d.ts.map +1 -0
  326. package/src/avif/native/isobmff/BoxHeader.js +57 -0
  327. package/src/avif/native/isobmff/BoxWriter.d.ts +118 -0
  328. package/src/avif/native/isobmff/BoxWriter.d.ts.map +1 -0
  329. package/src/avif/native/isobmff/BoxWriter.js +264 -0
  330. package/src/avif/native/isobmff/ByteCursor.d.ts +125 -0
  331. package/src/avif/native/isobmff/ByteCursor.d.ts.map +1 -0
  332. package/src/avif/native/isobmff/ByteCursor.js +298 -0
  333. package/src/avif/native/isobmff/for_each_box.d.ts +23 -0
  334. package/src/avif/native/isobmff/for_each_box.d.ts.map +1 -0
  335. package/src/avif/native/isobmff/for_each_box.js +39 -0
  336. package/src/avif/native/isobmff/read_box_header.d.ts +22 -0
  337. package/src/avif/native/isobmff/read_box_header.d.ts.map +1 -0
  338. package/src/avif/native/isobmff/read_box_header.js +59 -0
  339. package/src/avif/native/isobmff/read_full_box_header.d.ts +26 -0
  340. package/src/avif/native/isobmff/read_full_box_header.d.ts.map +1 -0
  341. package/src/avif/native/isobmff/read_full_box_header.js +33 -0
  342. package/src/avif/threaded_image_encoder.d.ts +7 -2
  343. package/src/avif/threaded_image_encoder.d.ts.map +1 -1
  344. package/src/avif/threaded_image_encoder.js +107 -21
  345. package/src/core/binary/BinaryBuffer.d.ts +40 -0
  346. package/src/core/binary/BinaryBuffer.d.ts.map +1 -1
  347. package/src/core/binary/BinaryBuffer.js +100 -0
  348. package/src/core/binary/hash/crc32.d.ts +16 -0
  349. package/src/core/binary/hash/crc32.d.ts.map +1 -0
  350. package/src/core/binary/hash/crc32.js +96 -0
  351. package/src/core/binary/utf8/utf8_decode.d.ts +21 -0
  352. package/src/core/binary/utf8/utf8_decode.d.ts.map +1 -0
  353. package/src/core/binary/utf8/utf8_decode.js +43 -0
  354. package/src/core/binary/utf8/utf8_encode_into.d.ts +20 -0
  355. package/src/core/binary/utf8/utf8_encode_into.d.ts.map +1 -0
  356. package/src/core/binary/utf8/utf8_encode_into.js +48 -0
  357. package/src/core/binary/utf8/utf8_encoded_length.d.ts +14 -0
  358. package/src/core/binary/utf8/utf8_encoded_length.d.ts.map +1 -0
  359. package/src/core/binary/utf8/utf8_encoded_length.js +36 -0
  360. package/src/core/color/COLOR_FIX_PLAN_2026_08_28.md +417 -0
  361. package/src/core/color/COLOR_REVIEW_2026_08_28.md +779 -0
  362. package/src/core/color/Color.d.ts +128 -20
  363. package/src/core/color/Color.d.ts.map +1 -1
  364. package/src/core/color/Color.js +959 -866
  365. package/src/core/color/PQ/PQ_constants.d.ts +10 -0
  366. package/src/core/color/PQ/PQ_constants.d.ts.map +1 -1
  367. package/src/core/color/PQ/PQ_constants.js +10 -0
  368. package/src/core/color/PQ/linear_to_PQ.d.ts.map +1 -1
  369. package/src/core/color/PQ/linear_to_PQ.js +6 -0
  370. package/src/core/color/REC709_PRIMARIES.d.ts +50 -0
  371. package/src/core/color/REC709_PRIMARIES.d.ts.map +1 -0
  372. package/src/core/color/REC709_PRIMARIES.js +53 -0
  373. package/src/core/color/construct/color_from_hex.d.ts +21 -0
  374. package/src/core/color/construct/color_from_hex.d.ts.map +1 -0
  375. package/src/core/color/construct/color_from_hex.js +33 -0
  376. package/src/core/color/construct/color_from_temperature.d.ts +22 -0
  377. package/src/core/color/construct/color_from_temperature.d.ts.map +1 -0
  378. package/src/core/color/construct/color_from_temperature.js +33 -0
  379. package/src/core/color/construct/color_from_uint24.d.ts +19 -0
  380. package/src/core/color/construct/color_from_uint24.d.ts.map +1 -0
  381. package/src/core/color/construct/color_from_uint24.js +26 -0
  382. package/src/core/color/construct/color_from_uint32.d.ts +20 -0
  383. package/src/core/color/construct/color_from_uint32.d.ts.map +1 -0
  384. package/src/core/color/construct/color_from_uint32.js +39 -0
  385. package/src/core/color/construct/color_gray.d.ts +17 -0
  386. package/src/core/color/construct/color_gray.d.ts.map +1 -0
  387. package/src/core/color/construct/color_gray.js +22 -0
  388. package/src/core/color/hex/hex2rgb.d.ts +1 -11
  389. package/src/core/color/hex/hex2rgb.d.ts.map +1 -1
  390. package/src/core/color/hex/hex2rgb.js +7 -24
  391. package/src/core/color/hex/hex_to_rgb.d.ts +18 -0
  392. package/src/core/color/hex/hex_to_rgb.d.ts.map +1 -0
  393. package/src/core/color/hex/hex_to_rgb.js +62 -0
  394. package/src/core/color/hex/rgb2hex.d.ts +1 -8
  395. package/src/core/color/hex/rgb2hex.d.ts.map +1 -1
  396. package/src/core/color/hex/rgb2hex.js +7 -13
  397. package/src/core/color/hex/rgb_to_hex.d.ts +9 -0
  398. package/src/core/color/hex/rgb_to_hex.d.ts.map +1 -0
  399. package/src/core/color/hex/rgb_to_hex.js +13 -0
  400. package/src/core/color/hex/rgba_to_hex.d.ts +19 -0
  401. package/src/core/color/hex/rgba_to_hex.d.ts.map +1 -0
  402. package/src/core/color/hex/rgba_to_hex.js +23 -0
  403. package/src/core/color/hsv/hsv2rgb.d.ts +1 -12
  404. package/src/core/color/hsv/hsv2rgb.d.ts.map +1 -1
  405. package/src/core/color/hsv/hsv2rgb.js +8 -21
  406. package/src/core/color/hsv/hsv2rgb_float.d.ts +1 -12
  407. package/src/core/color/hsv/hsv2rgb_float.d.ts.map +1 -1
  408. package/src/core/color/hsv/hsv2rgb_float.js +8 -56
  409. package/src/core/color/hsv/hsv_to_rgb.d.ts +13 -0
  410. package/src/core/color/hsv/hsv_to_rgb.d.ts.map +1 -0
  411. package/src/core/color/hsv/hsv_to_rgb.js +39 -0
  412. package/src/core/color/hsv/hsv_to_rgb_uint8.d.ts +13 -0
  413. package/src/core/color/hsv/hsv_to_rgb_uint8.d.ts.map +1 -0
  414. package/src/core/color/hsv/hsv_to_rgb_uint8.js +21 -0
  415. package/src/core/color/hsv/hue_to_rgb_sextant.d.ts +24 -0
  416. package/src/core/color/hsv/hue_to_rgb_sextant.d.ts.map +1 -0
  417. package/src/core/color/hsv/hue_to_rgb_sextant.js +67 -0
  418. package/src/core/color/hsv/rgb2hsv.d.ts +1 -12
  419. package/src/core/color/hsv/rgb2hsv.d.ts.map +1 -1
  420. package/src/core/color/hsv/rgb2hsv.js +7 -42
  421. package/src/core/color/hsv/rgb_to_hsv.d.ts +13 -0
  422. package/src/core/color/hsv/rgb_to_hsv.d.ts.map +1 -0
  423. package/src/core/color/hsv/rgb_to_hsv.js +42 -0
  424. package/src/core/color/hunt/hpe_to_xyz.d.ts +2 -0
  425. package/src/core/color/hunt/hpe_to_xyz.d.ts.map +1 -0
  426. package/src/core/color/hunt/hpe_to_xyz.js +4 -0
  427. package/src/core/color/hunt/xyz_to_hpe.d.ts +1 -6
  428. package/src/core/color/hunt/xyz_to_hpe.d.ts.map +1 -1
  429. package/src/core/color/hunt/xyz_to_hpe.js +12 -15
  430. package/src/core/color/illuminant/D65_spd_tabulated.d.ts.map +1 -1
  431. package/src/core/color/illuminant/D65_spd_tabulated.js +107 -104
  432. package/src/core/color/int2rgb.d.ts +1 -10
  433. package/src/core/color/int2rgb.d.ts.map +1 -1
  434. package/src/core/color/int2rgb.js +7 -12
  435. package/src/core/color/int_to_rgb.d.ts +21 -0
  436. package/src/core/color/int_to_rgb.d.ts.map +1 -0
  437. package/src/core/color/int_to_rgb.js +33 -0
  438. package/src/core/color/kelvin/kelvin_to_rgb.d.ts.map +1 -1
  439. package/src/core/color/kelvin/kelvin_to_rgb.js +22 -2
  440. package/src/core/color/kelvin/rgb_to_kelvin.d.ts +22 -2
  441. package/src/core/color/kelvin/rgb_to_kelvin.d.ts.map +1 -1
  442. package/src/core/color/kelvin/rgb_to_kelvin.js +22 -2
  443. package/src/core/color/lab/lab_to_xyz.d.ts +20 -0
  444. package/src/core/color/lab/lab_to_xyz.d.ts.map +1 -0
  445. package/src/core/color/lab/lab_to_xyz.js +69 -0
  446. package/src/core/color/oklab/gamut_clip_adaptive_l0.d.ts +34 -0
  447. package/src/core/color/oklab/gamut_clip_adaptive_l0.d.ts.map +1 -0
  448. package/src/core/color/oklab/gamut_clip_adaptive_l0.js +46 -0
  449. package/src/core/color/oklab/gamut_clip_at_l0.d.ts +33 -0
  450. package/src/core/color/oklab/gamut_clip_at_l0.d.ts.map +1 -0
  451. package/src/core/color/oklab/gamut_clip_at_l0.js +84 -0
  452. package/src/core/color/oklab/gamut_clip_preserve_chroma.d.ts +24 -0
  453. package/src/core/color/oklab/gamut_clip_preserve_chroma.d.ts.map +1 -0
  454. package/src/core/color/oklab/gamut_clip_preserve_chroma.js +37 -0
  455. package/src/core/color/oklab/gamut_clip_project_to_lcusp.d.ts +23 -0
  456. package/src/core/color/oklab/gamut_clip_project_to_lcusp.d.ts.map +1 -0
  457. package/src/core/color/oklab/gamut_clip_project_to_lcusp.js +46 -0
  458. package/src/core/color/oklab/linear_srgb_to_okhsl.d.ts +19 -0
  459. package/src/core/color/oklab/linear_srgb_to_okhsl.d.ts.map +1 -0
  460. package/src/core/color/oklab/linear_srgb_to_okhsl.js +93 -0
  461. package/src/core/color/oklab/linear_srgb_to_okhsv.d.ts +12 -4
  462. package/src/core/color/oklab/linear_srgb_to_okhsv.d.ts.map +1 -1
  463. package/src/core/color/oklab/linear_srgb_to_okhsv.js +108 -84
  464. package/src/core/color/oklab/linear_srgb_to_oklab.d.ts +13 -4
  465. package/src/core/color/oklab/linear_srgb_to_oklab.d.ts.map +1 -1
  466. package/src/core/color/oklab/linear_srgb_to_oklab.js +28 -19
  467. package/src/core/color/oklab/okhsl_chroma_bounds.d.ts +51 -0
  468. package/src/core/color/oklab/okhsl_chroma_bounds.d.ts.map +1 -0
  469. package/src/core/color/oklab/okhsl_chroma_bounds.js +128 -0
  470. package/src/core/color/oklab/okhsl_to_linear_srgb.d.ts +19 -0
  471. package/src/core/color/oklab/okhsl_to_linear_srgb.d.ts.map +1 -0
  472. package/src/core/color/oklab/okhsl_to_linear_srgb.js +85 -0
  473. package/src/core/color/oklab/oklab_to_oklch.d.ts +24 -0
  474. package/src/core/color/oklab/oklab_to_oklch.d.ts.map +1 -0
  475. package/src/core/color/oklab/oklab_to_oklch.js +35 -0
  476. package/src/core/color/oklab/oklch_to_oklab.d.ts +18 -0
  477. package/src/core/color/oklab/oklch_to_oklab.d.ts.map +1 -0
  478. package/src/core/color/oklab/oklch_to_oklab.js +26 -0
  479. package/src/core/color/oklab/toe.d.ts +12 -0
  480. package/src/core/color/oklab/toe.d.ts.map +1 -1
  481. package/src/core/color/oklab/toe.js +34 -22
  482. package/src/core/color/operations/color_add.d.ts +21 -0
  483. package/src/core/color/operations/color_add.d.ts.map +1 -0
  484. package/src/core/color/operations/color_add.js +23 -0
  485. package/src/core/color/operations/color_add_scaled.d.ts +20 -0
  486. package/src/core/color/operations/color_add_scaled.d.ts.map +1 -0
  487. package/src/core/color/operations/color_add_scaled.js +30 -0
  488. package/src/core/color/operations/color_clamp.d.ts +22 -0
  489. package/src/core/color/operations/color_clamp.d.ts.map +1 -0
  490. package/src/core/color/operations/color_clamp.js +25 -0
  491. package/src/core/color/operations/color_darken.d.ts +2 -1
  492. package/src/core/color/operations/color_darken.d.ts.map +1 -1
  493. package/src/core/color/operations/color_darken.js +25 -24
  494. package/src/core/color/operations/color_desaturate.d.ts +2 -1
  495. package/src/core/color/operations/color_desaturate.d.ts.map +1 -1
  496. package/src/core/color/operations/color_desaturate.js +25 -24
  497. package/src/core/color/operations/color_get_hsl.d.ts +18 -0
  498. package/src/core/color/operations/color_get_hsl.d.ts.map +1 -0
  499. package/src/core/color/operations/color_get_hsl.js +60 -0
  500. package/src/core/color/operations/color_is_in_gamut.d.ts +20 -0
  501. package/src/core/color/operations/color_is_in_gamut.d.ts.map +1 -0
  502. package/src/core/color/operations/color_is_in_gamut.js +30 -0
  503. package/src/core/color/operations/color_lerp.d.ts +12 -3
  504. package/src/core/color/operations/color_lerp.d.ts.map +1 -1
  505. package/src/core/color/operations/color_lerp.js +55 -46
  506. package/src/core/color/operations/color_lighten.d.ts +9 -5
  507. package/src/core/color/operations/color_lighten.d.ts.map +1 -1
  508. package/src/core/color/operations/color_lighten.js +29 -24
  509. package/src/core/color/operations/color_mix_okhsv_channel.d.ts +24 -0
  510. package/src/core/color/operations/color_mix_okhsv_channel.d.ts.map +1 -0
  511. package/src/core/color/operations/color_mix_okhsv_channel.js +48 -0
  512. package/src/core/color/operations/color_multiply_rgb.d.ts +21 -0
  513. package/src/core/color/operations/color_multiply_rgb.d.ts.map +1 -0
  514. package/src/core/color/operations/color_multiply_rgb.js +26 -0
  515. package/src/core/color/operations/color_saturate.d.ts +9 -5
  516. package/src/core/color/operations/color_saturate.d.ts.map +1 -1
  517. package/src/core/color/operations/color_saturate.js +29 -24
  518. package/src/core/color/operations/color_scale_okhsv_channel.d.ts +1 -1
  519. package/src/core/color/operations/color_scale_okhsv_channel.d.ts.map +1 -1
  520. package/src/core/color/operations/color_scale_okhsv_channel.js +58 -45
  521. package/src/core/color/operations/color_srgb_apply.d.ts +28 -0
  522. package/src/core/color/operations/color_srgb_apply.d.ts.map +1 -0
  523. package/src/core/color/operations/color_srgb_apply.js +40 -0
  524. package/src/core/color/operations/color_sub.d.ts +16 -0
  525. package/src/core/color/operations/color_sub.d.ts.map +1 -0
  526. package/src/core/color/operations/color_sub.js +18 -0
  527. package/src/core/color/parse_color.d.ts +10 -1
  528. package/src/core/color/parse_color.d.ts.map +1 -1
  529. package/src/core/color/parse_color.js +100 -84
  530. package/src/core/color/parse_color_normalized.d.ts +24 -0
  531. package/src/core/color/parse_color_normalized.d.ts.map +1 -0
  532. package/src/core/color/parse_color_normalized.js +38 -0
  533. package/src/core/color/rgb2uint24.d.ts +1 -8
  534. package/src/core/color/rgb2uint24.d.ts.map +1 -1
  535. package/src/core/color/rgb2uint24.js +7 -20
  536. package/src/core/color/rgb2uint32.d.ts +1 -9
  537. package/src/core/color/rgb2uint32.d.ts.map +1 -1
  538. package/src/core/color/rgb2uint32.js +7 -18
  539. package/src/core/color/rgb_to_luminance.d.ts +14 -5
  540. package/src/core/color/rgb_to_luminance.d.ts.map +1 -1
  541. package/src/core/color/rgb_to_luminance.js +24 -13
  542. package/src/core/color/rgb_to_uint24.d.ts +9 -0
  543. package/src/core/color/rgb_to_uint24.d.ts.map +1 -0
  544. package/src/core/color/rgb_to_uint24.js +20 -0
  545. package/src/core/color/rgb_to_uint32.d.ts +10 -0
  546. package/src/core/color/rgb_to_uint32.d.ts.map +1 -0
  547. package/src/core/color/rgb_to_uint32.js +21 -0
  548. package/src/core/color/sRGB/linear_to_sRGB.d.ts +7 -0
  549. package/src/core/color/sRGB/linear_to_sRGB.d.ts.map +1 -1
  550. package/src/core/color/sRGB/linear_to_sRGB.js +39 -32
  551. package/src/core/color/xyz/hpe_to_xyz.d.ts +24 -0
  552. package/src/core/color/xyz/hpe_to_xyz.d.ts.map +1 -0
  553. package/src/core/color/xyz/hpe_to_xyz.js +39 -0
  554. package/src/core/color/xyz/rgb_to_xyz.d.ts +17 -2
  555. package/src/core/color/xyz/rgb_to_xyz.d.ts.map +1 -1
  556. package/src/core/color/xyz/rgb_to_xyz.js +44 -18
  557. package/src/core/color/xyz/xyz_cmf_tabulated.d.ts.map +1 -1
  558. package/src/core/color/xyz/xyz_cmf_tabulated.js +217 -211
  559. package/src/core/color/xyz/xyz_cmf_wyman.d.ts +4 -0
  560. package/src/core/color/xyz/xyz_cmf_wyman.d.ts.map +1 -1
  561. package/src/core/color/xyz/xyz_cmf_wyman.js +74 -65
  562. package/src/core/color/xyz/xyz_to_hpe.d.ts +18 -0
  563. package/src/core/color/xyz/xyz_to_hpe.d.ts.map +1 -0
  564. package/src/core/color/xyz/xyz_to_hpe.js +33 -0
  565. package/src/core/color/xyz/xyz_to_rgb.d.ts +17 -2
  566. package/src/core/color/xyz/xyz_to_rgb.d.ts.map +1 -1
  567. package/src/core/color/xyz/xyz_to_rgb.js +39 -16
  568. package/src/core/color/ycxcz/xyz_to_ycxcz.d.ts +7 -2
  569. package/src/core/color/ycxcz/xyz_to_ycxcz.d.ts.map +1 -1
  570. package/src/core/color/ycxcz/xyz_to_ycxcz.js +33 -28
  571. package/src/core/events/signal/Signal.js +820 -820
  572. package/src/core/math/clamp_index.d.ts +18 -0
  573. package/src/core/math/clamp_index.d.ts.map +1 -0
  574. package/src/core/math/clamp_index.js +23 -0
  575. package/src/engine/asset/loaders/image/IMAGE_CODEC_REVIEW_2026_08_28.md +803 -0
  576. package/src/engine/asset/loaders/image/jpeg/JpegFrame.d.ts +5 -3
  577. package/src/engine/asset/loaders/image/jpeg/JpegFrame.d.ts.map +1 -1
  578. package/src/engine/asset/loaders/image/jpeg/JpegFrame.js +5 -3
  579. package/src/engine/asset/loaders/image/jpeg/JpegFrameComponent.d.ts +2 -1
  580. package/src/engine/asset/loaders/image/jpeg/JpegFrameComponent.d.ts.map +1 -1
  581. package/src/engine/asset/loaders/image/jpeg/JpegFrameComponent.js +2 -1
  582. package/src/engine/asset/loaders/image/jpeg/JpegImage.d.ts +17 -0
  583. package/src/engine/asset/loaders/image/jpeg/JpegImage.d.ts.map +1 -1
  584. package/src/engine/asset/loaders/image/jpeg/JpegImage.js +197 -157
  585. package/src/engine/asset/loaders/image/jpeg/idct8x8_float.d.ts +0 -1
  586. package/src/engine/asset/loaders/image/jpeg/idct8x8_float.d.ts.map +1 -1
  587. package/src/engine/asset/loaders/image/jpeg/idct8x8_float.js +0 -1
  588. package/src/engine/asset/loaders/image/jpeg/jpeg_component_row.d.ts +28 -0
  589. package/src/engine/asset/loaders/image/jpeg/jpeg_component_row.d.ts.map +1 -0
  590. package/src/engine/asset/loaders/image/jpeg/jpeg_component_row.js +31 -0
  591. package/src/engine/asset/loaders/image/png/PNG.d.ts +3 -18
  592. package/src/engine/asset/loaders/image/png/PNG.d.ts.map +1 -1
  593. package/src/engine/asset/loaders/image/png/PNG.js +3 -139
  594. package/src/engine/asset/loaders/image/png/PNGReader.d.ts +16 -16
  595. package/src/engine/asset/loaders/image/png/PNGReader.d.ts.map +1 -1
  596. package/src/engine/asset/loaders/image/png/PNGReader.js +143 -160
  597. package/src/engine/asset/loaders/image/png/chunk/png_chunk_decode_iTXt.js +3 -3
  598. package/src/engine/asset/loaders/image/png/chunk/png_chunk_decode_zTXt.js +3 -3
  599. package/src/engine/asset/loaders/image/png/crc32.d.ts +1 -15
  600. package/src/engine/asset/loaders/image/png/crc32.d.ts.map +1 -1
  601. package/src/engine/asset/loaders/image/png/crc32.js +5 -89
  602. package/src/engine/asset/loaders/image/png/filter/png_filter_unFilterNone.d.ts +12 -10
  603. package/src/engine/asset/loaders/image/png/filter/png_filter_unFilterNone.d.ts.map +1 -1
  604. package/src/engine/asset/loaders/image/png/filter/png_filter_unFilterNone.js +20 -45
  605. package/src/engine/asset/loaders/image/png/filter/png_filter_unFilterSub.d.ts +2 -1
  606. package/src/engine/asset/loaders/image/png/filter/png_filter_unFilterSub.d.ts.map +1 -1
  607. package/src/engine/asset/loaders/image/png/filter/png_filter_unFilterSub.js +2 -0
  608. package/src/engine/asset/loaders/image/png/filter/png_filter_unFilterUp.d.ts +2 -1
  609. package/src/engine/asset/loaders/image/png/filter/png_filter_unFilterUp.d.ts.map +1 -1
  610. package/src/engine/asset/loaders/image/png/filter/png_filter_unFilterUp.js +2 -0
  611. package/src/engine/asset/loaders/image/png/filter/png_unfilter.d.ts +22 -0
  612. package/src/engine/asset/loaders/image/png/filter/png_unfilter.d.ts.map +1 -0
  613. package/src/engine/asset/loaders/image/png/filter/png_unfilter.js +68 -0
  614. package/src/engine/asset/loaders/image/png/png_inflate.d.ts +20 -0
  615. package/src/engine/asset/loaders/image/png/png_inflate.d.ts.map +1 -0
  616. package/src/engine/asset/loaders/image/png/png_inflate.js +85 -0
  617. package/src/engine/asset/loaders/image/png/png_unpack_samples.d.ts +22 -0
  618. package/src/engine/asset/loaders/image/png/png_unpack_samples.d.ts.map +1 -0
  619. package/src/engine/asset/loaders/image/png/png_unpack_samples.js +38 -0
  620. package/src/engine/graphics/ecs/sprite/SpriteSystemPE.d.ts.map +1 -1
  621. package/src/engine/graphics/ecs/sprite/SpriteSystemPE.js +135 -132
  622. package/src/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.d.ts +16 -3
  623. package/src/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.d.ts.map +1 -1
  624. package/src/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.js +1157 -1149
  625. package/src/engine/graphics/render/frame_graph/FrameGraph.js +900 -900
  626. package/src/engine/physics/ecs/PhysicsSystem.d.ts +72 -81
  627. package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
  628. package/src/engine/physics/ecs/PhysicsSystem.js +86 -77
  629. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  630. package/src/shade/device/IMMEDIATE_DATA_PLAN_2026_08_28.md +451 -0
  631. package/src/shade/device/timing/GPU_PROFILER_PROPOSAL_2026_08_28.md +625 -0
  632. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
  633. package/src/shade/renderer/rasterize/native/oit/shader_oit_blend.d.ts.map +1 -1
  634. package/src/shade/renderer/rasterize/native/oit/shader_oit_blend.js +5 -4
  635. package/src/shade/renderer/scene/serialization/decode_image_source_hdr.d.ts +14 -3
  636. package/src/shade/renderer/scene/serialization/decode_image_source_hdr.d.ts.map +1 -1
  637. package/src/shade/renderer/scene/serialization/decode_image_source_hdr.js +50 -51
  638. package/src/shade/renderer/scene/serialization/deserialize_scene.d.ts.map +1 -1
  639. package/src/shade/renderer/scene/serialization/deserialize_scene.js +531 -521
  640. package/src/shade/renderer/scene/serialization/write_image_source.d.ts.map +1 -1
  641. package/src/shade/renderer/scene/serialization/write_image_source.js +6 -4
  642. package/src/shade/renderer/shader/chunk/color/chunk_rgb_to_luminance.d.ts.map +1 -1
  643. package/src/shade/renderer/shader/chunk/color/chunk_rgb_to_luminance.js +34 -32
  644. package/src/shade/renderer/shader/chunk/color/iCtCp/chunk_eotf_st2084.d.ts +31 -0
  645. package/src/shade/renderer/shader/chunk/color/iCtCp/chunk_eotf_st2084.d.ts.map +1 -1
  646. package/src/shade/renderer/shader/chunk/color/iCtCp/chunk_eotf_st2084.js +62 -31
  647. package/src/shade/renderer/shader/chunk/color/iCtCp/chunk_inverse_eotf_st2084.d.ts +10 -0
  648. package/src/shade/renderer/shader/chunk/color/iCtCp/chunk_inverse_eotf_st2084.d.ts.map +1 -1
  649. package/src/shade/renderer/shader/chunk/color/iCtCp/chunk_inverse_eotf_st2084.js +32 -22
  650. package/src/shade/renderer/shader/chunk/color/sRGB/chunk_sRGBTransferOETF.d.ts.map +1 -1
  651. package/src/shade/renderer/shader/chunk/color/sRGB/chunk_sRGBTransferOETF.js +22 -21
  652. package/src/shade/renderer/shader/chunk/color/tonemap/gt7/chunk_tonemap_gt7.d.ts +6 -0
  653. package/src/shade/renderer/shader/chunk/color/tonemap/gt7/chunk_tonemap_gt7.d.ts.map +1 -1
  654. package/src/shade/renderer/shader/chunk/color/tonemap/gt7/chunk_tonemap_gt7.js +110 -104
  655. package/src/shade/renderer/shader/chunk/color/xyz/chunk_rgb_to_xyz.d.ts.map +1 -1
  656. package/src/shade/renderer/shader/chunk/color/xyz/chunk_rgb_to_xyz.js +23 -21
  657. package/src/shade/renderer/shader/chunk/math/chunk_magnitude_floor.d.ts +9 -0
  658. package/src/shade/renderer/shader/chunk/math/chunk_magnitude_floor.d.ts.map +1 -0
  659. package/src/shade/renderer/shader/chunk/math/chunk_magnitude_floor.js +16 -0
  660. package/src/shade/renderer/shader/chunk/math/complex/chunk_complex_magnitude_floor.d.ts +10 -0
  661. package/src/shade/renderer/shader/chunk/math/complex/chunk_complex_magnitude_floor.d.ts.map +1 -0
  662. package/src/shade/renderer/shader/chunk/math/complex/chunk_complex_magnitude_floor.js +17 -0
  663. package/src/shade/renderer/shader/chunk/math/complex/chunk_complex_solve_cubic_blinn.d.ts.map +1 -1
  664. package/src/shade/renderer/shader/chunk/math/complex/chunk_complex_solve_cubic_blinn.js +7 -1
  665. package/src/shade/renderer/shader/chunk/math/complex/chunk_complex_square_root.d.ts.map +1 -1
  666. package/src/shade/renderer/shader/chunk/math/complex/chunk_complex_square_root.js +9 -3
  667. package/src/shade/renderer/shader/chunk/math/polynomial/chunk_solve_cubic.d.ts.map +1 -1
  668. package/src/shade/renderer/shader/chunk/math/polynomial/chunk_solve_cubic.js +13 -7
  669. package/src/shade/renderer/shader/chunk/math/polynomial/chunk_solve_cubic_blinn_smallest.d.ts.map +1 -1
  670. package/src/shade/renderer/shader/chunk/math/polynomial/chunk_solve_cubic_blinn_smallest.js +13 -4
  671. package/src/shade/renderer/shader/chunk/math/polynomial/chunk_solve_quadratic.d.ts.map +1 -1
  672. package/src/shade/renderer/shader/chunk/math/polynomial/chunk_solve_quadratic.js +20 -13
  673. package/src/shade/renderer/shader/chunk/math/polynomial/chunk_solve_quartic_neumark.d.ts.map +1 -1
  674. package/src/shade/renderer/shader/chunk/math/polynomial/chunk_solve_quartic_neumark.js +8 -4
  675. package/src/shade/renderer/shader/chunk/mboit/NOTES.md +35 -1
  676. package/src/shade/renderer/shader/chunk/mboit/moments/geometric/chunk_compute_transmittance_from_2_trigonometric_moments.d.ts.map +1 -1
  677. package/src/shade/renderer/shader/chunk/mboit/moments/geometric/chunk_compute_transmittance_from_2_trigonometric_moments.js +18 -5
  678. package/src/shade/renderer/shader/chunk/mboit/moments/geometric/chunk_compute_transmittance_from_3_trigonometric_moments.d.ts.map +1 -1
  679. package/src/shade/renderer/shader/chunk/mboit/moments/geometric/chunk_compute_transmittance_from_3_trigonometric_moments.js +21 -8
  680. package/src/shade/renderer/shader/chunk/mboit/moments/geometric/chunk_compute_transmittance_from_4_trigonometric_moments.d.ts.map +1 -1
  681. package/src/shade/renderer/shader/chunk/mboit/moments/geometric/chunk_compute_transmittance_from_4_trigonometric_moments.js +25 -12
  682. package/src/shade/renderer/shader/chunk/mboit/moments/geometric/chunk_generate_trigonometric_moments_4.d.ts +6 -2
  683. package/src/shade/renderer/shader/chunk/mboit/moments/geometric/chunk_generate_trigonometric_moments_4.d.ts.map +1 -1
  684. package/src/shade/renderer/shader/chunk/mboit/moments/geometric/chunk_generate_trigonometric_moments_4.js +42 -35
  685. package/src/shade/renderer/shader/chunk/mboit/moments/power/chunk_compute_transmittance_from_4_power_moments.d.ts.map +1 -1
  686. package/src/shade/renderer/shader/chunk/mboit/moments/power/chunk_compute_transmittance_from_4_power_moments.js +18 -5
  687. package/src/shade/renderer/shader/chunk/mboit/moments/power/chunk_compute_transmittance_from_6_power_moments.d.ts.map +1 -1
  688. package/src/shade/renderer/shader/chunk/mboit/moments/power/chunk_compute_transmittance_from_6_power_moments.js +24 -9
  689. package/src/shade/renderer/shader/chunk/mboit/moments/power/chunk_compute_transmittance_from_8_power_moments.d.ts.map +1 -1
  690. package/src/shade/renderer/shader/chunk/mboit/moments/power/chunk_compute_transmittance_from_8_power_moments.js +29 -13
  691. package/src/shade/renderer/shader/chunk/mboit/moments/power/chunk_generate_power_moments_4.d.ts +12 -0
  692. package/src/shade/renderer/shader/chunk/mboit/moments/power/chunk_generate_power_moments_4.d.ts.map +1 -1
  693. package/src/shade/renderer/shader/chunk/mboit/moments/power/chunk_generate_power_moments_4.js +38 -48
  694. package/src/view/elements/ColorPickerView.js +296 -296
  695. package/src/avif/codec/dec/Readme.md +0 -14
  696. package/src/avif/codec/dec/avif_dec.cpp +0 -234
  697. package/src/avif/codec/dec/avif_dec.d.ts +0 -3
  698. package/src/avif/codec/dec/avif_dec.d.ts.map +0 -1
  699. package/src/avif/codec/dec/avif_dec.js +0 -16
  700. package/src/avif/codec/dec/avif_dec.wasm +0 -0
  701. package/src/avif/codec/enc/README.md +0 -37
  702. package/src/avif/codec/enc/avif_enc.cpp +0 -216
  703. package/src/avif/codec/enc/avif_enc.d.ts +0 -3
  704. package/src/avif/codec/enc/avif_enc.d.ts.map +0 -1
  705. package/src/avif/codec/enc/avif_enc.js +0 -6144
  706. package/src/avif/codec/enc/avif_enc.wasm +0 -0
  707. package/src/avif/codec/enc/avif_enc_mt.d.ts +0 -3
  708. package/src/avif/codec/enc/avif_enc_mt.d.ts.map +0 -1
  709. package/src/avif/codec/enc/avif_enc_mt.js +0 -6811
  710. package/src/avif/codec/enc/avif_enc_mt.wasm +0 -0
  711. package/src/avif/codec/enc/avif_enc_mt.worker.d.mts +0 -2
  712. package/src/avif/codec/enc/avif_enc_mt.worker.d.mts.map +0 -1
  713. package/src/avif/codec/enc/avif_enc_mt.worker.d.ts +0 -11
  714. package/src/avif/codec/enc/avif_enc_mt.worker.d.ts.map +0 -1
  715. package/src/avif/codec/enc/avif_enc_mt.worker.js +0 -171
  716. package/src/avif/codec/enc/avif_enc_mt.worker.mjs +0 -1
  717. package/src/avif/decode.d.ts +0 -3
  718. package/src/avif/decode.d.ts.map +0 -1
  719. package/src/avif/decode.js +0 -42
  720. package/src/avif/encode.d.ts +0 -3
  721. package/src/avif/encode.d.ts.map +0 -1
  722. package/src/avif/encode.js +0 -75
  723. package/src/avif/meta.d.ts +0 -24
  724. package/src/avif/meta.d.ts.map +0 -1
  725. package/src/avif/meta.js +0 -23
  726. package/src/avif/tsconfig.tsbuildinfo +0 -1
  727. package/src/avif/utils.d.ts +0 -17
  728. package/src/avif/utils.d.ts.map +0 -1
  729. package/src/avif/utils.js +0 -31
  730. package/src/engine/asset/loaders/image/jpeg/idct8x8_fixed.d.ts +0 -23
  731. package/src/engine/asset/loaders/image/jpeg/idct8x8_fixed.d.ts.map +0 -1
  732. package/src/engine/asset/loaders/image/jpeg/idct8x8_fixed.js +0 -214
  733. package/src/engine/asset/loaders/image/png/inflate.d.ts +0 -7
  734. package/src/engine/asset/loaders/image/png/inflate.d.ts.map +0 -1
  735. package/src/engine/asset/loaders/image/png/inflate.js +0 -20
@@ -0,0 +1,625 @@
1
+ # A graphical GPU profiler for Shade — recorder, format, inspector
2
+
3
+ Proposal, 2026-08-28. Alex Goldring / Company Named Limited.
4
+
5
+ Scope: a **recording** side that ships with the engine, a **binary container** that carries a
6
+ capture, and an **inspector** web application under `packages/gpu-inspector-tool/` that reads the
7
+ container and nothing else.
8
+
9
+ > The request spelled the directory `gpu-inespector-tool`. Reading that as a typo and using
10
+ > `packages/gpu-inspector-tool/` throughout. Say the word if the misspelling was deliberate.
11
+
12
+ ---
13
+
14
+ ## 0. Verdict
15
+
16
+ **Worth building, and the engine is further along than it looks — but not in the place you would
17
+ expect.**
18
+
19
+ The timing half is the *small* half. `GPUTimerArray` already lands begin/end timestamps per GPU
20
+ pass, and `SoftwareGPUDevice` already emulates timestamp queries well enough to test the recorder in
21
+ node without a GPU. What is genuinely missing is **attribution**: the timestamps are keyed by
22
+ `GPUComputePassDescriptor.label`, the dependency structure lives in `FrameGraph`, and *nothing
23
+ connects the two*. One frame-graph pass can open several GPU passes with unrelated labels
24
+ (`graph_build_hzb` → `hzb.build()` → its own `constructComputePass` labels), so a label is not a key.
25
+ Closing that gap is the central piece of engineering in this proposal, and it is about thirty lines
26
+ in `FrameGraph.execute` plus a field on the command context.
27
+
28
+ The dependency half is nearly free. `FrameGraph.exportToJson()`
29
+ ([FrameGraph.js:644](src/engine/graphics/render/frame_graph/FrameGraph.js:644)) already emits passes,
30
+ resource nodes, versions, readers, writers, producers and cull state, keyed consistently. Resource
31
+ *sizes* fall out of the descriptors that graph already holds. Nesting for a flame-graph view falls
32
+ out of `FrameGraphScope`.
33
+
34
+ The work-size half needs a wrapper that does not exist: `beginComputePass` hands back the raw
35
+ `GPUComputePassEncoder`, so `dispatchWorkgroups(x, y, z)` is invisible to us. A recording-only proxy
36
+ around the pass encoder buys every dispatch and draw count for one class and no call-site churn.
37
+
38
+ **The single biggest risk is not ours.** Chrome quantizes WebGPU timestamps to **100 µs** unless the
39
+ user sets `chrome://flags/#enable-webgpu-developer-features`. Most Shade passes run well under that,
40
+ so on a default browser almost every pass measures as exactly 0 or exactly 100 µs. A profiler that
41
+ does not say this out loud, in the recording *and* in the inspector, is a profiler that lies. §2.1.
42
+
43
+ ---
44
+
45
+ ## 1. What exists today
46
+
47
+ ### 1.1 The timing path, end to end
48
+
49
+ | Piece | Where | What it does |
50
+ |---|---|---|
51
+ | `GPUTimerArray` | [GPUTimerArray.js](src/shade/device/timing/GPUTimerArray.js) | One `GPUQuerySet` of `size * 2` timestamps. `getComputeWrites(label)` / `getRenderWrites(label)` claim a slot from an `IdPool` and return the `timestampWrites` struct. Resolve + copy to a `MAP_READ` buffer, `download_results()` maps it, `results_to_console_table()` turns slots into `{label, type, duration_ms, start, end}`. |
52
+ | `ShadeGPUCommandContext.enable_debug_timers(cb)` | [ShadeGPUCommandContext.js:89](src/shade/device/ShadeGPUCommandContext.js:89) | Constructs a `GPUTimerArray` for this context. `beginComputePass` / `beginRenderPass` then inject `timestampWrites` into every descriptor. |
53
+ | `finish()` | [ShadeGPUCommandContext.js:699](src/shade/device/ShadeGPUCommandContext.js:699) | Resolves the query set into the command buffer before `encoder.finish()`, then after submit downloads results and calls the callback, then destroys the timer array. |
54
+ | `Renderer.add_debug_frame(count)` | [Renderer.js:626](src/shade/renderer/Renderer.js:626) | Arms N future frames. |
55
+ | `Renderer.onFrameDebug` | [Renderer.js:408](src/shade/renderer/Renderer.js:408) | `send2(frame_index, table)`. **Currently has no subscribers anywhere in the tree.** |
56
+ | `GPUTimerStats`, `format_nanosecond_time` | `src/shade/device/timing/` | Ring-buffer averaging and human formatting. Reusable in the inspector. |
57
+
58
+ Degradation is already correct: with `timestamp-query` withheld, the query set is never created and
59
+ `resolve` / `download_results` / `destroy` all no-op rather than throwing. Keep that property.
60
+
61
+ ### 1.2 Four defects the recorder must fix, not inherit
62
+
63
+ 1. **No slot bound check.** `GPUTimerArray.#bind_slot` takes an id from the `IdPool` and never
64
+ compares it to `#size`. Pass 1025 in a frame (default `size = 1024`) writes a query index past
65
+ `querySet.count` and takes a WebGPU validation error, at the `beginRenderPass` rather than at the
66
+ place that overflowed. A recording session runs *more* passes instrumented than a debug frame
67
+ does, so this is on the path. Clamp and count drops; report the drop count in the recording.
68
+ 2. **Per-context GPU allocation.** `enable_debug_timers` builds a query set and two buffers per
69
+ context and destroys them after the download. Fine for one frame; recording 600 frames means 600
70
+ query-set create/destroy pairs and 600 `mapAsync` round trips. Wants a small pool of timer arrays
71
+ cycled N-deep against frames in flight.
72
+ 3. **Descriptor mutation.** `beginComputePass` does `let _descriptor = descriptor;` and then writes
73
+ `_descriptor.timestampWrites`, mutating the caller's object. Several call sites reuse descriptor
74
+ objects. Copy, or document the mutation.
75
+ 4. **`beginComputePass()` with no descriptor throws** once timers are on, at
76
+ `timers.getComputeWrites(descriptor.label)`. Currently latent because every call site passes one.
77
+
78
+ ### 1.3 The structure half
79
+
80
+ `FrameGraph.exportToJson()` is most of the dependency model already:
81
+
82
+ ```js
83
+ {
84
+ passes: [{ id, name, culled, reads: [node_id], writes: [node_id] }],
85
+ resources: [{ id, name, transient, version?, description?, createdBy?, readers?, writers? }]
86
+ }
87
+ ```
88
+
89
+ Keyed by **resource node** (per version), not by registry entry — deliberately, so
90
+ `passes[].reads/writes` stay resolvable across versions. The recording format must preserve that
91
+ choice; a registry-keyed export dangles every reference past version 0.
92
+
93
+ What it does *not* carry, and we want:
94
+
95
+ - `FrameGraphNode.scope` — the `FrameGraphScope` chain, which is the hierarchy a flame graph needs.
96
+ - `ref_count` and `has_side_effects` — why a pass survived culling.
97
+ - Typed descriptors. `description` is `resource_descriptor.toString()`, a human string
98
+ (`"Buffer{ size = 1,048,576, usage = STORAGE | COPY_DST }"`). We want the fields.
99
+
100
+ ### 1.4 The gap: labels are not keys
101
+
102
+ ```js
103
+ // graph_build_hzb.js
104
+ const builder = graph.add("hzb/ build", data, (data, resources, context) => {
105
+ hzb.build(context.encoder, source, viewport); // opens N compute passes, its own labels
106
+ });
107
+ ```
108
+
109
+ `GPUTimerArray` records the labels `hzb.build` chose. `FrameGraph` records `"hzb/ build"`. Nothing
110
+ relates them, and the relation is not derivable after the fact — labels are not unique, not stable,
111
+ and one graph pass legitimately produces many GPU passes.
112
+
113
+ **Fix:** bracket `node.execute(...)` inside `FrameGraph.execute`
114
+ ([FrameGraph.js:604](src/engine/graphics/render/frame_graph/FrameGraph.js:604)) so the context knows
115
+ which graph pass is open. Every GPU pass begun while that bracket is open is attributed to it. The
116
+ same bracket should emit `pushDebugGroup(node.name)` / `popDebugGroup()`, which costs nothing and
117
+ immediately improves what RenderDoc, PIX and webgpu-inspector show — worth doing on its own merits.
118
+
119
+ ### 1.5 Work sizes are not observable today
120
+
121
+ `beginComputePass` / `constructComputePass` return the **raw** `GPUComputePassEncoder`. All 11
122
+ production `dispatchWorkgroups` call sites talk to it directly, as does every draw call across the
123
+ 31 render-pass construction sites. Editing every one of them to report its own counts is the wrong
124
+ trade. A proxy encoder, installed only while recording, is one class.
125
+
126
+ `SoftwareGPUComputePassEncoder` already models exactly this: it records
127
+ `{pipeline, bind_groups, dynamic_offsets, group_counts}` per dispatch. The recording proxy is the
128
+ same shape with a real encoder behind it.
129
+
130
+ ---
131
+
132
+ ## 2. What the platform will give us
133
+
134
+ ### 2.1 Timestamp quantization — the headline constraint
135
+
136
+ Chrome quantizes `timestamp-query` results to **100 µs** as a timing-attack mitigation. It is
137
+ disabled by `chrome://flags/#enable-webgpu-developer-features`; that flag does not itself enable the
138
+ feature, which additionally needs the device to expose `timestamp-query`.
139
+
140
+ 100 µs is 0.1 ms. A Shade frame at 60 Hz has ~16.6 ms of budget spread over a couple of hundred
141
+ passes. **The median pass is below the quantum.** Unmitigated, the tool reports a histogram of zeros
142
+ with occasional 100 µs spikes, and every conclusion drawn from it is noise.
143
+
144
+ Three consequences, all of which belong in the design rather than in a README:
145
+
146
+ - **Measure the quantum, do not assume it.** At session start, run a calibration: submit a known
147
+ workload repeatedly, collect raw timestamp values, take the GCD of the deltas. Store the result as
148
+ `timestamp_period_ns` in the recording header.
149
+ - **Stamp it into the container** so the inspector knows what it is looking at without being told.
150
+ - **The inspector refuses to draw a precise-looking picture from imprecise data.** If
151
+ `timestamp_period_ns > 1000`, the timeline renders spans with explicit uncertainty bars and a
152
+ persistent banner naming the flag. Not a footnote in a tooltip.
153
+
154
+ There is a real mitigation beyond the flag: **aggregate across frames.** 600 frames of a 40 µs pass
155
+ quantized to 100 µs still average toward ~40 µs, because the quantization is in practice a floor
156
+ applied to a free-running counter rather than a deterministic snap of the duration. The inspector's
157
+ statistical view is therefore not a nicety — on a default browser it is the *only* trustworthy view.
158
+ This shapes the format: keep every frame's raw values, never pre-aggregate on the recorder side.
159
+
160
+ ### 2.2 Pass granularity is the floor
161
+
162
+ WebGPU writes timestamps at pass boundaries only. Per-draw timing needs
163
+ `chromium-experimental-timestamp-query-inside-passes`, which is Chromium-only and experimental.
164
+
165
+ **Design for pass granularity.** Treat inside-passes as an optional capability the recorder probes
166
+ for and, if present, uses to add sub-pass markers — recorded as a distinct span kind so the format
167
+ does not pretend the two are the same measurement.
168
+
169
+ ### 2.3 No CPU↔GPU clock sync
170
+
171
+ WebGPU exposes no calibration between `performance.now()` and the GPU timestamp domain. Anything
172
+ claiming to place CPU and GPU events on one axis is guessing.
173
+
174
+ **Be honest in the format.** Record two clocks explicitly: a CPU track from `performance.now()`
175
+ (encode time, submit time, callback time) and a GPU track from timestamps. The inspector shows two
176
+ tracks anchored per frame at submit, and says the alignment is nominal. Perfetto solves this problem
177
+ with explicit `ClockSnapshot` packets and a clock graph; we do not have the snapshots, so we do not
178
+ get to claim the sync.
179
+
180
+ ### 2.4 Cross-query-set comparability
181
+
182
+ Timestamps from two different `GPUQuerySet`s are not specified to share a domain. In Dawn they do in
183
+ practice. Since each `ShadeGPUCommandContext` currently gets its own `GPUTimerArray`, and a frame has
184
+ several contexts, **every frame already spans several query sets.**
185
+
186
+ Record a `query_set_id` per span. Then the inspector can, if a capture ever looks wrong, colour
187
+ spans by origin and let the reader see whether the anomaly follows a set boundary. Cheap; makes an
188
+ otherwise unfalsifiable class of bug visible.
189
+
190
+ ### 2.5 Indirect work is unknowable at encode time
191
+
192
+ `dispatchWorkgroupsIndirect` and `drawIndirect` take their counts from a GPU buffer. At encode time
193
+ we know only *that* it was indirect. Two options, both worth having:
194
+
195
+ - **v1:** record the indirect flag plus the source buffer's id and offset. The inspector shows
196
+ "indirect (unknown)" and links to the buffer.
197
+ - **v2 (opt-in, costly):** the recorder copies indirect argument buffers into a readback staging
198
+ buffer at encode time and resolves the actual counts after submit. This is the only way to see the
199
+ real post-cull draw count, which for a GPU-driven renderer is one of the numbers most worth seeing.
200
+ It changes memory traffic, so it must be a flag, and the format must mark such counts as
201
+ *resolved* rather than *encoded* so nobody compares the two carelessly.
202
+
203
+ ### 2.6 Prior art
204
+
205
+ | Tool | What to take | What to leave |
206
+ |---|---|---|
207
+ | [webgpu_inspector](https://github.com/brendan-duncan/webgpu_inspector) (Brendan Duncan) | The reference point for WebGPU frame capture in a browser. Object inspection with creation stacktraces; frame-time plotting; buffer content view. Its recorder emits a standalone replayable HTML file. | It is a *generic API* interceptor, extension-hosted. We want *engine-semantic* data — frame graph passes, resource lifetimes, cull decisions — which a generic interceptor cannot see. Complementary, not competing. |
208
+ | [Perfetto](https://perfetto.dev/docs/getting-started/other-formats) | Track/slice model; nested slices; counter tracks; explicit clock domains. Its JSON importer is a free escape hatch — see §5.6. | The protobuf format and the full trace-processor stack are far more than we need, and its UI knows nothing about resource dependency. |
209
+ | RenderDoc / PIX / Radeon GPU Profiler | The three-pane idiom: event list, timeline, per-event detail; a resource view keyed by lifetime; "why is this bound" attribution. | Native capture, replay, driver counters. Out of reach on WebGPU. |
210
+ | Chrome Trace Event Format | Trivially writable, universally readable. | Text JSON at our event rates is 5–10× our binary size. Export target, not storage. |
211
+ | [webgpufundamentals timing](https://webgpufundamentals.org/webgpu/lessons/webgpu-timing.html) | The canonical treatment of the query-set/resolve/map dance and its pitfalls. | — |
212
+
213
+ The gap in that table is the whole reason to build this: **no existing tool knows what a Shade frame
214
+ graph is.** Timings without the dependency structure tell you a pass is slow; timings *with* it tell
215
+ you a pass is slow because it waits on a resource that a culled branch still produced.
216
+
217
+ ---
218
+
219
+ ## 3. What a recording must contain
220
+
221
+ Three axes were asked for. A fourth is needed to make the first three legible.
222
+
223
+ ### 3.1 Timings
224
+
225
+ | Datum | Source | Cost |
226
+ |---|---|---|
227
+ | GPU pass begin/end, ns | `GPUTimerArray` | free, already there |
228
+ | Which query set a span came from | recorder | 1 byte |
229
+ | CPU encode time per graph pass | `performance.now()` around `node.execute` | ~2 × 200 calls/frame |
230
+ | CPU submit timestamp | `ShadeGPUCommandContext.finish` | free |
231
+ | Callback/readback latency | recorder | free |
232
+ | Sub-pass markers | `chromium-experimental-timestamp-query-inside-passes` if present | optional |
233
+
234
+ ### 3.2 Dependencies
235
+
236
+ Straight from `FrameGraph`, enriched:
237
+
238
+ - Passes: id, name, scope chain, culled, `ref_count`, `has_side_effects`, reads/writes/creates.
239
+ - Resource nodes: id, name, version, transient/imported, producer, readers, writers.
240
+ - Per graph pass: the GPU passes it opened, in order — the join from §1.4.
241
+ - Resource lifetime: first write → last read, derivable from `ResourceEntry.last`, which `compile()`
242
+ already computes.
243
+
244
+ ### 3.3 Data sizes
245
+
246
+ Descriptors carry everything:
247
+
248
+ | Resource | Fields | Footprint |
249
+ |---|---|---|
250
+ | Buffer | `size` bytes, `usage` bitmask, `ensure_cleared` range | `size` directly |
251
+ | Texture | `resolution[3]`, `format`, `dimension`, `mipLevelCount`, `sampleCount`, `usage` | computed from `gpu_texture_format_info` — `bytes_per_block`, `block_width`, `block_height` — summed over the mip chain, × `sampleCount` |
252
+
253
+ These are **declared** sizes, not allocated ones; a pooled allocator may serve a larger block.
254
+ `GraphicsContext.gpu_memory_usage` gives the real total per frame — record it as a counter track and
255
+ let the inspector show declared-vs-actual as the aliasing metric it is.
256
+
257
+ ### 3.4 Work sizes
258
+
259
+ | Datum | Needs |
260
+ |---|---|
261
+ | `dispatchWorkgroups(x, y, z)` | proxy encoder |
262
+ | Workgroup size from the shader (`@workgroup_size`) | pipeline descriptor, recorded once per pipeline |
263
+ | Total invocations = groups × workgroup size | derived in the inspector |
264
+ | `draw` / `drawIndexed` vertex, index, instance counts | proxy encoder |
265
+ | Indirect flag + argument buffer id/offset | proxy encoder |
266
+ | Resolved indirect counts | §2.5 v2, opt-in |
267
+ | Bind group contents per dispatch | proxy encoder; **large** — gate behind a verbosity level |
268
+ | Render pass attachment formats and load/store ops | pass descriptor |
269
+
270
+ ### 3.5 The fourth axis — context, so any of it means anything
271
+
272
+ Without this a shared recording is unreadable:
273
+
274
+ - Adapter info (`vendor`, `architecture`, `device`, `description`), features, the limits that matter.
275
+ - Engine version, git revision, build flags, `ENV_PRODUCTION`.
276
+ - Renderer settings: internal vs output resolution, upscaler, which features are on.
277
+ - `timestamp_period_ns` (§2.1) and whether the developer-features flag was detected.
278
+ - Wall-clock start, session id, user-supplied note.
279
+ - Scene scale: mesh/instance/light counts, resident material and geometry bytes.
280
+
281
+ ---
282
+
283
+ ## 4. Architecture
284
+
285
+ ```
286
+ ENGINE (ships) CONTAINER INSPECTOR (published separately)
287
+ ───────────────────── ───────── ───────────────────────────────
288
+ GPUTimerArray ────┐
289
+ FrameGraph ───────┤ ┌── timeline / flame graph
290
+ proxy encoders ───┼──> GPUProfileRecorder ──> .sgpt ──drop──> ├── dependency graph
291
+ GraphicsContext ──┘ │ bytes ├── resource table
292
+ │ ├── pass detail
293
+ sgpt_write_* └── frame comparison
294
+ │ │
295
+ BinaryBuffer <─────────────────────────── sgpt_read_*
296
+ ```
297
+
298
+ **Three rules that keep this from rotting.**
299
+
300
+ 1. **The container is the only interface.** The inspector imports the format readers and
301
+ `BinaryBuffer`. It never imports Shade, `FrameGraph`, or anything under `src/shade/renderer/`.
302
+ This is a licensing constraint as much as an architectural one — meep is proprietary and
303
+ source-available, and a separately published inspector must not carry renderer internals.
304
+ 2. **The recorder never blocks the frame.** Every buffer it touches is written at encode time or
305
+ read after submit. Serialization runs off the frame — accumulate into per-frame plain records,
306
+ encode to bytes when the session stops or when a chunk fills.
307
+ 3. **Reader and writer live together, in the engine tree.** Under
308
+ `src/shade/device/timing/profile/`, one file per concern, matching the `vgeo_*` convention. The
309
+ inspector package imports them by path. One definition of the format; no drift.
310
+
311
+ ### 4.1 Verbosity levels
312
+
313
+ A capture is a trade between fidelity and cost. Four levels, recorded in the header:
314
+
315
+ | Level | Adds | Bytes/frame, ~200 passes |
316
+ |---|---|---|
317
+ | 0 `TIMING` | GPU pass spans, frame boundaries | ~2 KB |
318
+ | 1 `STRUCTURE` | + frame graph topology, resource descriptors, cull state | ~2 KB amortised (§5.4) |
319
+ | 2 `WORKLOAD` | + dispatch/draw counts, pipeline identities, attachment state | ~6 KB |
320
+ | 3 `VERBOSE` | + bind group contents, indirect readback, CPU per-pass timing | ~40 KB |
321
+
322
+ Levels 0–2 are the product. Level 3 is for us, on a repro, and the inspector should say so when it
323
+ opens one.
324
+
325
+ ---
326
+
327
+ ## 5. The `.sgpt` container
328
+
329
+ **S**hade **G**PU **P**rofile **T**race. Magic `0x54505347` — the ASCII bytes `S G P T` read as a
330
+ little-endian u32 at offset 0, matching the `VGEO_MAGIC` convention in
331
+ [VGEO_MAGIC.js](src/shade/renderer/geometry/virtual/format/header/VGEO_MAGIC.js).
332
+
333
+ ### 5.1 Why binary, concretely
334
+
335
+ A 600-frame capture at level 2, ~200 passes/frame, in Chrome Trace Event JSON: each span is roughly
336
+ `{"ph":"X","name":"...","cat":"gpu","ts":123456.7,"dur":234.5,"pid":1,"tid":3,"args":{...}}` — call
337
+ it 140 bytes minified, times 120,000 spans, **~17 MB**, before pass arguments. The same content in
338
+ the layout below is **~1.5 MB**, and gzip (already a dependency via `pako`, and available natively
339
+ via `CompressionStream`) takes it under 400 KB. That is the difference between a capture you attach
340
+ to a bug report and one you do not.
341
+
342
+ ### 5.2 Layout
343
+
344
+ Chunked, directory at the tail — so a writer streams forward and only seeks back once, and a reader
345
+ can pull the header and the frame index without reading the payload.
346
+
347
+ ```
348
+ offset size field
349
+ ──────────────────────────────────────────────────────────────────
350
+ 0 4 magic u32 0x54505347
351
+ 4 2 format_version u16
352
+ 6 2 min_reader_version u16
353
+ 8 4 flags u32 bit0 = payload deflated
354
+ 12 4 header_checksum u32 over bytes [0, 12)
355
+ 16 8 directory_offset u64
356
+ 24 8 directory_byte_length u64
357
+ 32 ... chunks, in write order
358
+ ... ... directory
359
+ ```
360
+
361
+ Chunk framing, uniform:
362
+
363
+ ```
364
+ 0 4 chunk_type u32 FourCC
365
+ 4 8 payload_byte_length u64
366
+ 12 ... payload
367
+ ```
368
+
369
+ ### 5.3 Chunks
370
+
371
+ | FourCC | Purpose | Cardinality |
372
+ |---|---|---|
373
+ | `META` | §3.5 context. Adapter, engine version, settings, `timestamp_period_ns`, verbosity level, session note. | 1 |
374
+ | `STRS` | String table. Every name, label, format, scope name — written once, referenced by u32 index. | 1 |
375
+ | `PIPE` | Pipeline table: id, label, kind, shader module name, `@workgroup_size`, entry point, vertex layout digest. | 1 |
376
+ | `TOPO` | Frame-graph **topologies**: pass list, resource node list, edges, scopes, descriptors. Content-hashed and deduplicated across frames (§5.4). | 0..n |
377
+ | `FRAM` | One per frame: topology id, CPU timestamps, span array, dispatch/draw array, counters. | 0..n |
378
+ | `CNTR` | Counter tracks sampled per frame: `gpu_memory_usage`, mesh/instance/light counts, resolution. | 0..1 |
379
+ | `NOTE` | Free-form user annotations with a frame index — "this is where it hitches". | 0..n |
380
+ | `DIRE` | Directory: `{chunk_type, offset, byte_length}` plus a frame index of `{frame_number, chunk_offset, gpu_duration_ns}` so the inspector can draw the frame-time strip before parsing anything else. | 1 |
381
+
382
+ Unknown chunk types are skipped by length. That is what makes level-3 payloads addable without a
383
+ version bump, and what lets an old inspector open a new capture and say honestly which parts it
384
+ cannot show.
385
+
386
+ ### 5.4 The compression that matters: topology deduplication
387
+
388
+ **A Shade frame graph is nearly identical frame to frame.** Same passes, same resources, same edges;
389
+ what changes is the timings, the cull decisions, and the occasional resolution change. Recording the
390
+ full topology 600 times is the difference between a 20 MB file and a 1.5 MB one.
391
+
392
+ So: hash the recorded topology (pass names, edges, descriptors, scope chain). If the hash matches a
393
+ `TOPO` already written, the frame stores only the topology id. Cull state and per-pass timings stay
394
+ in `FRAM`, because they are exactly what varies.
395
+
396
+ Expected behaviour on a real capture: a handful of distinct topologies over 600 frames — steady
397
+ state, plus the shadow-refresh variants, plus resolution changes. §4.1's "~2 KB amortised" for level
398
+ 1 is that claim.
399
+
400
+ This must be **measured, not assumed**. If topologies turn out to churn every frame, the design
401
+ still works (it degrades to storing each), but the size estimates in §5.1 do not. First milestone
402
+ work item, §8.
403
+
404
+ ### 5.5 Per-frame span encoding
405
+
406
+ Per span, level 0:
407
+
408
+ | Field | Type | Note |
409
+ |---|---|---|
410
+ | `pass_ref` | `uintVar` | index into the topology's GPU-pass list |
411
+ | `t_begin` | `u32` | ns offset from the frame's `gpu_epoch_ns` |
412
+ | `t_end_delta` | `uintVar` | ns from `t_begin` |
413
+ | `query_set_id` | `u8` | §2.4 |
414
+
415
+ `u32` for the frame-relative begin holds 4.29 s — three orders of magnitude of headroom over a
416
+ frame, and it survives a stall without overflowing. `BinaryBuffer.writeUintVar` / `readUintVar`
417
+ already exist and handle the two variable-length fields.
418
+
419
+ That is ~10 bytes per span against 26 for a naive absolute-u64 encoding, and the frame's absolute
420
+ epoch is stored once as a `u64`.
421
+
422
+ ### 5.6 Chrome Trace Event export
423
+
424
+ The inspector exports the loaded capture as Chrome Trace Event JSON, for opening in
425
+ [ui.perfetto.dev](https://perfetto.dev/docs/getting-started/other-formats). Costs an afternoon and
426
+ buys: a second opinion when the inspector looks wrong, a viewer for anyone unwilling to run ours, and
427
+ a sanity check on our own timeline maths. Passes become `X` slices on a GPU track, scopes become
428
+ nesting, counters become `C` events. Lossy — the dependency graph has no representation there — which
429
+ is precisely why it is an export and not the storage format.
430
+
431
+ ### 5.7 String encoding
432
+
433
+ Use an explicit `STRS` table with u32 indices rather than `EncodingBinaryBuffer`. The latter
434
+ deduplicates by writing back-references to **absolute buffer positions**
435
+ ([EncodingBinaryBuffer.js:21](src/core/binary/EncodingBinaryBuffer.js:21)), which is correct for a
436
+ single flat buffer and wrong the moment chunks are written out of order, compressed independently, or
437
+ skipped by a reader that does not understand them. An index table costs one indirection and is
438
+ robust against all three.
439
+
440
+ ---
441
+
442
+ ## 6. The recorder
443
+
444
+ ### 6.1 Surface
445
+
446
+ ```js
447
+ const session = new GPUProfileSession({
448
+ graphics,
449
+ level: GPUProfileLevel.WORKLOAD,
450
+ max_frames: 600,
451
+ note: "hitch on shadow refresh, RTX 3070"
452
+ });
453
+
454
+ session.start();
455
+ // ... frames run ...
456
+ const bytes = await session.stop(); // ArrayBuffer, ready to save
457
+ ```
458
+
459
+ `Renderer` gets `begin_profile(options)` / `end_profile()` wrapping it, so the common case is two
460
+ calls and no wiring. `add_debug_frame` and `onFrameDebug` stay as they are — cheap, synchronous,
461
+ console-shaped, and a different tool for a different question.
462
+
463
+ ### 6.2 The five hooks
464
+
465
+ 1. **`FrameGraph.execute`** — bracket `node.execute(...)`. Notify the context which graph pass is
466
+ open; take CPU timestamps either side; push/pop a debug group. The only edit outside `src/shade/`.
467
+ Guarded so a graph with no listener does nothing.
468
+ 2. **`ShadeGPUCommandContext`** — a `#profile_sink` field. When set, `beginComputePass` /
469
+ `beginRenderPass` report `{label, kind, graph_pass_id, query_slot, query_set_id}` and wrap the
470
+ returned encoder in the recording proxy.
471
+ 3. **The proxy encoders** — `ProfilingComputePassEncoder`, `ProfilingRenderPassEncoder`. Forward
472
+ everything; record `dispatchWorkgroups*`, `draw*`, `setPipeline`, `setBindGroup`. Modelled on
473
+ `SoftwareGPUComputePassEncoder`, which already records exactly this shape.
474
+ 4. **`GPUTimerArray`** — pooling (§1.2.2), bound checking (§1.2.1), and expose raw slot data rather
475
+ than only the console table.
476
+ 5. **`GraphicsContext`** — sample `gpu_memory_usage` and the collection counters once per frame into
477
+ the counter track.
478
+
479
+ ### 6.3 Cost when off
480
+
481
+ Every hook is a null check against a field that is `undefined` in normal operation. No allocation and
482
+ no proxy construction; the frame-graph bracket is two comparisons per pass. This must stay true — a
483
+ profiler that costs something when disabled will be disabled at the build level and then rot.
484
+
485
+ ### 6.4 Cost when on
486
+
487
+ Level 0–2 add: one `performance.now()` pair per graph pass, one small record per GPU pass, one per
488
+ dispatch/draw, and a `push`/`popDebugGroup` pair per graph pass. The existing per-context query set
489
+ churn (§1.2.2) is the largest cost and the pool removes it. Expect single-digit percent frame-time
490
+ overhead at level 2; measure it and record the measurement in `META`, so a reader can see how much of
491
+ what they are looking at is the observer.
492
+
493
+ ---
494
+
495
+ ## 7. The inspector
496
+
497
+ `packages/gpu-inspector-tool/`. A static site: drop a `.sgpt` on it, or pass `?file=` for a
498
+ bookmarkable view — the affordance `prototypeVGEOFormatViewer` already established in this codebase.
499
+
500
+ ### 7.1 Technology
501
+
502
+ **Plain ES modules, Canvas 2D for the timeline, DOM for panels, no runtime dependencies, built with
503
+ Vite.** Reasons: the repo has no UI framework and adding one for this is unjustified; the timeline is
504
+ a custom-drawn virtualised widget that a framework would only get in the way of; zero dependencies
505
+ keeps a separately published proprietary artifact simple to reason about; and Vite is already the dev
506
+ server here.
507
+
508
+ The only imports from the engine tree are `src/core/binary/BinaryBuffer.js` and the `sgpt_*` readers.
509
+ That boundary is a build-time assertion, not a convention — a lint rule that fails the build on any
510
+ other engine import.
511
+
512
+ ### 7.2 Views
513
+
514
+ | View | Answers |
515
+ |---|---|
516
+ | **Frame strip** | Which frame is interesting. Frame time over the session, GPU and CPU overlaid, hitches marked, brush to select a range. Drawn from the directory index alone, so it appears before the payload finishes parsing. |
517
+ | **Timeline / flame graph** | Where the time went in *this* frame. Spans on a GPU track, nested by `FrameGraphScope`; a CPU track above with encode time; hover for exact ns; click to select. Uncertainty rendering when `timestamp_period_ns` is coarse (§2.1). |
518
+ | **Statistics** | Where the time goes *in general*. Per-pass min/median/p95/max/total across the selected frame range, sorted by total contribution. **On a default-quantization capture this is the only honest view**, and the inspector should open on it in that case rather than on the timeline. |
519
+ | **Dependency graph** | Why this pass runs, and what it waits on. Passes and resource nodes, culled ones greyed, edges directed. Select a pass → highlight its transitive inputs. Select a resource → its version chain and every reader. |
520
+ | **Resource table** | What memory costs. Every resource node with declared bytes, format, usage, transient/imported, lifetime span, peak concurrent footprint. Sorted by size. Declared total vs `gpu_memory_usage` side by side. |
521
+ | **Pass detail** | Everything about one pass. Timings across frames as a sparkline, dispatch/draw counts, derived total invocations, pipeline and workgroup size, attachments, bindings at level 3. |
522
+ | **Frame comparison** | What changed. Two frames or two ranges side by side, per-pass deltas sorted by regression. This is the view that makes the tool useful for optimisation work rather than only for diagnosis. |
523
+
524
+ ### 7.3 What it must refuse to do
525
+
526
+ - **Never interpolate across the quantum.** If the data is 100 µs-granular, no view draws a 12 µs
527
+ span. Draw the quantum.
528
+ - **Never present the CPU and GPU tracks as one clock** (§2.3). Two tracks, anchored per frame,
529
+ labelled as nominal.
530
+ - **Never hide dropped spans.** If the recorder dropped passes on slot exhaustion (§1.2.1), say how
531
+ many, on the frame that dropped them.
532
+
533
+ ---
534
+
535
+ ## 8. Phasing
536
+
537
+ Each milestone is independently useful and independently shippable.
538
+
539
+ ### M0 — Measure the assumptions (½ day)
540
+
541
+ Before any of the below. Instrument one Sponza capture and answer three questions, because three
542
+ size estimates and one whole design decision rest on them:
543
+
544
+ 1. How many distinct frame-graph topologies over 600 frames? (§5.4)
545
+ 2. What is the observed `timestamp_period_ns` on our dev machines, flag on and flag off? (§2.1)
546
+ 3. How many GPU passes per frame, actually? (`GPUTimerArray` default is 1024 slots; §1.2.1)
547
+
548
+ Write the answers into this document.
549
+
550
+ ### M1 — Timing spine (2–3 days)
551
+
552
+ `GPUTimerArray` pooling and bound checks; the `FrameGraph.execute` bracket and debug groups;
553
+ `GPUProfileSession` at level 0; `META`/`STRS`/`FRAM`/`DIRE` chunks; round-trip test on
554
+ `SoftwareGPUDevice`. Deliverable: a `.sgpt` with real spans and no viewer.
555
+
556
+ ### M2 — Inspector skeleton (2–3 days)
557
+
558
+ Package scaffold, format readers, drop target, frame strip, timeline, pass detail. Deliverable: a
559
+ capture you can look at.
560
+
561
+ ### M3 — Structure (2–3 days)
562
+
563
+ `TOPO` chunk with deduplication; resource descriptors; scopes; cull state. Dependency graph and
564
+ resource table in the inspector. Deliverable: the "why is this pass here" question becomes
565
+ answerable.
566
+
567
+ ### M4 — Workload (2–3 days)
568
+
569
+ Proxy encoders; `PIPE` chunk; dispatch/draw counts; derived invocation counts. Deliverable: the "is
570
+ this dispatch the right size" question becomes answerable.
571
+
572
+ ### M5 — Analysis (2–3 days)
573
+
574
+ Statistics view, frame comparison, counter tracks, Chrome Trace Event export.
575
+
576
+ ### M6 — Publish (1–2 days)
577
+
578
+ Build target, static hosting, a format specification document written for someone outside the
579
+ company, and the sharing story: what a user sends us and what we can read from it.
580
+
581
+ **Not in scope, listed so it stays that way:** buffer/texture content capture, shader source in the
582
+ container, replay, live attach to a running session, anything requiring a browser extension.
583
+
584
+ ---
585
+
586
+ ## 9. Testing
587
+
588
+ Per the established tiers:
589
+
590
+ | Tier | Covers |
591
+ |---|---|
592
+ | **Unit, node** | Format round-trip: build a synthetic session, encode, decode, assert structural equality. Every chunk. Forward compatibility: a reader skipping an unknown chunk. Truncation and corruption: a bad checksum, a short chunk, a directory pointing past EOF — all must fail with a named error, not a stack trace out of `BinaryBuffer`. |
593
+ | **`SoftwareGPUDevice`** | The recorder end to end without a GPU. The device already emulates `timestamp-query`, query sets and `write_pass_timestamp`, and already refuses a query set over 4096. Encode a frame graph, run a session, decode the output, assert the topology matches what was recorded. This is where the §1.4 attribution logic gets its coverage. |
594
+ | **Playground page** | `src/shade/playground/` gets a capture harness against Sponza, which is also how M0 gets answered. |
595
+ | **Inspector** | Golden captures checked into the package as fixtures. Parse-and-render smoke tests. A capture recorded before a format change must still open — that is what `min_reader_version` is for and it needs a test that proves it. |
596
+
597
+ ---
598
+
599
+ ## 10. Risks and open questions
600
+
601
+ | Risk | Severity | Handling |
602
+ |---|---|---|
603
+ | **Timestamp quantization makes captures useless on default browsers** (§2.1) | **High** | Measure and record the period; make the statistics view the default when it is coarse; document the flag prominently. Accept that shared user captures will mostly be coarse. |
604
+ | Topology dedup does not pay off | Medium | M0 measures it. Design degrades gracefully; the size claims do not. |
605
+ | Proxy encoder overhead distorts what it measures | Medium | Level-gate it; record measured overhead in `META`; forward-only methods, no allocation per call. |
606
+ | One `GPUTimerArray` per context means several query sets per frame (§2.4) | Low–Medium | Record `query_set_id`. Consider a per-frame shared array as a follow-up, which would also simplify pooling. |
607
+ | Format churn during development invalidates captures | Low | `min_reader_version` from day one; the inspector reads every version it ever supported; fixtures in the test suite. |
608
+ | Publishing a proprietary-engine tool separately | Low, but real | The §4 rule-1 boundary is what makes this tractable. Enforce it in the build. Confirm the licensing intent for the published inspector before M6. |
609
+
610
+ **Open questions for you:**
611
+
612
+ 1. **Monorepo or not.** `packages/` does not exist and this repo has no workspaces. Options: (a) npm
613
+ workspaces with `packages/gpu-inspector-tool` as a real workspace — cleanest, touches the root
614
+ `package.json` and CI; (b) an unreferenced directory with its own `package.json`, built manually —
615
+ zero risk to the engine build, worse ergonomics. **Recommendation: (a)**, but it is your call
616
+ whether you want workspaces in this repo at all.
617
+ 2. **Does the recorder ship in production builds?** Rollup runs `@rollup/plugin-strip`. Shipping it
618
+ means users can send us captures, which is the stated goal; it also means the hooks survive
619
+ stripping and the null-check cost must genuinely be zero.
620
+ 3. **How much does the frame-graph bracket in `FrameGraph.execute` bother you?** It is the one edit
621
+ outside `src/shade/` and outside the profiler's own files. The alternative — inferring attribution
622
+ from labels — does not work (§1.4).
623
+ 4. **Recording length policy.** Ring buffer of the last N frames (good for "capture the hitch that
624
+ just happened") or explicit start/stop (good for reproducible benchmarks)? Both are cheap; the
625
+ ring buffer is more useful in the field. **Recommendation: both, ring by default.**
@@ -49,7 +49,7 @@ export class NSS {
49
49
  * @returns {number}
50
50
  */
51
51
  static recommended_jitter_sequence_size(upscale_ratio: number): number;
52
- static "__#126@#preprocess_tensor_descriptor"(render_w: any, render_h: any): TextureResourceDescriptor;
52
+ static "__#131@#preprocess_tensor_descriptor"(render_w: any, render_h: any): TextureResourceDescriptor;
53
53
  /**
54
54
  * @param {GraphicsContext} graphics
55
55
  */
@@ -1 +1 @@
1
- {"version":3,"file":"shader_oit_blend.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/rasterize/native/oit/shader_oit_blend.js"],"names":[],"mappings":"AAwDA,2CAkBE;4BAxE0B,gCAAgC"}
1
+ {"version":3,"file":"shader_oit_blend.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/rasterize/native/oit/shader_oit_blend.js"],"names":[],"mappings":"AAyDA,2CAkBE;4BAzE0B,gCAAgC"}
@@ -29,10 +29,11 @@ fn main(
29
29
  let accum_alpha = accum_transparent.a;
30
30
 
31
31
  if(is_nan(accum_transparent.r)){
32
- // not sure why we get invalid results, but we do
33
- // this removes the pixel from the final image
34
- // the final image ends up looking correct as far as I can tell
35
- // TODO investigate
32
+ // Backstop: one NaN fragment in the resolve pass poisons the whole pixel of the
33
+ // additive accumulator, so dropping the pixel beats smearing NaN into the frame.
34
+ // The known source the c[2] -> 0 division in
35
+ // compute_transmittance_from_4_power_moments, visible as a camera-locked stripe —
36
+ // is guarded at the source now; this remains for any future NaN in forward shading.
36
37
  discard;
37
38
  }
38
39