rayzee 10.0.0 → 11.1.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 (176) hide show
  1. package/README.md +252 -44
  2. package/dist/ActiveColor-YvuQq44O.js +13 -0
  3. package/dist/ArchiveImporter-Hn35o6Z5.js +5145 -0
  4. package/dist/AssetConfig-DSEntE65.js +30 -0
  5. package/dist/BidirectionalIntegrator-CBw8hkeu.js +946 -0
  6. package/dist/BufferLayout-D_IBo2ci.js +150 -0
  7. package/dist/ColorManagement-oeEk7oSu.js +1488 -0
  8. package/dist/EngineEvents-Ci8dVWCP.js +73 -0
  9. package/dist/EngineIssues-CIZnXHsF.js +72 -0
  10. package/dist/FileFormats-sPGJeCRc.js +102 -0
  11. package/dist/Logger-dDDGj9Av.js +97 -0
  12. package/dist/{NeuralRetouch-CYgkQY8Z.js → NeuralRetouch-BzNpiVHZ.js} +8 -6
  13. package/dist/{NeuralSuperRes-PkgDLQcD.js → NeuralSuperRes-Bk7bHg2B.js} +55 -120
  14. package/dist/PathTracer-72XufKAr.js +29976 -0
  15. package/dist/PhysicalSky-BgjdV88k.js +1219 -0
  16. package/dist/RayzeeRenderer-1QRO97eq.js +3551 -0
  17. package/dist/SolarLimb-CPaeZVwz.js +721 -0
  18. package/dist/ToneMapGPU-CjU3osDd.js +177 -0
  19. package/dist/ViewTransforms-CYN7bq2w.js +255 -0
  20. package/dist/WorkingMatrix-C6y233hT.js +27 -0
  21. package/dist/ZipReader-gDSWr0I5.js +98 -0
  22. package/dist/addons/archives.es.js +3 -0
  23. package/dist/addons/bidirectional.es.js +2 -0
  24. package/dist/addons/color.es.js +3 -0
  25. package/dist/addons/formats.es.js +2 -0
  26. package/dist/addons/physical-sky.es.js +2 -0
  27. package/dist/addons/storage.es.js +3 -0
  28. package/dist/archiveFormats-tnAoUL1j.js +94 -0
  29. package/dist/identity-DrQsGT2o.js +39 -0
  30. package/dist/openStorage-DwcBRUj7.js +820 -0
  31. package/dist/rayzee-core.es.js +12 -0
  32. package/dist/rayzee.es.js +2551 -44024
  33. package/dist/rayzee.umd.js +528 -487
  34. package/dist/sceneCachePolicy-C67jbci-.js +443 -0
  35. package/dist/shared-BGBcSxBQ.js +17 -0
  36. package/package.json +23 -2
  37. package/src/Color/ActiveColor.js +34 -0
  38. package/src/Color/BasicColor.js +147 -0
  39. package/src/Color/ColorManagement.js +7 -31
  40. package/src/Color/ViewTransforms.js +5 -1
  41. package/src/EngineDefaults.js +62 -1029
  42. package/src/EngineEvents.js +2 -0
  43. package/src/EngineIssues.js +2 -0
  44. package/src/Headless.js +6 -5
  45. package/src/Passes/AIUpscaler.js +58 -141
  46. package/src/Passes/OIDNDenoiser.js +92 -65
  47. package/src/Passes/OIDNTemporalHistory.js +1 -1
  48. package/src/PathTracerApp.js +620 -4026
  49. package/src/Pipeline/PipelineContext.js +0 -4
  50. package/src/Platform.js +36 -0
  51. package/src/Processor/ArchiveCache.js +20 -7
  52. package/src/Processor/ArchiveImporter.js +1265 -0
  53. package/src/Processor/ArchiveReader.js +22 -4
  54. package/src/Processor/AssetLoader.js +327 -1763
  55. package/src/Processor/AtmosphereModel.js +1 -2
  56. package/src/Processor/BVHBuilder.js +14 -126
  57. package/src/Processor/BVHLeafFold.js +4 -6
  58. package/src/Processor/BVHRefitter.js +67 -46
  59. package/src/Processor/BufferLayout.js +291 -0
  60. package/src/Processor/EmissiveTriangleBuilder.js +1 -1
  61. package/src/Processor/EnvironmentExactTable.js +187 -0
  62. package/src/Processor/EquirectHDRInfo.js +30 -223
  63. package/src/Processor/FileFormats.js +116 -0
  64. package/src/Processor/GLTFDecoders.js +85 -0
  65. package/src/Processor/GLTFDiffuseTransmission.js +63 -0
  66. package/src/Processor/GeometryExtractor.js +15 -5
  67. package/src/Processor/HostMemory.js +7 -1
  68. package/src/Processor/IESParser.js +47 -35
  69. package/src/Processor/InstanceTable.js +1 -1
  70. package/src/Processor/KernelManager.js +35 -2
  71. package/src/Processor/MaterialPacking.js +10 -8
  72. package/src/Processor/PBRT/PBRTMaterials.js +254 -42
  73. package/src/Processor/PBRT/PBRTParser.js +49 -19
  74. package/src/Processor/PBRT/PBRTScattering.js +93 -0
  75. package/src/Processor/PBRT/PBRTSceneBuilder.js +1050 -75
  76. package/src/Processor/PBRT/PBRTTextureBake.js +179 -0
  77. package/src/Processor/PBRT/PFM.js +59 -0
  78. package/src/Processor/PackedRayBuffer.js +116 -9
  79. package/src/Processor/ParallelBVHBuilder.js +3 -6
  80. package/src/Processor/PhysicalSky.js +5 -4
  81. package/src/Processor/PlatformImageLoader.js +50 -6
  82. package/src/Processor/QueueManager.js +39 -5
  83. package/src/Processor/ReinsertionOptimizer.js +2 -2
  84. package/src/Processor/SceneMetadata.js +30 -5
  85. package/src/Processor/SceneProcessor.js +53 -62
  86. package/src/Processor/ShaderBuilder.js +6 -16
  87. package/src/Processor/SimpleSky.js +1 -62
  88. package/src/Processor/SolarLimb.js +3 -0
  89. package/src/Processor/SplitBLAS.js +1 -1
  90. package/src/Processor/StorageTexturePool.js +22 -1
  91. package/src/Processor/TLASBuilder.js +1 -3
  92. package/src/Processor/TextureBuckets.js +237 -0
  93. package/src/Processor/TextureCreator.js +181 -8
  94. package/src/Processor/ToneMapGPU.js +64 -15
  95. package/src/Processor/Workers/BVHRefitWorker.js +5 -2
  96. package/src/Processor/Workers/BVHSubtreeWorker.js +1 -34
  97. package/src/Processor/Workers/BVHWorker.js +5 -18
  98. package/src/Processor/Workers/CDFWorker.js +6 -183
  99. package/src/Processor/Workers/TexturesWorker.js +103 -18
  100. package/src/Processor/archiveFormats.js +7 -0
  101. package/src/Processor/utils.js +2 -1
  102. package/src/RayzeeRenderer.js +3900 -0
  103. package/src/RenderSettings.js +68 -62
  104. package/src/Stages/ASVGF.js +13 -14
  105. package/src/Stages/AutoExposure.js +17 -17
  106. package/src/Stages/BilateralFilter.js +2 -1
  107. package/src/Stages/Compositor.js +8 -23
  108. package/src/Stages/DenoiserSettings.js +182 -0
  109. package/src/Stages/EdgeFilter.js +2 -1
  110. package/src/Stages/MotionVector.js +1 -1
  111. package/src/Stages/NRD.js +11 -5
  112. package/src/Stages/NormalDepth.js +12 -8
  113. package/src/Stages/PathTracer.js +336 -43
  114. package/src/Stages/PathTracerStage.js +69 -66
  115. package/src/Stages/Variance.js +1 -1
  116. package/src/Storage/BLASCache.js +1 -1
  117. package/src/Storage/CDFCache.js +18 -17
  118. package/src/Storage/DownloadCache.js +1 -1
  119. package/src/Storage/SceneGraphCodec.js +46 -3
  120. package/src/Storage/SpillStore.js +1 -1
  121. package/src/Storage/StorageManager.js +45 -9
  122. package/src/Storage/areas.js +4 -0
  123. package/src/TSL/BVHTraversal.js +50 -25
  124. package/src/TSL/Bidirectional.js +208 -0
  125. package/src/TSL/BidirectionalLamps.js +132 -0
  126. package/src/TSL/Clearcoat.js +15 -6
  127. package/src/TSL/Common.js +20 -15
  128. package/src/TSL/ConnectKernel.js +167 -0
  129. package/src/TSL/Debugger.js +1 -1
  130. package/src/TSL/Displacement.js +4 -3
  131. package/src/TSL/EmissiveSampling.js +65 -18
  132. package/src/TSL/Environment.js +77 -106
  133. package/src/TSL/EnvironmentCDF.js +85 -39
  134. package/src/TSL/ExtendKernel.js +8 -3
  135. package/src/TSL/FinalWriteKernel.js +4 -4
  136. package/src/TSL/GenerateKernel.js +18 -4
  137. package/src/TSL/HitFacet.js +35 -5
  138. package/src/TSL/LightBVHSampling.js +40 -9
  139. package/src/TSL/LightGenerateKernel.js +293 -0
  140. package/src/TSL/LightGuide.js +198 -0
  141. package/src/TSL/LightSplatKernel.js +180 -0
  142. package/src/TSL/LightVisibility.js +111 -0
  143. package/src/TSL/LightsCore.js +13 -38
  144. package/src/TSL/LightsDirect.js +28 -29
  145. package/src/TSL/LightsIndirect.js +3 -1
  146. package/src/TSL/LightsSampling.js +239 -51
  147. package/src/TSL/MaterialEvaluation.js +113 -31
  148. package/src/TSL/MaterialProperties.js +44 -17
  149. package/src/TSL/MaterialTransmission.js +52 -47
  150. package/src/TSL/MergeKernel.js +224 -0
  151. package/src/TSL/PathTracerCore.js +65 -29
  152. package/src/TSL/Random.js +5 -1
  153. package/src/TSL/SceneResources.js +51 -0
  154. package/src/TSL/ShadeKernel.js +985 -101
  155. package/src/TSL/Struct.js +10 -0
  156. package/src/TSL/Sun.js +1 -1
  157. package/src/TSL/TextureSampling.js +66 -61
  158. package/src/addons/archives.js +14 -0
  159. package/src/addons/bidirectional.js +13 -0
  160. package/src/addons/color.js +32 -0
  161. package/src/addons/formats.js +16 -0
  162. package/src/addons/physicalSky.js +14 -0
  163. package/src/addons/storage.js +19 -0
  164. package/src/core.js +31 -0
  165. package/src/index.js +13 -23
  166. package/src/integrators/BidirectionalIntegrator.js +838 -0
  167. package/src/managers/AnimationManager.js +88 -6
  168. package/src/managers/CameraManager.js +103 -46
  169. package/src/managers/DenoisingManager.js +14 -10
  170. package/src/managers/EnvironmentManager.js +125 -103
  171. package/src/managers/GoboManager.js +9 -0
  172. package/src/managers/MaterialDataManager.js +48 -37
  173. package/src/managers/UniformManager.js +32 -10
  174. package/dist/ToneMapGPU-B6XIe3DU.js +0 -544
  175. package/dist/rolldown-runtime-CAFD8bLK.js +0 -11
  176. package/src/Processor/TreeletOptimizer.js +0 -574
