rayzee 11.13.0 → 11.15.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 (278) hide show
  1. package/README.md +95 -22
  2. package/dist/{ActiveColor-YvuQq44O.js → ActiveColor-DakLCifA.js} +1 -1
  3. package/dist/{ArchiveImporter-DQU55mit.js → ArchiveImporter-DuWqpbXf.js} +282 -277
  4. package/dist/{BidirectionalIntegrator-CLmFjSN3.js → BidirectionalIntegrator-BEXXxmZH.js} +199 -198
  5. package/dist/{BufferLayout-BROyMqO1.js → BufferLayout-ny3WneEc.js} +1 -1
  6. package/dist/ColorManagement-CKN2pTRS.js +2537 -0
  7. package/dist/DepthPass-u5g7hr7J.js +68 -0
  8. package/dist/{EngineEvents-CLckhYbL.js → EngineEvents-oQGofgRf.js} +16 -2
  9. package/dist/{EngineIssues-CfJiBaNj.js → EngineIssues-t5p7TEjb.js} +2 -0
  10. package/dist/{FileFormats-sPGJeCRc.js → FileFormats-C91JE5DM.js} +1 -1
  11. package/dist/LocalExposure-Cw1g8rdU.js +344 -0
  12. package/dist/{Logger-dDDGj9Av.js → Logger-CH-TZ1co.js} +1 -1
  13. package/dist/{NeuralRetouch-CEkBhI1M.js → NeuralRetouch-CLtoW6Vt.js} +5 -5
  14. package/dist/{NeuralSuperRes-Drjws9nE.js → NeuralSuperRes-PlLjWpMF.js} +14 -14
  15. package/dist/{SolarLimb-ZYl-Pwl0.js → PackedRayBuffer-DwhV931f.js} +8 -12
  16. package/dist/{PathTracer-7a7L3cGF.js → PathTracer-BMtUFjdP.js} +5263 -4868
  17. package/dist/{PhysicalSky-DUIbTE93.js → PhysicalSky-DqanSS2m.js} +49 -48
  18. package/dist/PictureView-DpHE_jDr.js +96 -0
  19. package/dist/RayzeeRenderer-C9zGAMJo.js +3281 -0
  20. package/dist/{sceneCachePolicy-DavHt6Ii.js → SceneMetadata-BUfzHMSj.js} +335 -608
  21. package/dist/SolarLimb-BiVdxxmL.js +8 -0
  22. package/dist/TextureBuckets-D09iX9_y.js +308 -0
  23. package/dist/TextureSampling-CvMi8LNc.js +904 -0
  24. package/dist/{ToneMapGPU-4GPwoG_c.js → ToneMapGPU-tJZo_-7S.js} +22 -12
  25. package/dist/{ViewTransforms-CYN7bq2w.js → ViewTransforms-Bh7hSjSb.js} +1 -1
  26. package/dist/{WorkingMatrix-C6y233hT.js → WorkingMatrix-CDGicYGE.js} +1 -1
  27. package/dist/{ZipReader-gDSWr0I5.js → ZipReader-KPFbIuOs.js} +1 -1
  28. package/dist/addons/archives.es.js +2 -2
  29. package/dist/addons/bidirectional.es.js +1 -1
  30. package/dist/addons/color.es.js +3 -3
  31. package/dist/addons/formats.es.js +1 -1
  32. package/dist/addons/physical-sky.es.js +1 -1
  33. package/dist/addons/storage.es.js +3 -3
  34. package/dist/archiveFormats-j39rQeKs.js +37 -0
  35. package/dist/encoders.es.js +942 -0
  36. package/dist/identity-x_UfobDa.js +65 -0
  37. package/dist/{openStorage-CdyVjmps.js → openStorage-CxLMw2_a.js} +61 -62
  38. package/dist/rayzee-core.es.js +13 -12
  39. package/dist/rayzee.es.js +795 -1053
  40. package/dist/rayzee.umd.js +163 -115
  41. package/package.json +5 -2
  42. package/src/AssetConfig.js +1 -1
  43. package/src/EngineDefaults.js +1 -1
  44. package/src/EngineEvents.js +26 -0
  45. package/src/EngineIssues.js +2 -0
  46. package/src/Platform.js +40 -0
  47. package/src/RayzeeRenderer.js +221 -1111
  48. package/src/RenderSettings.js +3 -3
  49. package/src/addons/archives.js +2 -2
  50. package/src/addons/bidirectional.js +1 -1
  51. package/src/addons/color.js +6 -6
  52. package/src/addons/formats.js +1 -1
  53. package/src/addons/physicalSky.js +1 -1
  54. package/src/addons/storage.js +3 -3
  55. package/src/{Processor → bvh}/BVHBuilder.js +2 -2
  56. package/src/{Processor → bvh}/BVHLeafFold.js +1 -1
  57. package/src/{Processor/Workers → bvh}/BVHRefitWorker.js +2 -2
  58. package/src/{Processor → bvh}/BVHRefitter.js +1 -1
  59. package/src/{Processor/Workers → bvh}/BVHSubtreeWorker.js +2 -2
  60. package/src/{Processor/Workers → bvh}/BVHWorker.js +3 -3
  61. package/src/{Processor → bvh}/ParallelBVHBuilder.js +3 -3
  62. package/src/{Processor → bvh}/SplitBLAS.js +2 -2
  63. package/src/{Processor → bvh}/TLASBuilder.js +4 -4
  64. package/src/{Processor/Workers → bvh}/TLASWorker.js +2 -2
  65. package/src/{Color → color}/BakedViews.js +5 -1
  66. package/src/{Color → color}/BasicColor.js +7 -0
  67. package/src/{Color → color}/ColorManagement.js +132 -64
  68. package/src/{Color → color}/Displays.js +35 -0
  69. package/src/{Color → color}/LutBake.js +163 -9
  70. package/src/{Color → color}/OcioRuntime.js +1 -1
  71. package/src/color/OcioViews.js +1086 -0
  72. package/src/core.js +8 -8
  73. package/src/{Processor/Workers → environment}/CDFWorker.js +1 -1
  74. package/src/{Processor → environment}/EnvironmentExactTable.js +2 -2
  75. package/src/{managers → environment}/EnvironmentManager.js +10 -10
  76. package/src/{Processor → environment}/EquirectHDRInfo.js +1 -1
  77. package/src/{Processor → environment}/PhysicalSky.js +5 -5
  78. package/src/{Processor → environment}/SolarLimb.js +1 -1
  79. package/src/index.js +46 -46
  80. package/src/{Processor → lights}/EmissiveTriangleBuilder.js +5 -5
  81. package/src/{managers → lights}/LightManager.js +3 -3
  82. package/src/{Processor → lights}/LightSerializer.js +1 -1
  83. package/src/{Processor → loaders}/AssetLoader.js +115 -11
  84. package/src/loaders/SceneLoading.js +730 -0
  85. package/src/{Processor → loaders/archives}/ArchiveCache.js +3 -3
  86. package/src/{Processor → loaders/archives}/ArchiveImporter.js +15 -15
  87. package/src/{Processor/PBRT → loaders/pbrt}/PBRTSceneBuilder.js +2 -3
  88. package/src/{Processor/USD → loaders/usd}/USDScene.js +1 -1
  89. package/src/{Processor/USD → loaders/usd}/index.js +1 -1
  90. package/src/{managers → materials}/MaterialDataManager.js +8 -8
  91. package/src/{Processor → materials}/MaterialPacking.js +1 -1
  92. package/src/{Processor/Workers → materials}/PackWorker.js +1 -1
  93. package/src/{Processor → materials}/TextureCreator.js +160 -54
  94. package/src/{Processor/Workers → materials}/TexturesWorker.js +11 -14
  95. package/src/{Processor → memory}/HostMemory.js +1 -1
  96. package/src/memory/SceneSpill.js +477 -0
  97. package/src/node/nodePlatform.js +4 -2
  98. package/src/output/ImageEncoders.js +1306 -0
  99. package/src/output/Pictures.js +460 -0
  100. package/src/{Processor → output}/ToneMapCPU.js +37 -11
  101. package/src/{Processor → output}/ToneMapGPU.js +54 -8
  102. package/src/{integrators → pathtracer}/BidirectionalIntegrator.js +16 -16
  103. package/src/{Processor → pathtracer}/KernelManager.js +29 -4
  104. package/src/{Processor → pathtracer}/PackedRayBuffer.js +3 -3
  105. package/src/{Stages → pathtracer}/PathTracer.js +294 -180
  106. package/src/{Stages → pathtracer}/PathTracerStage.js +84 -26
  107. package/src/{Processor → pathtracer}/QueueManager.js +42 -13
  108. package/src/{Processor → pathtracer}/ShaderBuilder.js +1 -1
  109. package/src/{Processor → pathtracer}/StorageTexturePool.js +2 -2
  110. package/src/{managers → pathtracer}/UniformManager.js +2 -2
  111. package/src/{Pipeline → pipeline}/CompletionTracker.js +8 -1
  112. package/src/{Stages → pipeline}/Compositor.js +128 -21
  113. package/src/{Processor → scene}/BuildTimer.js +1 -1
  114. package/src/{Processor → scene}/GeometryExtractor.js +46 -6
  115. package/src/scene/SceneEdits.js +260 -0
  116. package/src/{Processor → scene}/SceneProcessor.js +65 -1106
  117. package/src/scene/SceneRefit.js +823 -0
  118. package/src/{TSL → shaders}/Atmosphere.js +1 -1
  119. package/src/{TSL → shaders}/BVHTraversal.js +1 -1
  120. package/src/{TSL → shaders}/CameraRay.js +1 -1
  121. package/src/{TSL → shaders}/Common.js +1 -1
  122. package/src/{TSL → shaders}/EmissiveSampling.js +1 -1
  123. package/src/{TSL → shaders}/Environment.js +1 -1
  124. package/src/{TSL → shaders}/LightGuide.js +1 -1
  125. package/src/{TSL → shaders}/LightVisibility.js +1 -1
  126. package/src/{TSL → shaders}/Sun.js +1 -1
  127. package/src/{TSL → shaders}/TextureSampling.js +1 -1
  128. package/src/{TSL → shaders/kernels}/CompactKernel.js +2 -2
  129. package/src/{TSL → shaders/kernels}/ConnectKernel.js +10 -10
  130. package/src/{TSL → shaders/kernels}/DebugKernel.js +4 -4
  131. package/src/shaders/kernels/DepthPass.js +146 -0
  132. package/src/{TSL → shaders/kernels}/ExtendKernel.js +5 -5
  133. package/src/{TSL → shaders/kernels}/FinalWriteKernel.js +14 -4
  134. package/src/{TSL → shaders/kernels}/GenerateKernel.js +5 -5
  135. package/src/{TSL → shaders/kernels}/LightGenerateKernel.js +14 -14
  136. package/src/{TSL → shaders/kernels}/LightSplatKernel.js +9 -9
  137. package/src/{TSL → shaders/kernels}/MergeKernel.js +7 -7
  138. package/src/{TSL → shaders/kernels}/ShadeKernel.js +27 -27
  139. package/src/{TSL → shaders/kernels}/SortGlobalKernels.js +2 -2
  140. package/src/{TSL → shaders}/patches.js +1 -1
  141. package/src/{Storage → storage}/BLASCache.js +1 -1
  142. package/src/{Storage → storage}/DownloadCache.js +10 -0
  143. package/src/{Storage → storage}/SceneGraphCodec.js +17 -2
  144. package/src/{Headless.js → viewer/Headless.js} +15 -3
  145. package/src/{PathTracerApp.js → viewer/PathTracerApp.js} +54 -32
  146. package/src/{SceneState → viewer}/SceneState.js +3 -3
  147. package/src/{managers → viewer/animation}/AnimationManager.js +1 -1
  148. package/src/{managers/timeline → viewer/animation}/CameraTrack.js +1 -1
  149. package/src/{managers/timeline → viewer/animation}/TimelineManager.js +1 -1
  150. package/src/{managers → viewer/animation}/VideoRenderManager.js +10 -6
  151. package/src/{managers → viewer/camera}/CameraManager.js +10 -10
  152. package/src/{managers → viewer/camera}/InteractionManager.js +4 -4
  153. package/src/{Stages → viewer/denoise}/DenoiserSettings.js +1 -1
  154. package/src/{managers → viewer/denoise}/DenoisingManager.js +27 -17
  155. package/src/{Stages → viewer/denoise}/MotionVector.js +3 -3
  156. package/src/{Stages → viewer/denoise}/NRD.js +4 -4
  157. package/src/{Stages → viewer/denoise}/NormalDepth.js +8 -8
  158. package/src/{Passes → viewer/denoise}/OIDNDenoiser.js +94 -25
  159. package/src/{Passes → viewer/denoise}/OIDNTemporalHistory.js +1 -1
  160. package/src/{managers → viewer/lights}/GoboManager.js +3 -3
  161. package/src/{managers → viewer/lights}/IESManager.js +4 -4
  162. package/src/{Processor → viewer/lights}/IESParser.js +1 -1
  163. package/src/{managers → viewer/overlays}/OverlayManager.js +10 -10
  164. package/src/{managers/helpers → viewer/overlays}/TransformGizmoHelper.js +1 -1
  165. package/src/{managers → viewer/overlays}/TransformManager.js +1 -1
  166. package/src/{managers/helpers → viewer/overlays}/ViewOverlayRenderer.js +2 -12
  167. package/src/{Passes → viewer/picture}/AIUpscaler.js +3 -3
  168. package/src/{Processor/Workers → viewer/picture}/AIUpscalerWorker.js +2 -2
  169. package/src/{Stages → viewer/picture}/AutoExposure.js +2 -2
  170. package/src/{Stages → viewer/picture}/LocalExposure.js +2 -2
  171. package/src/{neural → viewer/picture}/NeuralRetouch.js +3 -3
  172. package/src/{neural → viewer/picture}/NeuralSuperRes.js +5 -5
  173. package/src/viewer/picture/PictureView.js +205 -0
  174. package/dist/ColorManagement-3xw0xXRg.js +0 -1973
  175. package/dist/RayzeeRenderer-CjjGT2e0.js +0 -3717
  176. package/dist/SceneMetadata-CoAHTAmo.js +0 -183
  177. package/dist/identity-C1cLD1C0.js +0 -49
  178. package/dist/shared-BGBcSxBQ.js +0 -17
  179. package/src/Color/OcioViews.js +0 -633
  180. package/src/Processor/generateMaterialSpheres.js +0 -71
  181. package/src/Processor/utils.js +0 -613
  182. /package/dist/{AssetConfig-DSEntE65.js → AssetConfig-C8BsprCp.js} +0 -0
  183. /package/src/{utils/Logger.js → Logger.js} +0 -0
  184. /package/src/{Processor → bvh}/ReinsertionOptimizer.js +0 -0
  185. /package/src/{Color → color}/ActiveColor.js +0 -0
  186. /package/src/{Color → color}/BuiltinViews.js +0 -0
  187. /package/src/{Color → color}/ColorSpaces.js +0 -0
  188. /package/src/{Color → color}/InputColorSpaces.js +0 -0
  189. /package/src/{Color → color}/ViewTransforms.js +0 -0
  190. /package/src/{Color → color}/WorkingMatrix.js +0 -0
  191. /package/src/{Processor → environment}/AtmosphereModel.js +0 -0
  192. /package/src/{Processor → environment}/SimpleSky.js +0 -0
  193. /package/src/{Processor → environment}/SunPosition.js +0 -0
  194. /package/src/{Processor → lights}/LightBVHBuilder.js +0 -0
  195. /package/src/{Processor → lights}/blackbody.js +0 -0
  196. /package/src/{Processor → loaders}/FileFormats.js +0 -0
  197. /package/src/{Processor → loaders}/GLTFDecoders.js +0 -0
  198. /package/src/{Processor → loaders}/GLTFDiffuseTransmission.js +0 -0
  199. /package/src/{Processor → loaders}/PlatformImageLoader.js +0 -0
  200. /package/src/{Processor → loaders}/SceneMetadata.js +0 -0
  201. /package/src/{Processor → loaders/archives}/ArchiveReader.js +0 -0
  202. /package/src/{Processor → loaders/archives}/ZipReader.js +0 -0
  203. /package/src/{Processor → loaders/archives}/archiveFormats.js +0 -0
  204. /package/src/{Processor/PBRT → loaders/pbrt}/EqualAreaOctahedral.js +0 -0
  205. /package/src/{Processor/PBRT → loaders/pbrt}/LoopSubdivision.js +0 -0
  206. /package/src/{Processor/PBRT → loaders/pbrt}/PBRTAnimation.js +0 -0
  207. /package/src/{Processor/PBRT → loaders/pbrt}/PBRTCurves.js +0 -0
  208. /package/src/{Processor/PBRT → loaders/pbrt}/PBRTMaterials.js +0 -0
  209. /package/src/{Processor/PBRT → loaders/pbrt}/PBRTMath.js +0 -0
  210. /package/src/{Processor/PBRT → loaders/pbrt}/PBRTParser.js +0 -0
  211. /package/src/{Processor/PBRT → loaders/pbrt}/PBRTScattering.js +0 -0
  212. /package/src/{Processor/PBRT → loaders/pbrt}/PBRTTextureBake.js +0 -0
  213. /package/src/{Processor/PBRT → loaders/pbrt}/PBRTTokenizer.js +0 -0
  214. /package/src/{Processor/PBRT → loaders/pbrt}/PFM.js +0 -0
  215. /package/src/{Processor/PBRT → loaders/pbrt}/buffers.js +0 -0
  216. /package/src/{Processor/PBRT → loaders/pbrt}/index.js +0 -0
  217. /package/src/{Processor/USD → loaders/usd}/USDLayer.js +0 -0
  218. /package/src/{Processor/USD → loaders/usd}/USDStage.js +0 -0
  219. /package/src/{Processor/USD → loaders/usd}/USDText.js +0 -0
  220. /package/src/{Processor → materials}/ResampleRGBA8.js +0 -0
  221. /package/src/{Processor → materials}/TextureBuckets.js +0 -0
  222. /package/src/{Processor → memory}/ChunkedRecords.js +0 -0
  223. /package/src/{Processor → memory}/VRAMTracker.js +0 -0
  224. /package/src/{Processor → output}/TextureReadback.js +0 -0
  225. /package/src/{Processor → pathtracer}/CameraOptimizer.js +0 -0
  226. /package/src/{Pipeline → pipeline}/BindingAudit.js +0 -0
  227. /package/src/{Pipeline → pipeline}/EventDispatcher.js +0 -0
  228. /package/src/{Pipeline → pipeline}/PipelineContext.js +0 -0
  229. /package/src/{Pipeline → pipeline}/RenderPipeline.js +0 -0
  230. /package/src/{Pipeline → pipeline}/RenderStage.js +0 -0
  231. /package/src/{SceneState/portable.js → portable.js} +0 -0
  232. /package/src/{Processor → scene}/BufferLayout.js +0 -0
  233. /package/src/{Processor → scene}/InstanceTable.js +0 -0
  234. /package/src/{SceneHelpers.js → scene/SceneHelpers.js} +0 -0
  235. /package/src/{managers → scene}/ViewCamera.js +0 -0
  236. /package/src/{TSL → shaders}/Bidirectional.js +0 -0
  237. /package/src/{TSL → shaders}/BidirectionalLamps.js +0 -0
  238. /package/src/{TSL → shaders}/Clearcoat.js +0 -0
  239. /package/src/{TSL → shaders}/Debugger.js +0 -0
  240. /package/src/{TSL → shaders}/Displacement.js +0 -0
  241. /package/src/{TSL → shaders}/EnvironmentCDF.js +0 -0
  242. /package/src/{TSL → shaders}/Fresnel.js +0 -0
  243. /package/src/{TSL → shaders}/HitFacet.js +0 -0
  244. /package/src/{TSL → shaders}/LightBVHSampling.js +0 -0
  245. /package/src/{TSL → shaders}/LightsCore.js +0 -0
  246. /package/src/{TSL → shaders}/LightsDirect.js +0 -0
  247. /package/src/{TSL → shaders}/LightsIndirect.js +0 -0
  248. /package/src/{TSL → shaders}/LightsSampling.js +0 -0
  249. /package/src/{TSL → shaders}/MaterialEvaluation.js +0 -0
  250. /package/src/{TSL → shaders}/MaterialProperties.js +0 -0
  251. /package/src/{TSL → shaders}/MaterialSampling.js +0 -0
  252. /package/src/{TSL → shaders}/MaterialTransmission.js +0 -0
  253. /package/src/{TSL → shaders}/PathTracerCore.js +0 -0
  254. /package/src/{TSL → shaders}/Random.js +0 -0
  255. /package/src/{TSL → shaders}/SceneResources.js +0 -0
  256. /package/src/{TSL → shaders}/ShadowTerminator.js +0 -0
  257. /package/src/{TSL → shaders}/Struct.js +0 -0
  258. /package/src/{TSL → shaders}/Subsurface.js +0 -0
  259. /package/src/{Storage → storage}/CDFCache.js +0 -0
  260. /package/src/{Storage → storage}/GeometrySpill.js +0 -0
  261. /package/src/{Storage → storage}/SpillStore.js +0 -0
  262. /package/src/{Storage → storage}/StorageManager.js +0 -0
  263. /package/src/{Storage → storage}/StorageOps.js +0 -0
  264. /package/src/{Storage → storage}/StorageWorker.js +0 -0
  265. /package/src/{Storage → storage}/areas.js +0 -0
  266. /package/src/{Storage → storage}/events.js +0 -0
  267. /package/src/{Storage → storage}/identity.js +0 -0
  268. /package/src/{Storage → storage}/index.js +0 -0
  269. /package/src/{Storage → storage}/inlineTransport.js +0 -0
  270. /package/src/{Storage → storage}/locks.js +0 -0
  271. /package/src/{Storage → storage}/openStorage.js +0 -0
  272. /package/src/{Storage → storage}/sceneCachePolicy.js +0 -0
  273. /package/src/{Storage → storage}/shared.js +0 -0
  274. /package/src/{Storage → storage}/transport.js +0 -0
  275. /package/src/{managers → viewer/camera}/WalkControls.js +0 -0
  276. /package/src/{managers/helpers → viewer/overlays}/OutlineHelper.js +0 -0
  277. /package/src/{managers/helpers → viewer/overlays}/TileHelper.js +0 -0
  278. /package/src/{managers/helpers → viewer/overlays}/overlaySurface.js +0 -0
package/README.md CHANGED
@@ -147,7 +147,7 @@ A single HTML file — no Node.js, no build step. Uses [ES module import maps](h
147
147
  "three/tsl": "https://cdn.jsdelivr.net/npm/three@0.186.0/build/three.tsl.js",
148
148
  "three/webgpu": "https://cdn.jsdelivr.net/npm/three@0.186.0/build/three.webgpu.js",
149
149
  "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.186.0/examples/jsm/",
150
- "oidn-web/": "https://cdn.jsdelivr.net/npm/oidn-web@0.5.0/",
150
+ "oidn-webgpu/": "https://cdn.jsdelivr.net/npm/oidn-webgpu@0.6.0/",
151
151
  "rayzee": "https://cdn.jsdelivr.net/npm/rayzee/dist/rayzee.es.js"
152
152
  }
153
153
  }
@@ -533,7 +533,7 @@ To pause rendering for image-viewing UI, set `engine.pauseRendering = true` and
533
533
 
534
534
  ### Renderer core (`rayzee/core`)
535
535
 
536
- `PathTracerApp` is built on `RayzeeRenderer`, the renderer without the viewer: a scene and camera in, path-traced samples accumulated, the image out. The denoisers, camera controls, gizmo, overlays, timeline and animation playback exist only in `PathTracerApp`; six capabilities come as add-ons — file formats beyond glTF and `.hdr`, the physical sky, scene archives, bidirectional path tracing, OpenColorIO colour and on-disk storage. Its entry point downloads about 40 % less (249 KB against 418 KB compressed). It takes the same constructor options except `container`, and renders the same pixels.
536
+ `PathTracerApp` is built on `RayzeeRenderer`, the renderer without the viewer: a scene and camera in, path-traced samples accumulated, the image out. The denoisers, camera controls, gizmo, overlays, timeline and animation playback exist only in `PathTracerApp`; six capabilities come as add-ons — file formats beyond glTF and `.hdr`, the physical sky, scene archives, bidirectional path tracing, OpenColorIO colour and on-disk storage. Its entry point downloads about 30 % less at startup (277 KB against 404 KB compressed). It takes the same constructor options except `container`, and renders the same pixels.
537
537
 