package/README.md CHANGED
@@ -21,6 +21,8 @@ A real-time WebGPU path tracing engine built on Three.js. Framework-agnostic —
21
21
  - [API Reference](#api-reference)
22
22
  - [Configuring Assets (CDN URLs & cache namespace)](#configuring-assets-cdn-urls--cache-namespace)
23
23
  - [PathTracerApp](#pathtracerapp)
24
+ - [Renderer core (`rayzee/core`)](#renderer-core-rayzeecore)
25
+ - [Add-ons](#add-ons)
24
26
  - [engine.cameraManager](#enginecameramanager)
25
27
  - [Camera Projection (Orthographic, 360° Panorama)](#camera-projection-orthographic-360-panorama)
26
28
  - [engine.lightManager](#enginelightmanager)
@@ -39,6 +41,9 @@ A real-time WebGPU path tracing engine built on Three.js. Framework-agnostic —
39
41
  - [Memory Monitoring](#memory-monitoring)
40
42
  - [Logging](#logging)
41
43
  - [Deterministic & Headless Rendering](#deterministic--headless-rendering)
44
+ - [On-disk Storage (OPFS)](#on-disk-storage-opfs)
45
+ - [Saving Scene State](#saving-scene-state)
46
+ - [Render Checkpoints](#render-checkpoints)
42
47
  - [Events](#events)
43
48
  - [Advanced: Custom Pipeline Stages](#advanced-custom-pipeline-stages)
44
49
  - [All Exports](#all-exports)
@@ -55,7 +60,7 @@ A real-time WebGPU path tracing engine built on Three.js. Framework-agnostic —
55
60
  npm install rayzee three
56
61
  ```
57
62
 
58
- `three` (>=0.185.0) is a required peer dependency.
63
+ `three` (>=0.186.0) is a required peer dependency.
59
64
 
60
65
  ## Getting Started
61
66
 
@@ -137,10 +142,10 @@ A single HTML file — no Node.js, no build step. Uses [ES module import maps](h
137
142
  <script type="importmap">
138
143
  {
139
144
  "imports": {
140
- "three": "https://cdn.jsdelivr.net/npm/three@0.185.0/build/three.webgpu.js",
141
- "three/tsl": "https://cdn.jsdelivr.net/npm/three@0.185.0/build/three.tsl.js",
142
- "three/webgpu": "https://cdn.jsdelivr.net/npm/three@0.185.0/build/three.webgpu.js",
143
- "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.185.0/examples/jsm/",
145
+ "three": "https://cdn.jsdelivr.net/npm/three@0.186.0/build/three.webgpu.js",
146
+ "three/tsl": "https://cdn.jsdelivr.net/npm/three@0.186.0/build/three.tsl.js",
147
+ "three/webgpu": "https://cdn.jsdelivr.net/npm/three@0.186.0/build/three.webgpu.js",
148
+ "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.186.0/examples/jsm/",
144
149
  "oidn-web": "https://cdn.jsdelivr.net/npm/oidn-web@0.4.0/dist/oidn.js",
145
150
  "rayzee": "https://cdn.jsdelivr.net/npm/rayzee/dist/rayzee.es.js"
146
151
  }
@@ -306,7 +311,7 @@ All keys are optional — only what you pass is overridden. Call `getAssetConfig
306
311
 
307
312
  ### PathTracerApp
308
313
 
309
- The main engine class. Extends Three.js `EventDispatcher`. Related functionality is grouped into **namespaced managers** accessed via `engine.cameraManager`, `engine.lightManager`, etc., or as direct methods on the engine instance.
314
+ The main engine class. Extends `RayzeeRenderer`, the [renderer core](#renderer-core-rayzeecore), which extends three.js's `EventDispatcher`. Related functionality is grouped into **namespaced managers** accessed via `engine.cameraManager`, `engine.lightManager`, etc., or as direct methods on the engine instance.
310
315
 
311
316
  ```js
312
317
  const engine = new PathTracerApp(canvas, options?)
@@ -320,7 +325,6 @@ const engine = new PathTracerApp(canvas, options?)
320
325
  | `options.autoResize` | `boolean` | Auto-resize on window resize (default: `true`; always off headless) |
321
326
  | `options.container` | `HTMLElement` | Single DOM parent the engine mounts auxiliary elements into — HUD overlay (tile borders, helpers) and denoiser canvas. Defaults to `canvas.parentNode`. |
322
327
  | `options.strict` | `boolean` | Throw an `EngineIssueError` where the engine would otherwise degrade and carry on (default: `false`). See [Degradation contract](#degradation-contract). |
323
- | `options.profile` | `string` | `'viewer'` (default) or `'physical'` — product tuning that is not a physical constant: area-light scale, environment rotation, tone mapping, saturation. An unknown name throws. |
324
328
  | `options.maxSceneBytes` | `number` | Raise or lower the CPU memory ceiling a scene may need before the engine refuses it (default 9,216 MB). See [Memory monitoring](#memory-monitoring). |
325
329
  | `options.hostMemoryGB` | `number` | The host's memory, for runtimes without Chrome's `navigator.deviceMemory` (which then read as 4 GB and cap the render reserve at 2048). Sizes the reserve and the path pool. |
326
330
  | `options.storage` | `false \| 'auto' \| StorageManager` | On-disk storage (default: `configureAssets( { storage } )`; off under `strict` unless you set it there or here). A manager you pass stays yours to dispose. See [On-disk storage](#on-disk-storage-opfs). |
@@ -346,12 +350,15 @@ Constructing a new `PathTracerApp` on a canvas that already has an active instan
346
350
  #### Loading Assets
347
351
 
348
352
  ```js
349
- await engine.loadModel(url) // Load GLB/GLTF/FBX/OBJ/STL/PLY/DAE/3MF/USDZ/ZIP
353
+ await engine.loadModel(url) // Load a GLB/GLTF by URL
354
+ await engine.loadFile(fileOrUrl) // Any supported file: GLB/GLTF/FBX/OBJ/STL/PLY/DAE/3MF/USD/USDZ, archives, HDR/EXR
350
355
  await engine.loadObject3D(object3d, name?) // Load a Three.js Object3D directly (name is optional, defaults to 'object3d')
351
356
  await engine.loadEnvironment(url) // Load HDR/EXR environment map
352
357
  engine.cancelLoad() // Abort an in-flight download (network phase only; no-op once processing starts)
353
358
  ```
354
359
 
360
+ On `rayzee/core`, formats other than glTF and `.hdr` need the `rayzee/addons/formats` add-on — see [Add-ons](#add-ons).
361
+
355
362
  `loadModel` / `loadObject3D` **replace** the current scene. To add or remove objects from a live scene without a full reload (and without reframing the camera):
356
363
 
357
364
  ```js
@@ -368,6 +375,8 @@ engine.setSceneObjectVisibility(id, visible) // Toggle visi
368
375
 
369
376
  ##### Loading part of a scene archive
370
377
 
378
+ On `rayzee/core`, archives and pbrt need the `rayzee/addons/archives` add-on — see [Renderer core](#renderer-core-rayzeecore).
379
+
371
380
  A pbrt-v4 scene archive (`.tar`, `.tar.gz`, `.zip`) is usually a root `.pbrt` file that includes one
372
381
  subtree per element, and the whole thing rarely fits in a browser tab — Moana is 29 GB unpacked.
373
382
  The archive can be inspected without retaining any of it, then loaded one element at a time:
@@ -435,15 +444,19 @@ Key settings:
435
444
  | `enableEnvironment` | `boolean` | true | Use environment lighting |
436
445
  | `environmentIntensity` | `number` | 1.0 | Environment light strength |
437
446
  | `environmentRotation` | `number` | 0 | Environment Y-rotation (degrees); 0 shows the HDRI as authored, as Blender's unmapped world does |
447
+ | `areaLightIntensityScale` | `number` | 0.1 | Power of a glTF model's placeholder area lights (RectAreaLight extras), read when the model loads, so set it first; 1 is the authored power |
448
+ | `maxTextureSize` | `number` | 4096 | Longest edge of a material texture, read when a model loads (clamped to the hardware ceiling); `setMaxTextureSize()` applies it to the current scene too |
449
+ | `wavefrontSortMaterials` | `boolean` | true | Sort rays by material before shading, above 8 materials; read when the shaders next build |
438
450
  | `showBackground` | `boolean` | true | Show the environment as a visible backdrop for camera-miss rays (vs. a solid/transparent background) |
439
451
  | `samplingTechnique` | `number` | 2 | Sampler: `0` PCG, `1` scrambled Halton, `2` Owen-scrambled Sobol |
452
+ | `integrator` | `string` | 'path' | `'path'` \| `'bidirectional'` \| `'vcm'` (on the core, needs the bidirectional add-on). Bidirectional also traces light subpaths from every light — emissive surfaces, rect/disk, point, spot and directional lights, the sun and the environment — far faster for caustics and light through small openings, about 2× the cost per sample. On a lamp-lit interior with an HDRI it is ~20 % less noisy at equal time; a room lit only through a window stays better path traced. `'vcm'` adds photon merging, for caustics seen in mirrors and through glass. Switching rebuilds the kernels |
440
453
  | `fireflyThreshold` | `number` | 3.0 | Firefly clamping threshold |
441
454
  | `shadowTerminatorOffset` | `number` | 0.1 | Cycles' Shadow Terminator → Geometry Offset: near the light's terminator on a smooth-shaded low-poly mesh, light and environment shadow rays start on the smooth surface the vertex normals describe, not the flat facet. Blender's default; `0` disables |
442
455
  | `transmissiveBounces` | `number` | 5 | Max bounces for transmissive materials |
443
456
  | `maxSubsurfaceSteps` | `number` | 8 | Max random-walk steps for subsurface scattering (raised to 64 by `configureForMode('production')`) |
444
457
  | `enableAlphaShadows` | `boolean` | false | Alpha-tested shadow rays (enabled by `configureForMode('production')`) |
445
458
  | `enableDOF` | `boolean` | false | Enable depth of field |
446
- | `dofMode` | `string` | 'look' | `'look'`: the blur is set by `dofBlur`, the same at any scene scale; `'physical'`: a real lens set by `aperture`, `focalLength` and `unitsPerMetre`. The `physical` render profile defaults to `'physical'` |
459
+ | `dofMode` | `string` | 'look' | `'look'`: the blur is set by `dofBlur`, the same at any scene scale; `'physical'`: a real lens set by `aperture`, `focalLength` and `unitsPerMetre`. |
447
460
  | `dofBlur` | `number` | 0.05 | Look mode: how far a distant background blurs, as a fraction of the image height |
448
461
  | `focusDistance` | `number` | 0.8 | DOF focus distance in scene units — depth along the view axis (the focal plane is flat) |
449
462
  | `aperture` | `number` | 5.6 | Physical mode: f-stop |
@@ -451,23 +464,23 @@ Key settings:
451
464
  | `unitsPerMetre` | `number` | 1 | Physical mode: scene units per real metre, for files whose units are not metres. It carries over between model loads — reset it when the new file's units differ |
452
465
  | `transparentBackground` | `boolean` | false | Transparent canvas background |
453
466
  | `interactionModeEnabled` | `boolean` | true | Render at lower resolution while the camera moves, keeping the full bounce budget ("Fast Navigation" in the app) |
454
- | `interactionRenderScale` | `number` | 0.5 | Per-axis render scale while the camera moves (0.5 = a quarter of the pixels); `1` turns the drop off. Ignored while OIDN is the live denoiser |
467
+ | `interactionRenderScale` | `number` | 0.5 | Per-axis render scale while the camera moves (0.5 = a quarter of the pixels); `1` turns the drop off. Ignored while OIDN is the live denoiser. `PathTracerApp` only |
455
468
  | `renderMode` | `number` | 0 | Internal preview(0)/production(1) flag driving accumulation & ASVGF behavior — normally set via `configureForMode()`, not written directly |
456
469
  | `visMode` | `number` | 0 | Debug visualization mode (0 = off) |
457
- | `environmentMode` | `string` | 'hdri' | Sky mode: `'hdri'` \| `'procedural'` \| `'gradient'` \| `'color'` — not routed through `engine.settings`; use `engine.environmentManager.setMode()` instead |
470
+ | `environmentMode` | `string` | 'hdri' | Sky mode: `'hdri'` \| `'procedural'` \| `'color'` — not routed through `engine.settings`; use `engine.environmentManager.setMode()` instead |
458
471
  | `cameraProjection` | `string` | 'perspective' | `'perspective'` \| `'orthographic'` \| `'equirectangular'` — see [Camera Projection](#camera-projection-orthographic-360-panorama) |
459
472
  | `panoramaLonRange` | `[number, number]` | `[-180, 180]` | Panorama longitude sweep, degrees, left→right |
460
473
  | `panoramaLatRange` | `[number, number]` | `[-90, 90]` | Panorama latitude sweep, degrees, bottom→top |
461
474
  | `panoramaLevelHorizon` | `boolean` | true | Yaw-only panorama basis, so orbit pitch/roll can't tilt the horizon |
462
475
  | `useAdaptiveSampling` | `boolean` | true | Whole-frame early-stop once convergence reaches `adaptiveStopFraction` |
463
- | `noiseThreshold` | `number` | 0.02 | √-luminance-normalized per-pixel noise below which a pixel counts as converged |
476
+ | `noiseThreshold` | `number` | 0.1 | √-luminance-normalized per-pixel noise below which a pixel counts as converged (the production preset uses 0.02) |
464
477
  | `adaptiveMinSamples` | `number` | 8 | Minimum samples before adaptive sampling can trigger |
465
- | `adaptiveStopFraction` | `number` | 0.95 | Fraction of pixels that must converge before the frame retires |
478
+ | `adaptiveStopFraction` | `number` | 0.90 | Fraction of pixels that must converge before the frame retires (the production preset uses 0.94) |
466
479
  | `usePixelFreeze` | `boolean` | true | Per-pixel freeze (Tier-2): skip individually-converged pixels via active-list compaction |
467
480
  | `pixelFreezeThreshold` | `number` | 0.02 | Relative-error threshold for a pixel to become a freeze candidate |
468
481
  | `pixelFreezeStability` | `number` | 8 | Consecutive candidate frames required before a pixel freezes |
469
482
 
470
- See `ENGINE_DEFAULTS` for the full list with default values. The default look is AgX (`toneMapping: 6`) at neutral saturation; tone mapping is chosen through [Colour Management](#colour-management) (`engine.color.setActiveView( id )`), not `settings`.
483
+ See `ENGINE_DEFAULTS` for the full list with default values — every key in it is a setting of the same name. The default look is AgX (`DEFAULT_VIEW`) at neutral saturation; tone mapping is chosen through [Colour Management](#colour-management) (`engine.color.setActiveView( id )`), not `settings`. On the core without the colour add-on, set `renderer.renderer.toneMapping`.
471
484
 
472
485
  #### Rendering Modes
473
486
 
@@ -480,6 +493,168 @@ To pause rendering for image-viewing UI, set `engine.pauseRendering = true` and
480
493
 
481
494
  ---
482
495
 
496
+ ### Renderer core (`rayzee/core`)
497
+
498
+ `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.
499
+
500
+ ```js
501
+ import { RayzeeRenderer } from 'rayzee/core';
502
+
503
+ const renderer = await new RayzeeRenderer(canvas).init();
504
+ await renderer.loadModel('/models/scene.glb');
505
+ renderer.camera.position.set(0, 2, 6); // the camera it renders from; reset() after moving it
506
+ renderer.camera.lookAt(0, 0, 0);
507
+ renderer.reset();
508
+ await renderer.renderFrames(256);
509
+ const image = await renderer.renderToBuffer({ colorSpace: 'srgb' });
510
+ renderer.dispose();
511
+ ```
512
+
513
+ Two runnable examples live in the repository: `rayzee/examples/core-node.mjs` (the core alone, in Node, writing a PNG)
514
+ and `rayzee/examples/core-browser/` (the core plus the physical sky, accumulating on a canvas).
515
+
516
+ #### Add-ons
517
+
518
+ Six capabilities install on the core explicitly. `PathTracerApp` installs all six itself, so nothing in this
519
+ section applies to it.
520
+
521
+ | Add-on | Import | Install | When | Without it |
522
+ |---|---|---|---|---|
523
+ | File formats | `fbxFormat`, `objFormat`, `stlFormat`, `plyFormat`, `colladaFormat`, `threeMFFormat`, `usdFormat`, `exrFormat` or `allFormats` from `rayzee/addons/formats` | `renderer.assetLoader.registerFormat(objFormat, exrFormat)` | after `init()` | only glTF/GLB, `.hdr` and images load; any other file's error names the add-on |
524
+ | Physical sky | `PhysicalSky` from `rayzee/addons/physical-sky` | `renderer.environmentManager.setProceduralSky(PhysicalSky)` | after `init()` | `'procedural'` mode records `capability.missing` (throws under `strict`) |
525
+ | Scene archives and pbrt | `ArchiveImporter` from `rayzee/addons/archives` | `renderer.assetLoader.setArchiveImporter(new ArchiveImporter(renderer.assetLoader))` | after `init()` | `.zip`, `.tar` and `.tgz` are not supported formats, and the error names the add-on |
526
+ | Bidirectional and VCM | `BidirectionalIntegrator` from `rayzee/addons/bidirectional` | `renderer.stages.pathTracer.registerIntegrator(['bidirectional', 'vcm'], pt => new BidirectionalIntegrator(pt))` | after `init()` | choosing either integrator records `capability.missing` (throws under `strict`) and keeps the current one |
527
+ | OpenColorIO colour | `ColorManagement` from `rayzee/addons/color` | `renderer.setColorManagement(ColorManagement)` | before or after `init()` | linear Rec.709 through three.js's own tone mappers; `loadColorConfig()` records `capability.missing` and rejects |
528
+ | On-disk storage | `acquireSharedStorage` from `rayzee/addons/storage` | `renderer.setStorageOpener(acquireSharedStorage)` | **before** `init()` | downloads land in memory and nothing is cached between visits |
529
+
530
+ `init()` creates the asset loader, the environment manager and the path tracer stage, which is why four of them come
531
+ after it. Storage is opened during `init()`, so its opener has to be set first.
532
+
533
+ All six, in that order:
534
+
535
+ ```js
536
+ import { RayzeeRenderer, configureAssets } from 'rayzee/core';
537
+ import { acquireSharedStorage } from 'rayzee/addons/storage';
538
+ import { ColorManagement } from 'rayzee/addons/color';
539
+ import { ArchiveImporter } from 'rayzee/addons/archives';
540
+ import { PhysicalSky } from 'rayzee/addons/physical-sky';
541
+ import { BidirectionalIntegrator } from 'rayzee/addons/bidirectional';
542
+ import { allFormats } from 'rayzee/addons/formats';
543
+
544
+ configureAssets({ ocioRuntimeFactory: () => import('@bb-studio/ocio') });
545
+
546
+ const renderer = new RayzeeRenderer(canvas);
547
+ renderer.setStorageOpener(acquireSharedStorage); // before init()
548
+ renderer.setColorManagement(ColorManagement);
549
+ await renderer.init();
550
+ renderer.assetLoader.registerFormat(...allFormats);
551
+ renderer.assetLoader.setArchiveImporter(new ArchiveImporter(renderer.assetLoader));
552
+ renderer.environmentManager.setProceduralSky(PhysicalSky);
553
+ renderer.stages.pathTracer.registerIntegrator(['bidirectional', 'vcm'], pt => new BidirectionalIntegrator(pt));
554
+ ```
555
+
556
+ **Loading on first use.** The physical sky and the archive importer can be installed as loaders instead, so their code
557
+ is fetched only the first time the sky is baked or an archive is read — `PathTracerApp` does this. The archive loader
558
+ takes the formats it reads, which `rayzee/core` exports, so the loader recognises an archive before its code exists:
559
+
560
+ ```js
561
+ import { ARCHIVE_FORMATS } from 'rayzee/core';
562
+
563
+ renderer.environmentManager.setProceduralSkyLoader(() => import('rayzee/addons/physical-sky').then((m) => m.PhysicalSky));
564
+ renderer.assetLoader.setArchiveImporterLoader(
565
+ () => import('rayzee/addons/archives').then((m) => new m.ArchiveImporter(renderer.assetLoader)),
566
+ ARCHIVE_FORMATS,
567
+ );
568
+ ```
569
+
570
+ Colour, storage and the integrators have no loader: colour and storage are used at startup, and an integrator applies
571
+ the moment it is chosen (a lazy one would trace plain frames meanwhile and break reproducible renders).
572
+
573
+ **File formats.** The core reads glTF/GLB (Draco, KTX2 and meshopt decoders are fetched only for a file that uses
574
+ them), `.hdr` and LDR images. FBX, OBJ, STL, PLY, Collada, 3MF, USD/USDZ and EXR are formats to register — import only
575
+ those you read and a bundler leaves the rest out; each three.js loader is downloaded the first time its format is read:
576
+
577
+ ```js
578
+ import { objFormat, usdFormat, exrFormat } from 'rayzee/addons/formats';
579
+
580
+ renderer.assetLoader.registerFormat(objFormat, usdFormat, exrFormat);
581
+ await renderer.loadFile(objFile);
582
+ ```
583
+
584
+ A format of your own registers the same way. A model format's `parse` gets the file and resolves to the model; an
585
+ environment format's `createLoader` returns a three.js loader whose `loadAsync` resolves to a texture:
586
+
587
+ ```js
588
+ renderer.assetLoader.registerFormat({
589
+ name: 'Point cloud (XYZ)', label: 'XYZ', type: 'model', extensions: ['xyz'],
590
+ async parse(file, { filename }) {
591
+ return { model: buildPoints(await file.text(), filename) };
592
+ },
593
+ });
594
+ ```
595
+
596
+ **Physical sky**, for `environmentMode: 'procedural'`:
597
+
598
+ ```js
599
+ renderer.environmentManager.setProceduralSky(PhysicalSky);
600
+ await renderer.environmentManager.setMode('procedural');
601
+ ```
602
+
603
+ **Bidirectional path tracing and vertex merging**, for `integrator: 'bidirectional' | 'vcm'`:
604
+
605
+ ```js
606
+ renderer.stages.pathTracer.registerIntegrator(['bidirectional', 'vcm'], pt => new BidirectionalIntegrator(pt));
607
+ renderer.settings.set('integrator', 'bidirectional');
608
+ ```
609
+
610
+ Its controls are on the active integrator (the same on `PathTracerApp`):
611
+
612
+ ```js
613
+ const integrator = renderer.stages.pathTracer.activeIntegrator;
614
+ integrator.setMergeRadius(1); // 'vcm': gather radius in pixels
615
+ integrator.setMergeTrust(0.25); // 'vcm': how far merging is trusted against the other strategies
616
+ integrator.setLightGuiding(true); // learn where light paths from the sky and sun start
617
+ integrator.setBidirectionalStrategy('connect', { alone: true }); // keep one strategy, for verification
618
+ ```
619
+
620
+ **Scene archives** (`.zip`, `.tar`, `.tar.gz`) and the pbrt scenes in them:
621
+
622
+ ```js
623
+ renderer.assetLoader.setArchiveImporter(new ArchiveImporter(renderer.assetLoader));
624
+ await renderer.loadFile(archiveFile);
625
+ ```
626
+
627
+ **OpenColorIO colour management** — configs, their views and looks, working spaces and export spaces. The host supplies
628
+ the OCIO runtime (the engine never names the package). Without the add-on, pick a tone mapper on the three.js renderer
629
+ instead (`renderer.renderer.toneMapping = AgXToneMapping`):
630
+
631
+ ```js
632
+ configureAssets({ ocioRuntimeFactory: () => import('@bb-studio/ocio') });
633
+ renderer.setColorManagement(ColorManagement);
634
+ await renderer.loadColorConfig({ builtin: 'ocio://cg-config-v4.0.0_aces-v2.0_ocio-v2.5' });
635
+ ```
636
+
637
+ **On-disk storage** (the browser's origin private file system), for the download, environment and scene caches and
638
+ the `memorySpill` option. Asking for it without the add-on (`storage: 'auto'`) records a `capability.missing` warning;
639
+ `storage: false` turns it off either way:
640
+
641
+ ```js
642
+ const renderer = new RayzeeRenderer(canvas);
643
+ renderer.setStorageOpener(acquireSharedStorage);
644
+ await renderer.init();
645
+ ```
646
+
647
+ Several renderers, core or full, can live in one page; they share only the colour management and the on-disk storage,
648
+ which are page-wide.
649
+
650
+ Code of your own that adds a setting declares it on the renderer's settings, with its default, so it gets the same
651
+ provenance, change events and session saving as the built-in ones:
652
+
653
+ ```js
654
+ renderer.settings.define('myGlowStrength', { default: 1, apply: (value) => glow.setStrength(value), reset: true });
655
+ renderer.settings.set('myGlowStrength', 2);
656
+ ```
657
+
483
658
  ### engine.cameraManager
484
659
 
485
660
  Camera switching, auto-focus, DOF, and direct Three.js access.
@@ -617,7 +792,8 @@ engine.stages.pathTracer.materialData.updateMaterial(index, mat) // Replace a m
617
792
  await engine.rebuildMaterials(scene) // Full rebuild (after texture changes)
618
793
 
619
794
  // Cap the longest edge of processed material textures (clamped to the hardware max).
620
- // Larger = sharper textures, ~quadratic VRAM. Reprocesses the current scene by default.
795
+ // Larger = sharper textures, ~quadratic VRAM. Reprocesses the current scene by default;
796
+ // settings.set('maxTextureSize', n) stores it for the next load instead.
621
797
  await engine.setMaxTextureSize(2048)
622
798
  await engine.setMaxTextureSize(4096, { reprocess: false })
623
799
 
@@ -641,6 +817,8 @@ A property a three.js material lacks falls back to `MATERIAL_DEFAULTS` (exported
641
817
 
642
818
  ### Colour Management
643
819
 
820
+ On `rayzee/core` this is the `rayzee/addons/color` add-on — see [Renderer core](#renderer-core-rayzeecore).
821
+
644
822
  `engine.color` is an OpenColorIO pipeline: what textures and lights mean, what the render happens in, and what it is shown and saved as. **It is inert until a config is loaded** — the render stays linear Rec.709 and the view transforms are three.js's own seven, so a host that never loads one sees no change. The host supplies the runtime (`ocioRuntimeFactory` or `ocioRuntimeUrl` in [`configureAssets`](#configuring-assets-cdn-urls--cache-namespace)).
645
823
 
646
824
  ```js
@@ -678,9 +856,8 @@ engine.environmentManager.params // Current environment parameters
678
856
  engine.environmentManager.texture // The loaded environment texture
679
857
  await engine.loadEnvironment(url) // Load HDR/EXR environment map (method on engine)
680
858
  await engine.environmentManager.setEnvironmentMap(tex) // Set a custom environment texture
681
- await engine.environmentManager.setMode(mode) // 'hdri' | 'procedural' | 'gradient' | 'color'
682
- await engine.environmentManager.generateProcedural() // Physical sky: spectral, multiple scattering, analytic sun
683
- await engine.environmentManager.generateGradient() // Gradient sky
859
+ await engine.environmentManager.setMode(mode) // 'hdri' | 'procedural' | 'color'
860
+ await engine.environmentManager.generateProcedural() // Physical sky: spectral, multiple scattering, analytic sun (core: needs rayzee/addons/physical-sky)
684
861
  await engine.environmentManager.generateSolid() // Solid color sky
685
862
  engine.environmentManager.markDirty() // Flag environment for GPU re-upload
686
863
  ```
@@ -708,15 +885,15 @@ Denoiser strategy, ASVGF, OIDN, upscaler, and auto-exposure.
708
885
 
709
886
  ```js
710
887
  // Strategy
711
- engine.denoisingManager.setStrategy('asvgf', 'medium') // 'none' | 'asvgf' | 'edgeaware'
888
+ engine.denoisingManager.setStrategy('asvgf', 'medium') // 'none' | 'asvgf' | 'nrd' | 'edgeaware' | 'oidn'
712
889
  engine.denoisingManager.denoiserStrategy // read back the active strategy (derived from stage state)
713
890
  engine.denoisingManager.setASVGFEnabled(true, 'medium')
714
891
  engine.denoisingManager.applyASVGFPreset('high') // 'low' | 'medium' | 'high'
715
892
  engine.denoisingManager.setAutoExposure(true)
716
893
 
717
894
  // Fine-grained parameters
718
- engine.denoisingManager.setASVGFParams({ temporalAlpha: 0.1, phiColor: 10 })
719
- engine.denoisingManager.setEdgeAwareParams({ pixelEdgeSharpness: 1.0 })
895
+ engine.denoisingManager.setASVGFParams({ temporalAlpha: 0.1, maxAccumFrames: 16 })
896
+ engine.denoisingManager.setEdgeAwareParams({ phiLuminance: 4.0, atrousIterations: 5 })
720
897
  engine.denoisingManager.setAutoExposureParams({ keyValue: 0.18 })
721
898
 
722
899
  // OIDN & Upscaler
@@ -727,7 +904,7 @@ engine.denoisingManager.setTemporalHistory(false) // live OIDN without th
727
904
  engine.denoisingManager.continuousDenoiseInterval = 250 // cap refreshes at 4/sec (default 8 = uncapped)
728
905
  engine.denoisingManager.setUpscalerEnabled(true)
729
906
  engine.denoisingManager.setUpscalerScaleFactor(2) // 2 or 4
730
- engine.denoisingManager.setUpscalerQuality('high') // ESRGAN only
907
+ engine.denoisingManager.setUpscalerQuality('quality') // 'fast' | 'balanced' | 'quality'
731
908
  ```
732
909
 
733
910
  ### engine.interactionManager
@@ -831,7 +1008,11 @@ surface** — pin a version and branch on the strings; they are never renamed or
831
1008
  | `refit.shared_geometry` | a deform was asked for on a mesh that shares its triangles, and was skipped |
832
1009
  | `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 |
833
1010
  | `output.source_fallback` | `renderToBuffer( { source: 'display' } )` found no denoised picture and returned the raw accumulation |
1011
+ | `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) |
834
1012
  | `light.placeholder_skipped` | a `RectAreaLightPlaceholder` node lacked `userData.name` or `userData.type: 'RectAreaLight'`, so no light was made for it |
1013
+ | `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 |
1014
+ | `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 |
1015
+ | `storage.unavailable` / `storage.quota_exceeded` / `storage.write_failed` / `storage.read_failed` / `storage.entry_corrupt` / `storage.cache_mismatch` | on-disk storage is off or failed; the engine carries on in memory — warnings |
835
1016
 
836
1017
  `asset.unreachable` also covers what the engine fetches for itself: OIDN weights, IES profiles and
837
1018
  gobos (`detail.asset` says which).
@@ -1021,7 +1202,7 @@ auto-exposure, if you turn it on.
1021
1202
  #### Batch rendering
1022
1203
 
1023
1204
  The supported entry point for a render farm is `rayzee/src/Headless.js`, exported from the package.
1024
- Its defaults are a batch renderer's — `strict`, `profile: 'physical'`, deterministic, storage off —
1205
+ Its defaults are a batch renderer's — `strict`, deterministic, storage off —
1025
1206
  so a degraded render throws instead of shipping:
1026
1207
 
1027
1208
  ```js
@@ -1045,19 +1226,26 @@ it back with `renderToBuffer( { source: 'display' } )`. Driving it yourself is t
1045
1226
  `'display'` was asked for, a denoiser is in use, and nothing had published — so a strict host cannot
1046
1227
  ship a noisy image by mistake. Its `'srgb'` bytes are tone-mapped on the GPU — 9 ms at 4096×2160,
1047
1228
  where the CPU pass it replaced took 1.4 s on an M-series Mac and 10 s on a cloud host — and match the
1048
- canvas to within one level (it rounds half a level up); `'linear'` is exact.
1229
+ canvas to within one level (it rounds half a level up); `'linear'` is exact. When the GPU pass is
1230
+ unavailable or fails, the CPU does it instead: the result's `toneMappedOn` says `'cpu'` rather than
1231
+ `'gpu'`, and `output.tonemap_fallback` is recorded with the reason.
1049
1232
 
1050
1233
  Constructing `PathTracerApp` yourself instead: pass `strict: true`; storage is then off unless you
1051
1234
  set it. Outside Chrome, pass `hostMemoryGB`.
1052
1235
 
1236
+ The engine has one set of defaults, the viewer's. For lens-accurate depth of field and glTF placeholder area
1237
+ lights at their authored power, set `dofMode: 'physical'` and `areaLightIntensityScale: 1` — through `settings`
1238
+ here, or `engine.settings` before loading the model.
1239
+
1053
1240
  **Provenance.** `engine.getProvenance()` — also `frame.provenance` from `captureHeadless` — is plain
1054
- JSON naming what produced the image: engine and three.js versions, the profile by name *and* by
1055
- value, the adapter, every live setting with its source, the colour pipeline, the render size and
1056
- samples, and whether it ran headless, strict, deterministic or lockstepped. Store it beside each
1057
- render and "what made this?" has an answer without rendering again.
1241
+ 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
1242
+ samples, and whether it ran headless, strict, deterministic or lockstepped. `mode.lockstep` says
1243
+ whether the current image was traced in lockstep, so it stays true after `renderUntilComplete` turns
1244
+ lockstep back off. Store it beside each render and "what made this?" has an answer without rendering
1245
+ again.
1058
1246
 
1059
1247
  **Pinning a look.** A change to what a render looks like when a host sets nothing — a default
1060
- setting, a mode preset, a profile's values, light units — is released as a **major**, with the
1248
+ setting, a mode preset, light units — is released as a **major**, with the
1061
1249
  change described under BREAKING CHANGES in the release notes. Pin a major to pin a look; read the
1062
1250
  notes before moving to the next one.
1063
1251
 
@@ -1097,7 +1285,9 @@ app.dispose();
1097
1285
  JPEG or WebP to RGBA8, straight alpha, top row first — since the engine carries no decoder. It decodes
1098
1286
  every glTF image, embedded or not, and JPEG/PNG skies. PNGs with bytes after `IEND`, which browsers
1099
1287
  accept and strict decoders refuse, are trimmed first; a texture that still fails is recorded as
1100
- `texture.build_failed` rather than dropped. Measured on a 91-texture model: `sharp` and
1288
+ `texture.build_failed` rather than dropped. Without `decodeImage`, each glTF image is recorded that way with what to
1289
+ configure (a strict host's load throws), and the model loads untextured. KTX2 (Basis) textures need no
1290
+ `decodeImage`: three's KTX2 loader decodes them, in a `NodeWorker` the engine lends it. Measured on a 91-texture model: `sharp` and
1101
1291
  `@napi-rs/canvas` (`await loadImage()`, then a 2D canvas) both decode in parallel, ~0.3 s against
1102
1292
  pngjs's 2.5 s serial. The canvas route premultiplies, which zeroes colour under alpha 0 and loses
1103
1293
  it under low alpha; `sharp` is exact. `jpeg-js` differs from libjpeg-turbo by up to 63 levels.
@@ -1111,12 +1301,13 @@ app.dispose();
1111
1301
  memory): on the main thread it held up the BVH workers, and a 1.9M-triangle, 91-texture model
1112
1302
  loaded in 4.1–4.9 s. It now loads in 2.1 s, against Chrome's 2.9 s on the same machine.
1113
1303
  - `nodePlatform()` also defines `ProgressEvent`, which three.js's `FileLoader` constructs while
1114
- streaming; that is the only global it sets. three.js's own Draco and KTX2 workers call the global
1115
- `Worker`, so a model using either also needs `globalThis.Worker = NodeWorker`.
1304
+ streaming; that is the only global it sets. three.js's own Draco and KTX2 loaders call the global
1305
+ `Worker`; the engine lends them `NodeWorker` for the length of each glTF parse, so a Draco or KTX2
1306
+ model loads with nothing set by the host.
1116
1307
 
1117
1308
  Measured on this bench's corpus: all 29 scenes match the Chrome goldens (`npm run bench:node`, RMSE
1118
1309
  ≤ 0.0036, no pixel over 0.02 — the readback's tone map accounts for most of it), and a textured glTF with an
1119
- HDR, a PNG sky or a gradient matches Chrome block for block within 0.05 of a level. Not available
1310
+ HDR or a PNG sky matches Chrome block for block within 0.05 of a level. Not available
1120
1311
  without a browser: on-disk storage (OPFS), gobo libraries (they draw on a 2D canvas), and the AI
1121
1312
  upscaler.
1122
1313
 
@@ -1147,6 +1338,8 @@ list. Both need `timestamp-query`, and `getDenoiseProfile()` returns `null` when
1147
1338
 
1148
1339
  ### On-disk Storage (OPFS)
1149
1340
 
1341
+ On `rayzee/core`, storage needs the `rayzee/addons/storage` add-on (`setStorageOpener`) — see [Renderer core](#renderer-core-rayzeecore).
1342
+
1150
1343
  `engine.storage` is a `StorageManager` over the browser's origin private file system, or `null` where
1151
1344
  there is none (a private window, Node) — everything works without it, only slower. The engine keeps
1152
1345
  its caches there: downloads (models, skies, OIDN weights — revalidated at most daily with a 1-byte `Range` request, and served from the cache meanwhile),
@@ -1243,6 +1436,7 @@ engine.addEventListener(EngineEvents.RENDER_COMPLETE, (e) => {
1243
1436
  | Event | Fired when |
1244
1437
  |---|---|
1245
1438
  | `RENDER_COMPLETE` | Rendering has converged |
1439
+ | `SHADERS_COMPILING` | The path tracer compiles its shaders in the background (`event.compiling` true, then false) — after a model load, a new material layer, a light transport switch. The page stays responsive; the canvas keeps its last frame until they are ready, and `renderFrames()` waits for them |
1246
1440
  | `RENDER_RESET` | Accumulation buffer is reset |
1247
1441
  | `FRAME` | Fires once per `animate()` tick — hook external instrumentation (stats panels, telemetry) here |
1248
1442
  | `DENOISING_START` / `DENOISING_END` | Denoiser runs. `event.continuous` is `true` for a cadence denoise of the still-accumulating image, `false` for the one that ends a render |
@@ -1296,12 +1490,30 @@ class MyCustomStage extends RenderStage {
1296
1490
  }
1297
1491
  ```
1298
1492
 
1493
+ To run between the path tracer and the compositor, subclass the renderer and return the stage from
1494
+ `_createExtraStages()` (call the parent's and add yours); for the compositor to show its picture, list
1495
+ `'my-stage:output'` in `_displaySources()`. `pipeline.addStage()` after `init()` appends after the
1496
+ compositor. A stage that needs an extra path-tracer output asks for it with
1497
+ `stages.pathTracer.requestOutput( name, options )` — `'gBuffer'` (the normal/depth and albedo a denoiser reads; the
1498
+ viewer asks for it itself) or `'hitDistance'`. Each is compiled into the path tracer only while asked for.
1499
+
1299
1500
  ### All Exports
1300
1501
 
1301
1502
  ```js
1302
- // Core
1503
+ // The full engine (it also exports RayzeeRenderer)
1303
1504
  import { PathTracerApp, EngineEvents, LEGACY_EVENT_NAMES } from 'rayzee';
1304
1505
 
1506
+ // The renderer core and its add-ons (see Renderer core)
1507
+ import { RayzeeRenderer } from 'rayzee/core';
1508
+ import { PhysicalSky } from 'rayzee/addons/physical-sky';
1509
+ import { ArchiveImporter } from 'rayzee/addons/archives';
1510
+ import { BidirectionalIntegrator } from 'rayzee/addons/bidirectional';
1511
+ import { ColorManagement } from 'rayzee/addons/color';
1512
+ import { acquireSharedStorage } from 'rayzee/addons/storage';
1513
+
1514
+ // Headless rendering (see Deterministic & Headless Rendering)
1515
+ import { renderHeadless, openHeadless, captureHeadless } from 'rayzee';
1516
+
1305
1517
  // Platform services for hosts without a browser (see Running in Node)
1306
1518
  import { configurePlatform, getPlatform } from 'rayzee';
1307
1519
  import { nodePlatform, NodeWorker } from 'rayzee/node';
@@ -1309,22 +1521,18 @@ import { nodePlatform, NodeWorker } from 'rayzee/node';
1309
1521
  // Configuration & presets
1310
1522
  import {
1311
1523
  ENGINE_DEFAULTS,
1524
+ DENOISER_DEFAULTS,
1525
+ AUTO_EXPOSURE_DEFAULTS,
1526
+ AUTO_FOCUS_DEFAULTS,
1312
1527
  ASVGF_QUALITY_PRESETS,
1313
- CAMERA_PRESETS,
1314
- CAMERA_RANGES,
1315
- SKY_PRESETS,
1528
+ SKY_DEFAULTS,
1316
1529
  DEFAULT_SUN_PATH,
1317
- AUTO_FOCUS_MODES,
1318
- AF_DEFAULTS,
1530
+ DEFAULT_VIEW,
1319
1531
  TRIANGLE_DATA_LAYOUT,
1320
1532
  BVH_LEAF_MARKERS,
1321
- TEXTURE_CONSTANTS,
1322
- DEFAULT_TEXTURE_MATRIX,
1323
- MEMORY_CONSTANTS,
1324
1533
  PRODUCTION_RENDER_CONFIG,
1325
1534
  INTERACTIVE_RENDER_CONFIG,
1326
1535
  MAX_RESERVABLE_RENDER_SIZE,
1327
- RENDER_PROFILES,
1328
1536
  MATERIAL_DEFAULTS,
1329
1537
  } from 'rayzee';
1330
1538
 
@@ -1426,7 +1634,7 @@ import { setBindingAudit, getBindingAuditFindings, clearBindingAuditFindings } f
1426
1634
  OIDN provides high-quality AI denoising. It runs automatically once the render converges (reaches
1427
1635
  `maxSamples`), and — in `'interactive'` mode — also on a cadence while the image is still
1428
1636
  accumulating, so a preview shows a clean picture as it refines instead of only at the end. See
1429
- [Continuous denoising](#continuous-denoising).
1637
+ [When the denoiser runs](#when-the-denoiser-runs).
1430
1638
 
1431
1639
  1. **Install the package**
1432
1640
 
@@ -0,0 +1,13 @@
1
+ //#region src/Color/ActiveColor.js
2
+ var e = "Linear Rec.709 (sRGB)", t = null;
3
+ function n() {
4
+ return t;
5
+ }
6
+ function r(e) {
7
+ t = e, e?._publishWorkingMatrix?.();
8
+ }
9
+ function i(e) {
10
+ t === null && (t = e);
11
+ }
12
+ //#endregion
13
+ export { r as i, i as n, n as r, e as t };