538
538
  ```js
539
539
  import { RayzeeRenderer } from 'rayzee/core';
@@ -890,8 +890,8 @@ await engine.unloadColorConfig();
890
890
  ```
891
891
 
892
892
  - **Load and unload through `engine.loadColorConfig()` / `unloadColorConfig()`** once a scene exists: they undo an adopted working space while the config that converted the environment is still loaded.
893
- - A view is baked to a log2 shaper and a 65³ table, interpolated tetrahedrally; the same table drives the canvas, the GPU and CPU readbacks and the menu (`listViewTransforms()`, `onRegistryChange()`). An OCIO view returns display-encoded colour, so the engine switches the output pass to linear while one is active.
894
- - **Baked views.** `await engine.color.saveBakedView(id)` writes a view's table to a file (157 KB gzip for 65³), and `await engine.color.loadBakedView(bytes, { expect })` registers it with no runtime and no config — show the look on the first frame, load the config later. When that config loads, a baked view whose files match the fingerprint it was baked from is kept as is: no rebake, no new id, no restart.
893
+ - A view is baked to a log2 shaper and a 65³ table, interpolated tetrahedrally — where that measures poorly, on linear Rec.709's axes and at 97³, whichever is closer (`entry.error` says what it cost); the same table drives the canvas, the GPU and CPU readbacks and the menu (`listViewTransforms()`, `onRegistryChange()`). An OCIO view returns display-encoded colour, so the engine switches the output pass to linear while one is active.
894
+ - **Baked views.** `await engine.color.saveBakedView(id)` writes a view's table to a file (157 KB gzip for 65³, 426 KB for 97³), and `await engine.color.loadBakedView(bytes, { expect })` registers it with no runtime and no config — show the look on the first frame, load the config later. When that config loads, a baked view whose files match the fingerprint it was baked from is kept as is: no rebake, no new id, no restart.
895
895
  - `renderToBuffer({ colorSpace })` takes `'srgb'` (display bytes through the active view), `'linear'` (the working-space accumulation) or a config colour space; `source: 'display'` reads what the viewport shows, denoised, instead of the raw accumulation.
896
896
  - Degradations (a view that cannot bake, a display the canvas cannot show) are recorded as warnings in the [degradation contract](#degradation-contract).
897
897
 
@@ -1081,8 +1081,10 @@ surface** — pin a version and branch on the strings; they are never renamed or
1081
1081
  | `emissive.instances_collapsed` | an emissive instanced mesh was too large to expand, so its copies light the scene as one |
1082
1082
  | `refit.shared_geometry` | a deform was asked for on a mesh that shares its triangles, and was skipped |
1083
1083
  | `denoiser.unavailable` | a requested denoise or upscale produced nothing — the denoiser was not built, OIDN was off while accumulating, or the pass needs a canvas in a document |
1084
+ | `denoiser.non_finite_input` | the render handed OIDN NaN or infinite pixels (`detail.color` / `albedo` / `normal`: how many), which were treated as zero — a warning, recorded again only after a clean frame |
1084
1085
  | `output.source_fallback` | `renderToBuffer( { source: 'display' } )` found no denoised picture and returned the raw accumulation |
1085
1086
  | `output.tonemap_fallback` | `renderToBuffer`'s `'srgb'` bytes were tone-mapped on the CPU, not the GPU — the picture is the same within a level, only slower (a warning: strict does not throw) |
1087
+ | `output.pass_unavailable` | `exportImage` was asked for an EXR layer it cannot write, such as `albedo` or `normal` with no denoiser on (`detail.pass`); the file is written without it |
1086
1088
  | `light.placeholder_skipped` | a `RectAreaLightPlaceholder` node lacked `userData.name` or `userData.type: 'RectAreaLight'`, so no light was made for it |
1087
1089
  | `capability.missing` | a feature was asked for whose add-on is not installed on the core (procedural sky, an unregistered integrator, a colour config, storage) — names the add-on |
1088
1090
  | `color.config_load_failed` / `viewTransform.bake_failed` / `viewTransform.display_mismatch` | a colour config failed to load (the previous one stays), a view could not be rebaked, or a view targets a display the canvas cannot show (a saved buffer is still right) — warnings |
@@ -1111,7 +1113,7 @@ setting as `{ value, source, routed }`, and `routed: false` means stored but rea
1111
1113
 
1112
1114
  ### Output Methods
1113
1115
 
1114
- Canvas output, screenshots, and scene statistics — accessed as direct methods on the engine.
1116
+ Canvas output, screenshots, saved files and scene statistics — accessed as direct methods on the engine.
1115
1117
 
1116
1118
  ```js
1117
1119
  engine.getCanvas() // Get the canvas with the final rendered image
@@ -1135,6 +1137,61 @@ a.click();
1135
1137
  URL.revokeObjectURL(url);
1136
1138
  ```
1137
1139
 
1140
+ #### Saving a file
1141
+
1142
+ `exportImage()` writes the render as a file and returns `{ blob, extension, mimeType, width, height, colorSpace, … }`.
1143
+ It works on the core too, and headless.
1144
+
1145
+ | `format` | What the file holds |
1146
+ |---|---|
1147
+ | `'png'` (`bitDepth: 8` or `16`), `'jpeg'`, `'webp'` | the picture the canvas shows: exposure, view and denoising applied; at 8 bits, JPEG and WebP, the AI upscaler's picture while one shows (`upscaled: false` skips it) |
1148
+ | `'heic'`, `'avif'` | the same picture, written by the browser's video encoder |
1149
+ | `'exr'` (`precision: 'half'` or `'float'`), `'hdr'` (Radiance) | the light itself, before exposure and view, in the working space or `colorSpace`; with `asShown: true`, the light the screen gives off for the picture, so any viewer shows it as the screen does |
1150
+
1151
+ ```js
1152
+ const { blob, extension } = await engine.exportImage({ format: 'png', bitDepth: 16 });
1153
+ const exr = await engine.exportImage({ format: 'exr', passes: ['albedo', 'normal', 'depth'] });
1154
+ const photo = await engine.exportImage({ format: 'jpeg', gainMap: true }); // an HDR photo
1155
+ engine.exportInfo(); // what can be written now: { width, height, upscaled, hdr, layers: { albedo, normal, depth } }
1156
+ ```
1157
+
1158
+ - **HDR photos.** `gainMap: true` on `'jpeg'`, `'heic'` or `'avif'` adds a gain map — a second, small picture that
1159
+ says how much brighter each part of the HDR version is (ISO 21496-1; Ultra HDR in a JPEG). Photo viewers that read gain
1160
+ maps show the file in HDR, others the normal picture. It needs the screen showing HDR
1161
+ (`engine.color.setHdrOutput(true)` on an HDR display; `exportInfo().hdr`).
1162
+ - **EXR layers.** `albedo` and `normal` are the denoisers' guide images, so they exist only while a denoiser is on;
1163
+ `depth` is measured when asked for. A layer that cannot be written records `output.pass_unavailable`.
1164
+ - **Where each works.** JPEG, WebP, HEIC and AVIF need a browser (its canvas or video encoder); PNG, EXR and HDR work in
1165
+ Node too. `canEncodeStill('heic')` from `rayzee/encoders` says whether this browser can write HEIC or AVIF.
1166
+ - Render details (samples, size, view, settings, versions) go into the file, except a WebP, unless `metadata: false`.
1167
+ An EXR's also say how its picture was shown (the exposure, auto exposure's included, local exposure and a held
1168
+ backdrop). The file writers download on the first export, not at startup.
1169
+ - **Showing a saved EXR again.** `await engine.createPictureView(canvas)` (the viewer, `PathTracerApp`) gives a
1170
+ picture view on a canvas of your own; `await view.show(exrBlob)` draws the raw EXR exactly as an HDR screen showed it,
1171
+ through the same view, exposure and local exposure, and returns `{ shown, reason }` (`reason`: the screen shows no HDR,
1172
+ the file has no such details, its colour config is not the one loaded, or a later `show()` took over). It reads the
1173
+ file's header first and decodes the pixels only of a file it shows. `view.setGrade(fn)` adds your own edit after
1174
+ the view, a TSL function of the shown colour; `view.redraw()` after its uniforms change; `view.dispose()`.
1175
+
1176
+ The writers are also a module of their own, `rayzee/encoders`, for pixels a host already has. It is part of the
1177
+ package, not an add-on: nothing to install, and importing it loads nothing else (9 KB compressed).
1178
+
1179
+ ```js
1180
+ import { encodePNG, encodeEXR, encodeHDR, IMAGE_FORMATS } from 'rayzee/encoders';
1181
+
1182
+ const png = await encodePNG({ data, width, height }); // RGBA, Uint8Array (8 bits) or Uint16Array (16), top row first
1183
+ const hdr = await encodeHDR({ data: floats, width, height }); // RGBA Float32Array
1184
+ const exr = await encodeEXR({ width, height, channels: [
1185
+ { name: 'R', data: floats, stride: 4, offset: 0 },
1186
+ { name: 'G', data: floats, stride: 4, offset: 1 },
1187
+ { name: 'B', data: floats, stride: 4, offset: 2 },
1188
+ ] });
1189
+ ```
1190
+
1191
+ Chrome on macOS takes about 5 seconds to start its first hardware video encoder after the browser launches, and about
1192
+ 2 ms after that. HEIC and MP4 both use it. `prepareStill('heic')` starts it ahead of time without encoding anything,
1193
+ for example when an export menu opens.
1194
+
1138
1195
  ---
1139
1196
 
1140
1197
  ### Render Resolution Reserve
@@ -1183,7 +1240,7 @@ engine.vram.getReport(); // formatted one-line summary string
1183
1240
 
1184
1241
  `denoiser` is what the engine allocates for OIDN — its three float inputs, its half-float output and
1185
1242
  the motion history. `canvas` is one image per presented surface (a browser may keep one or two more)
1186
- plus the buffer three.js's output pass tone-maps through. Not counted: oidn-web's own network weights
1243
+ plus the buffer three.js's output pass tone-maps through. Not counted: oidn-webgpu's own network weights
1187
1244
  and activations, which it reports by count, not by size; and the neural passes, which run on a
1188
1245
  `GPUDevice` of their own.
1189
1246
 
@@ -1257,10 +1314,10 @@ const blob = await engine.screenshot();
1257
1314
  engine.setDeterministicMode(false); // restore the previous configuration
1258
1315
  ```
1259
1316
 
1260
- The RNG is already pure — `hash(pixel, rayIndex, frame)`, no clock, no `Math.random()` in any shader. What varies run to run is *which* uniforms and dispatch grids are live on frame k, so `setDeterministicMode` disables adaptive sampling, per-pixel freeze, the readback-driven per-bounce early exit and dynamic dispatch sizing, interaction mode, auto-focus, and auto-exposure, and pins the sampler's seed axis to the accumulation frame. It also forces `renderLimitMode` to `'frames'` — a wall-clock render limit retires at a run-dependent sample count. It leaves the rAF loop stopped; `renderFrames` is the drive.
1317
+ The RNG is already pure — `hash(pixel, rayIndex, frame)`, no clock, no `Math.random()` in any shader. What varies run to run is *which* uniforms and dispatch grids are live on frame k, so `setDeterministicMode` disables adaptive sampling, per-pixel freeze, the readback-driven per-bounce early exit and GPU-sized dispatch, interaction mode, auto-focus, and auto-exposure, and pins the sampler's seed axis to the accumulation frame. It also forces `renderLimitMode` to `'frames'` — a wall-clock render limit retires at a run-dependent sample count. It leaves the rAF loop stopped; `renderFrames` is the drive.
1261
1318
 
1262
1319
  - `engine.isDeterministic` — whether output is currently bit-reproducible.
1263
- - `setDeterministicMode(true, { pinDispatch: false })` keeps the two readback-driven dispatch heuristics active. Output is then *not* reproducible; this exists so performance measurements reflect shipping behaviour rather than a configuration production never runs.
1320
+ - `setDeterministicMode(true, { pinDispatch: false })` keeps the two dispatch heuristics active (GPU-sized dispatch and the readback-driven early exit). Output is then *not* reproducible; this exists so performance measurements reflect shipping behaviour rather than a configuration production never runs.
1264
1321
  - `renderFrames` raises `maxSamples` if needed, and throws if something retires the render early.
1265
1322
 
1266
1323
  #### Production renders, reproducibly
@@ -1279,8 +1336,9 @@ It renders without `requestAnimationFrame` until the sample ceiling, convergence
1279
1336
  whichever comes first — then runs the final OIDN denoise once, and fires `RENDER_COMPLETE` as the
1280
1337
  loop does. Adaptive sampling decides from counts read back from the GPU; normally each is applied
1281
1338
  whenever it lands, so the frame that retires depends on how fast frames are submitted. For its
1282
- duration `renderUntilComplete` runs those readbacks in **lockstep**: one issued at frame N is applied
1283
- at frame N + 4 exactly, and the render waits if it has not landed; every reset also starts from seed
1339
+ duration `renderUntilComplete` runs those readbacks in **lockstep**: the first, issued at frame 1, is
1340
+ applied at frame 2, then one issued at frame N (a multiple of 4) at frame N + 4 exactly, and the
1341
+ render waits if one has not landed; every reset also starts from seed
1284
1342
  0 and from nothing the previous render measured. It turns interaction mode off meanwhile (a
1285
1343
  wall-clock mode for camera drags), and keeps submissions at most 2 × `drainEvery` frames ahead of
1286
1344
  the GPU. A time limit is wall-clock by nature, so that one stop is not reproducible. Auto exposure, if you turn it
@@ -1290,7 +1348,7 @@ on, lands on a metering of the finished image before the closing denoise.
1290
1348
 
1291
1349
  #### Batch rendering
1292
1350
 
1293
- The supported entry point for a render farm is `rayzee/src/Headless.js`, exported from the package.
1351
+ The supported entry point for a render farm is `rayzee/src/viewer/Headless.js`, exported from the package.
1294
1352
  Its defaults are a batch renderer's — `strict`, deterministic, storage off —
1295
1353
  so a degraded render throws instead of shipping:
1296
1354
 
@@ -1311,6 +1369,9 @@ try {
1311
1369
  `denoise: true` turns OIDN on before accumulating (it reads the albedo and normal buffers, which
1312
1370
  are written only while it is on), runs **one** final denoise with `app.runFinalDenoise()`, and reads
1313
1371
  it back with `renderToBuffer( { source: 'display' } )`. Driving it yourself is the same three calls.
1372
+ `denoise: { quality: 'high', tileSize: 2048 }` also picks the model (the default is `'fast'`) and the tile cap: with no
1373
+ live view to keep smooth, a larger cap is faster for more GPU memory — 1920×1080 as one tile instead of four took 27 %
1374
+ less time on an M5 Pro. A tile never grows past what the GPU can dispatch (~2000² with its border), whatever the cap.
1314
1375
  `renderToBuffer` reports the picture it read as `source`, and records `output.source_fallback` when
1315
1376
  `'display'` was asked for, a denoiser is in use, and nothing had published — so a strict host cannot
1316
1377
  ship a noisy image by mistake. Its `'srgb'` bytes are tone-mapped on the GPU — 9 ms at 4096×2160,
@@ -1328,7 +1389,8 @@ here, or `engine.settings` before loading the model.
1328
1389
 
1329
1390
  **Provenance.** `engine.getProvenance()` — also `frame.provenance` from `captureHeadless` — is plain
1330
1391
  JSON naming what produced the image: engine and three.js versions, the adapter, every live setting with its source, the colour pipeline, the render size and
1331
- samples, and whether it ran headless, strict, deterministic or lockstepped. `mode.lockstep` says
1392
+ samples, whether it ran headless, strict, deterministic or lockstepped, and the denoisers (`denoise.live`, and
1393
+ `denoise.final`: the OIDN tier, weights file, precision and tile). `mode.lockstep` says
1332
1394
  whether the current image was traced in lockstep, so it stays true after `renderUntilComplete` turns
1333
1395
  lockstep back off. Store it beside each render and "what made this?" has an answer without rendering
1334
1396
  again.
@@ -1368,7 +1430,7 @@ app.dispose();
1368
1430
  - **No canvas means headless.** `new PathTracerApp(null)` — or `{ headless: true }` — makes its own
1369
1431
  canvas (a WebGPU context over a plain texture), runs no render loop (drive it with `renderFrames` or
1370
1432
  `renderUntilComplete`), and builds neither the overlay renderer nor the transform gizmo.
1371
- - **`configurePlatform({ Worker, decodeImage })`** is where a host without a browser supplies what one
1433
+ - **`configurePlatform({ Worker, decodeImage, readFile })`** is where a host without a browser supplies what one
1372
1434
  would. `nodePlatform()` from `rayzee/node` fills it: `NodeWorker`, the Web Worker API over
1373
1435
  `worker_threads`, runs the engine's inlined workers; `decodeImage(bytes, mimeType)` is yours — PNG,
1374
1436
  JPEG or WebP to RGBA8, straight alpha, top row first — since the engine carries no decoder. It decodes
@@ -1389,6 +1451,10 @@ app.dispose();
1389
1451
  packs in a worker, reading images decoded by `decodeImage` in place (they are kept in shared
1390
1452
  memory): on the main thread it held up the BVH workers, and a 1.9M-triangle, 91-texture model
1391
1453
  loaded in 4.1–4.9 s. It now loads in 2.1 s, against Chrome's 2.9 s on the same machine.
1454
+ - **Offline: OIDN weights from disk.** Node's `fetch` cannot open `file:` URLs, so `nodePlatform()` also hands
1455
+ the engine a file reader, and what it downloads itself — the OIDN weights, IES profiles — can come from a folder:
1456
+ `configureAssets({ oidnWeightsBaseUrl: 'file:///opt/rayzee/oidn/' })`, holding the `.tza` files the tiers
1457
+ name (`rt_hdr_alb_nrm_small`, `rt_hdr_calb_cnrm_small`, `rt_hdr_calb_cnrm`, `rt_hdr_calb_cnrm_large`).
1392
1458
  - `nodePlatform()` also defines `ProgressEvent`, which three.js's `FileLoader` constructs while
1393
1459
  streaming; that is the only global it sets. three.js's own Draco and KTX2 loaders call the global
1394
1460
  `Worker`; the engine lends them `NodeWorker` for the length of each glTF parse, so a Draco or KTX2
@@ -1412,7 +1478,7 @@ WebGPU timestamp queries are the only true GPU metric here — `pipeline.getStat
1412
1478
 
1413
1479
  `getKernelGPUTimings()` attributes each compute pass of the last resolved frame back to a wavefront kernel name. Durations are **summed per kernel across the frame**, so `extend` reports its whole per-frame cost over every bounce iteration, not one bounce. `unattributed` collects passes belonging to no registered kernel (other stages, denoisers), so `sum(kernels) + unattributed` reconciles with `total`.
1414
1480
 
1415
- Neither method can see the OIDN denoise — `oidn-web` submits on its own command encoders, outside
1481
+ Neither method can see the OIDN denoise — `oidn-webgpu` submits on its own command encoders, outside
1416
1482
  the stages three.js times. It carries its own profiler instead:
1417
1483
 
1418
1484
  ```js
@@ -1616,6 +1682,12 @@ import { acquireSharedStorage } from 'rayzee/addons/storage';
1616
1682
  // Headless rendering (see Deterministic & Headless Rendering)
1617
1683
  import { renderHeadless, openHeadless, captureHeadless } from 'rayzee';
1618
1684
 
1685
+ // File writers behind exportImage(), for pixels a host already has (see Saving a file)
1686
+ import {
1687
+ IMAGE_FORMATS, encodePNG, encodeEXR, encodeHDR, encodeWithCanvas, encodeGainMapJPEG,
1688
+ encodeStill, canEncodeStill, prepareStill,
1689
+ } from 'rayzee/encoders';
1690
+
1619
1691
  // Platform services for hosts without a browser (see Running in Node)
1620
1692
  import { configurePlatform, getPlatform } from 'rayzee';
1621
1693
  import { nodePlatform, NodeWorker } from 'rayzee/node';
@@ -1726,7 +1798,7 @@ import { setBindingAudit, getBindingAuditFindings, clearBindingAuditFindings } f
1726
1798
 
1727
1799
  | Package | Purpose | Install needed? |
1728
1800
  |---|---|---|
1729
- | `oidn-web` | Intel Open Image Denoise for high-quality final renders | Yes — `npm install oidn-web` (**>=0.5.0**) |
1801
+ | `oidn-webgpu` | Intel Open Image Denoise for high-quality final renders | Yes — `npm install oidn-webgpu` (**>=0.6.0**; it was `oidn-web` up to 0.5.0) |
1730
1802
  | `onnxruntime-web` | AI-powered upscaling | No — loaded from CDN at runtime |
1731
1803
  | `@bb-studio/ocio` | OpenColorIO runtime for [Colour Management](#colour-management) (~6 MB WebAssembly) | Only to load colour configs — `npm install @bb-studio/ocio`, then pass it as `ocioRuntimeFactory` |
1732
1804
 
@@ -1742,7 +1814,7 @@ accumulating, so a preview shows a clean picture as it refines instead of only a
1742
1814
  1. **Install the package**
1743
1815
 
1744
1816
  ```bash
1745
- npm install oidn-web
1817
+ npm install oidn-webgpu
1746
1818
  ```
1747
1819
 
1748
1820
  2. **Enable in your app**
@@ -1857,7 +1929,7 @@ Two constraints shape that table, and neither is optional:
1857
1929
  (`> 120 ms`).** A tier a machine can afford is kept — at 512² that is every tier. The verdict
1858
1930
  survives a camera move, because the device does not get faster between them; it is re-taken when
1859
1931
  the tier or the resolution changes. Past it, each render swaps twice (to the cheap model when the
1860
- view moves, back for the finished image). A swap costs 10-20 ms on oidn-web 0.4.0, and each model's
1932
+ view moves, back for the finished image). A swap costs 10–50 ms on oidn-webgpu 0.6.0 (the large model the most), and each model's
1861
1933
  weights are downloaded once and kept, so a swap never goes back to the network.
1862
1934
 
1863
1935
  #### What paces the refreshes
@@ -1917,8 +1989,9 @@ Denoise cost scales with frame area, and the tile tracks the frame so that a fra
1917
1989
  tile pays no overlap padding — at 1024x1024 that is roughly 1.8x faster than tiling it. A cap
1918
1990
  (default 1024) bounds the one-time activation allocation, so larger frames tile and stay
1919
1991
  memory-bounded. Raise or lower it with
1920
- `engine.denoisingManager.denoiser.updateConfiguration({ tileSize: 2048 })`; the effective tile is
1921
- `min( max( width, height ), tileSize )`.
1992
+ `engine.denoisingManager.denoiser.updateConfiguration({ tileSize: 2048 })`: a frame no larger in area than
1993
+ `tileSize`² is one tile, a larger one is split into tiles of at most `tileSize`, and no tile grows past what the GPU
1994
+ can dispatch (about 2000² with its border and overlap) — past that the denoise would silently do nothing.
1922
1995
 
1923
1996
  > **Note:** The neural network model is downloaded on first use. Subsequent runs use the browser cache. OIDN also works with `configureForMode('production')`, which enables it automatically alongside high-quality render settings.
1924
1997
 
@@ -1947,13 +2020,13 @@ engine.addEventListener(EngineEvents.UPSCALING_END, () => console.log('Upsc
1947
2020
  ## Troubleshooting
1948
2021
 
1949
2022
  **OIDN: `Cannot find module './tza'` (webpack)**
1950
- The `oidn-web` package uses dynamic imports that webpack cannot resolve. This does not affect Vite or other ESM-native bundlers. Add `oidn-web` to your webpack externals:
2023
+ The `oidn-webgpu` package uses dynamic imports that webpack cannot resolve. This does not affect Vite or other ESM-native bundlers. Add the engine's import of it to your webpack externals:
1951
2024
 
1952
2025
  ```js
1953
2026
  // webpack.config.js
1954
2027
  module.exports = {
1955
2028
  externals: {
1956
- 'oidn-web': 'oidn-web'
2029
+ 'oidn-webgpu/dist/oidn.js': 'oidn-webgpu/dist/oidn.js'
1957
2030
  }
1958
2031
  };
1959
2032
  ```
@@ -1964,7 +2037,7 @@ Then load it via a script tag or import map instead:
1964
2037
  <script type="importmap">
1965
2038
  {
1966
2039
  "imports": {
1967
- "oidn-web": "https://cdn.jsdelivr.net/npm/oidn-web@0.4.0/dist/oidn.js"
2040
+ "oidn-webgpu/dist/oidn.js": "https://cdn.jsdelivr.net/npm/oidn-webgpu@0.6.0/dist/oidn.js"
1968
2041
  }
1969
2042
  }
1970
2043
  </script>
@@ -1,4 +1,4 @@
1
- //#region src/Color/ActiveColor.js
1
+ //#region src/color/ActiveColor.js
2
2
  var e = "Linear Rec.709 (sRGB)", t = null;
3
3
  function n() {
4
4
  return t;