rayzee 9.4.2 → 9.5.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 (144) hide show
  1. package/README.md +223 -21
  2. package/dist/ActiveColor-YvuQq44O.js +13 -0
  3. package/dist/ArchiveImporter-xuUJiklP.js +4301 -0
  4. package/dist/AssetConfig-DSEntE65.js +30 -0
  5. package/dist/BidirectionalIntegrator-C5PKjJoT.js +934 -0
  6. package/dist/ColorManagement-CheBCPaW.js +1488 -0
  7. package/dist/EngineDefaults-DH3bI5t-.js +844 -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-BnHghprG.js +97 -0
  12. package/dist/{NeuralRetouch-vkdXXyK2.js → NeuralRetouch-CW11yLZ_.js} +8 -6
  13. package/dist/{NeuralSuperRes-FVqRJKQV.js → NeuralSuperRes-BekaecYg.js} +55 -120
  14. package/dist/PathTracer-Ccl9KOuF.js +29729 -0
  15. package/dist/PhysicalSky-Dv2PMFGW.js +1219 -0
  16. package/dist/RayzeeRenderer-BQxnzCTD.js +3542 -0
  17. package/dist/SolarLimb-ken-JbDK.js +721 -0
  18. package/dist/ToneMapGPU-BHi5JzIq.js +177 -0
  19. package/dist/ViewTransforms-D0rTLBsX.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-BZw7TiDp.js +75 -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 +2266 -44079
  33. package/dist/rayzee.umd.js +485 -473
  34. package/dist/sceneCachePolicy-BmwYOYDu.js +183 -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/EngineDefaults.js +22 -8
  41. package/src/EngineEvents.js +2 -0
  42. package/src/EngineIssues.js +1 -0
  43. package/src/PathTracerApp.js +617 -4016
  44. package/src/Pipeline/PipelineContext.js +0 -4
  45. package/src/Platform.js +36 -0
  46. package/src/Processor/ArchiveCache.js +1 -1
  47. package/src/Processor/ArchiveImporter.js +1259 -0
  48. package/src/Processor/AssetLoader.js +322 -1746
  49. package/src/Processor/AtmosphereModel.js +1 -2
  50. package/src/Processor/BVHBuilder.js +4 -95
  51. package/src/Processor/EnvironmentExactTable.js +187 -0
  52. package/src/Processor/EquirectHDRInfo.js +30 -223
  53. package/src/Processor/FileFormats.js +116 -0
  54. package/src/Processor/GLTFDecoders.js +85 -0
  55. package/src/Processor/GLTFDiffuseTransmission.js +63 -0
  56. package/src/Processor/GeometryExtractor.js +12 -1
  57. package/src/Processor/IESParser.js +47 -35
  58. package/src/Processor/KernelManager.js +35 -2
  59. package/src/Processor/MaterialPacking.js +8 -7
  60. package/src/Processor/PBRT/PBRTMaterials.js +129 -41
  61. package/src/Processor/PBRT/PBRTParser.js +30 -17
  62. package/src/Processor/PBRT/PBRTSceneBuilder.js +548 -37
  63. package/src/Processor/PBRT/PBRTTextureBake.js +154 -0
  64. package/src/Processor/PBRT/PFM.js +59 -0
  65. package/src/Processor/PackedRayBuffer.js +116 -9
  66. package/src/Processor/ParallelBVHBuilder.js +3 -6
  67. package/src/Processor/PhysicalSky.js +5 -4
  68. package/src/Processor/PlatformImageLoader.js +50 -6
  69. package/src/Processor/QueueManager.js +12 -3
  70. package/src/Processor/ReinsertionOptimizer.js +2 -2
  71. package/src/Processor/SceneProcessor.js +15 -55
  72. package/src/Processor/ShaderBuilder.js +6 -16
  73. package/src/Processor/SolarLimb.js +3 -0
  74. package/src/Processor/TextureCreator.js +1 -1
  75. package/src/Processor/Workers/BVHSubtreeWorker.js +1 -34
  76. package/src/Processor/Workers/BVHWorker.js +5 -18
  77. package/src/Processor/Workers/CDFWorker.js +6 -183
  78. package/src/Processor/archiveFormats.js +7 -0
  79. package/src/Processor/utils.js +2 -1
  80. package/src/RayzeeRenderer.js +3902 -0
  81. package/src/RenderSettings.js +49 -41
  82. package/src/Stages/ASVGF.js +5 -7
  83. package/src/Stages/AutoExposure.js +3 -12
  84. package/src/Stages/Compositor.js +8 -23
  85. package/src/Stages/NRD.js +9 -2
  86. package/src/Stages/NormalDepth.js +9 -6
  87. package/src/Stages/PathTracer.js +254 -38
  88. package/src/Stages/PathTracerStage.js +11 -16
  89. package/src/Storage/BLASCache.js +1 -1
  90. package/src/Storage/CDFCache.js +18 -17
  91. package/src/Storage/DownloadCache.js +1 -1
  92. package/src/Storage/SceneGraphCodec.js +46 -3
  93. package/src/Storage/SpillStore.js +1 -1
  94. package/src/Storage/StorageManager.js +2 -4
  95. package/src/Storage/areas.js +4 -0
  96. package/src/TSL/BVHTraversal.js +62 -24
  97. package/src/TSL/Bidirectional.js +204 -0
  98. package/src/TSL/BidirectionalLamps.js +132 -0
  99. package/src/TSL/Clearcoat.js +15 -6
  100. package/src/TSL/Common.js +19 -14
  101. package/src/TSL/ConnectKernel.js +147 -0
  102. package/src/TSL/Debugger.js +1 -1
  103. package/src/TSL/Displacement.js +4 -3
  104. package/src/TSL/EmissiveSampling.js +64 -17
  105. package/src/TSL/Environment.js +77 -106
  106. package/src/TSL/EnvironmentCDF.js +85 -39
  107. package/src/TSL/ExtendKernel.js +8 -3
  108. package/src/TSL/FinalWriteKernel.js +4 -4
  109. package/src/TSL/GenerateKernel.js +18 -4
  110. package/src/TSL/HitFacet.js +35 -5
  111. package/src/TSL/LightBVHSampling.js +40 -9
  112. package/src/TSL/LightGenerateKernel.js +293 -0
  113. package/src/TSL/LightGuide.js +198 -0
  114. package/src/TSL/LightSplatKernel.js +165 -0
  115. package/src/TSL/LightsCore.js +13 -38
  116. package/src/TSL/LightsDirect.js +28 -29
  117. package/src/TSL/LightsIndirect.js +3 -1
  118. package/src/TSL/LightsSampling.js +90 -38
  119. package/src/TSL/MaterialEvaluation.js +113 -31
  120. package/src/TSL/MaterialProperties.js +44 -17
  121. package/src/TSL/MaterialTransmission.js +52 -47
  122. package/src/TSL/MergeKernel.js +218 -0
  123. package/src/TSL/PathTracerCore.js +65 -29
  124. package/src/TSL/Random.js +4 -0
  125. package/src/TSL/SceneResources.js +51 -0
  126. package/src/TSL/ShadeKernel.js +881 -103
  127. package/src/TSL/Struct.js +10 -0
  128. package/src/TSL/Sun.js +1 -1
  129. package/src/TSL/TextureSampling.js +65 -60
  130. package/src/addons/archives.js +14 -0
  131. package/src/addons/bidirectional.js +13 -0
  132. package/src/addons/color.js +32 -0
  133. package/src/addons/formats.js +16 -0
  134. package/src/addons/physicalSky.js +14 -0
  135. package/src/addons/storage.js +19 -0
  136. package/src/core.js +35 -0
  137. package/src/index.js +3 -1
  138. package/src/integrators/BidirectionalIntegrator.js +832 -0
  139. package/src/managers/EnvironmentManager.js +85 -33
  140. package/src/managers/MaterialDataManager.js +42 -0
  141. package/src/managers/UniformManager.js +0 -1
  142. package/dist/ToneMapGPU-DKQM1pMd.js +0 -552
  143. package/dist/rolldown-runtime-CAFD8bLK.js +0 -11
  144. 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?)
@@ -346,12 +351,15 @@ Constructing a new `PathTracerApp` on a canvas that already has an active instan
346
351
  #### Loading Assets
347
352
 
348
353
  ```js
349
- await engine.loadModel(url) // Load GLB/GLTF/FBX/OBJ/STL/PLY/DAE/3MF/USDZ/ZIP
354
+ await engine.loadModel(url) // Load a GLB/GLTF by URL
355
+ await engine.loadFile(fileOrUrl) // Any supported file: GLB/GLTF/FBX/OBJ/STL/PLY/DAE/3MF/USD/USDZ, archives, HDR/EXR
350
356
  await engine.loadObject3D(object3d, name?) // Load a Three.js Object3D directly (name is optional, defaults to 'object3d')
351
357
  await engine.loadEnvironment(url) // Load HDR/EXR environment map
352
358
  engine.cancelLoad() // Abort an in-flight download (network phase only; no-op once processing starts)
353
359
  ```
354
360
 
361
+ On `rayzee/core`, formats other than glTF and `.hdr` need the `rayzee/addons/formats` add-on — see [Add-ons](#add-ons).
362
+
355
363
  `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
364
 
357
365
  ```js
@@ -368,6 +376,8 @@ engine.setSceneObjectVisibility(id, visible) // Toggle visi
368
376
 
369
377
  ##### Loading part of a scene archive
370
378
 
379
+ On `rayzee/core`, archives and pbrt need the `rayzee/addons/archives` add-on — see [Renderer core](#renderer-core-rayzeecore).
380
+
371
381
  A pbrt-v4 scene archive (`.tar`, `.tar.gz`, `.zip`) is usually a root `.pbrt` file that includes one
372
382
  subtree per element, and the whole thing rarely fits in a browser tab — Moana is 29 GB unpacked.
373
383
  The archive can be inspected without retaining any of it, then loaded one element at a time:
@@ -437,6 +447,7 @@ Key settings:
437
447
  | `environmentRotation` | `number` | 0 | Environment Y-rotation (degrees); 0 shows the HDRI as authored, as Blender's unmapped world does |
438
448
  | `showBackground` | `boolean` | true | Show the environment as a visible backdrop for camera-miss rays (vs. a solid/transparent background) |
439
449
  | `samplingTechnique` | `number` | 2 | Sampler: `0` PCG, `1` scrambled Halton, `2` Owen-scrambled Sobol |
450
+ | `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
451
  | `fireflyThreshold` | `number` | 3.0 | Firefly clamping threshold |
441
452
  | `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
453
  | `transmissiveBounces` | `number` | 5 | Max bounces for transmissive materials |
@@ -451,7 +462,7 @@ Key settings:
451
462
  | `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
463
  | `transparentBackground` | `boolean` | false | Transparent canvas background |
453
464
  | `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 |
465
+ | `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
466
  | `renderMode` | `number` | 0 | Internal preview(0)/production(1) flag driving accumulation & ASVGF behavior — normally set via `configureForMode()`, not written directly |
456
467
  | `visMode` | `number` | 0 | Debug visualization mode (0 = off) |
457
468
  | `environmentMode` | `string` | 'hdri' | Sky mode: `'hdri'` \| `'procedural'` \| `'color'` — not routed through `engine.settings`; use `engine.environmentManager.setMode()` instead |
@@ -460,14 +471,14 @@ Key settings:
460
471
  | `panoramaLatRange` | `[number, number]` | `[-90, 90]` | Panorama latitude sweep, degrees, bottom→top |
461
472
  | `panoramaLevelHorizon` | `boolean` | true | Yaw-only panorama basis, so orbit pitch/roll can't tilt the horizon |
462
473
  | `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 |
474
+ | `noiseThreshold` | `number` | 0.1 | √-luminance-normalized per-pixel noise below which a pixel counts as converged (the production preset uses 0.02) |
464
475
  | `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 |
476
+ | `adaptiveStopFraction` | `number` | 0.90 | Fraction of pixels that must converge before the frame retires (the production preset uses 0.94) |
466
477
  | `usePixelFreeze` | `boolean` | true | Per-pixel freeze (Tier-2): skip individually-converged pixels via active-list compaction |
467
478
  | `pixelFreezeThreshold` | `number` | 0.02 | Relative-error threshold for a pixel to become a freeze candidate |
468
479
  | `pixelFreezeStability` | `number` | 8 | Consecutive candidate frames required before a pixel freezes |
469
480
 
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`.
481
+ 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`. On the core without the colour add-on, set `renderer.renderer.toneMapping`.
471
482
 
472
483
  #### Rendering Modes
473
484
 
@@ -480,6 +491,168 @@ To pause rendering for image-viewing UI, set `engine.pauseRendering = true` and
480
491
 
481
492
  ---
482
493
 
494
+ ### Renderer core (`rayzee/core`)
495
+
496
+ `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.
497
+
498
+ ```js
499
+ import { RayzeeRenderer } from 'rayzee/core';
500
+
501
+ const renderer = await new RayzeeRenderer(canvas).init();
502
+ await renderer.loadModel('/models/scene.glb');
503
+ renderer.camera.position.set(0, 2, 6); // the camera it renders from; reset() after moving it
504
+ renderer.camera.lookAt(0, 0, 0);
505
+ renderer.reset();
506
+ await renderer.renderFrames(256);
507
+ const image = await renderer.renderToBuffer({ colorSpace: 'srgb' });
508
+ renderer.dispose();
509
+ ```
510
+
511
+ Two runnable examples live in the repository: `rayzee/examples/core-node.mjs` (the core alone, in Node, writing a PNG)
512
+ and `rayzee/examples/core-browser/` (the core plus the physical sky, accumulating on a canvas).
513
+
514
+ #### Add-ons
515
+
516
+ Six capabilities install on the core explicitly. `PathTracerApp` installs all six itself, so nothing in this
517
+ section applies to it.
518
+
519
+ | Add-on | Import | Install | When | Without it |
520
+ |---|---|---|---|---|
521
+ | 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 |
522
+ | Physical sky | `PhysicalSky` from `rayzee/addons/physical-sky` | `renderer.environmentManager.setProceduralSky(PhysicalSky)` | after `init()` | `'procedural'` mode records `capability.missing` (throws under `strict`) |
523
+ | 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 |
524
+ | 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 |
525
+ | 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 |
526
+ | On-disk storage | `acquireSharedStorage` from `rayzee/addons/storage` | `renderer.setStorageOpener(acquireSharedStorage)` | **before** `init()` | downloads land in memory and nothing is cached between visits |
527
+
528
+ `init()` creates the asset loader, the environment manager and the path tracer stage, which is why four of them come
529
+ after it. Storage is opened during `init()`, so its opener has to be set first.
530
+
531
+ All six, in that order:
532
+
533
+ ```js
534
+ import { RayzeeRenderer, configureAssets } from 'rayzee/core';
535
+ import { acquireSharedStorage } from 'rayzee/addons/storage';
536
+ import { ColorManagement } from 'rayzee/addons/color';
537
+ import { ArchiveImporter } from 'rayzee/addons/archives';
538
+ import { PhysicalSky } from 'rayzee/addons/physical-sky';
539
+ import { BidirectionalIntegrator } from 'rayzee/addons/bidirectional';
540
+ import { allFormats } from 'rayzee/addons/formats';
541
+
542
+ configureAssets({ ocioRuntimeFactory: () => import('@bb-studio/ocio') });
543
+
544
+ const renderer = new RayzeeRenderer(canvas);
545
+ renderer.setStorageOpener(acquireSharedStorage); // before init()
546
+ renderer.setColorManagement(ColorManagement);
547
+ await renderer.init();
548
+ renderer.assetLoader.registerFormat(...allFormats);
549
+ renderer.assetLoader.setArchiveImporter(new ArchiveImporter(renderer.assetLoader));
550
+ renderer.environmentManager.setProceduralSky(PhysicalSky);
551
+ renderer.stages.pathTracer.registerIntegrator(['bidirectional', 'vcm'], pt => new BidirectionalIntegrator(pt));
552
+ ```
553
+
554
+ **Loading on first use.** The physical sky and the archive importer can be installed as loaders instead, so their code
555
+ is fetched only the first time the sky is baked or an archive is read — `PathTracerApp` does this. The archive loader
556
+ takes the formats it reads, which `rayzee/core` exports, so the loader recognises an archive before its code exists:
557
+
558
+ ```js
559
+ import { ARCHIVE_FORMATS } from 'rayzee/core';
560
+
561
+ renderer.environmentManager.setProceduralSkyLoader(() => import('rayzee/addons/physical-sky').then((m) => m.PhysicalSky));
562
+ renderer.assetLoader.setArchiveImporterLoader(
563
+ () => import('rayzee/addons/archives').then((m) => new m.ArchiveImporter(renderer.assetLoader)),
564
+ ARCHIVE_FORMATS,
565
+ );
566
+ ```
567
+
568
+ Colour, storage and the integrators have no loader: colour and storage are used at startup, and an integrator applies
569
+ the moment it is chosen (a lazy one would trace plain frames meanwhile and break reproducible renders).
570
+
571
+ **File formats.** The core reads glTF/GLB (Draco, KTX2 and meshopt decoders are fetched only for a file that uses
572
+ them), `.hdr` and LDR images. FBX, OBJ, STL, PLY, Collada, 3MF, USD/USDZ and EXR are formats to register — import only
573
+ those you read and a bundler leaves the rest out; each three.js loader is downloaded the first time its format is read:
574
+
575
+ ```js
576
+ import { objFormat, usdFormat, exrFormat } from 'rayzee/addons/formats';
577
+
578
+ renderer.assetLoader.registerFormat(objFormat, usdFormat, exrFormat);
579
+ await renderer.loadFile(objFile);
580
+ ```
581
+
582
+ A format of your own registers the same way. A model format's `parse` gets the file and resolves to the model; an
583
+ environment format's `createLoader` returns a three.js loader whose `loadAsync` resolves to a texture:
584
+
585
+ ```js
586
+ renderer.assetLoader.registerFormat({
587
+ name: 'Point cloud (XYZ)', label: 'XYZ', type: 'model', extensions: ['xyz'],
588
+ async parse(file, { filename }) {
589
+ return { model: buildPoints(await file.text(), filename) };
590
+ },
591
+ });
592
+ ```
593
+
594
+ **Physical sky**, for `environmentMode: 'procedural'`:
595
+
596
+ ```js
597
+ renderer.environmentManager.setProceduralSky(PhysicalSky);
598
+ await renderer.environmentManager.setMode('procedural');
599
+ ```
600
+
601
+ **Bidirectional path tracing and vertex merging**, for `integrator: 'bidirectional' | 'vcm'`:
602
+
603
+ ```js
604
+ renderer.stages.pathTracer.registerIntegrator(['bidirectional', 'vcm'], pt => new BidirectionalIntegrator(pt));
605
+ renderer.settings.set('integrator', 'bidirectional');
606
+ ```
607
+
608
+ Its controls are on the active integrator (the same on `PathTracerApp`):
609
+
610
+ ```js
611
+ const integrator = renderer.stages.pathTracer.activeIntegrator;
612
+ integrator.setMergeRadius(1); // 'vcm': gather radius in pixels
613
+ integrator.setMergeTrust(0.25); // 'vcm': how far merging is trusted against the other strategies
614
+ integrator.setLightGuiding(true); // learn where light paths from the sky and sun start
615
+ integrator.setBidirectionalStrategy('connect', { alone: true }); // keep one strategy, for verification
616
+ ```
617
+
618
+ **Scene archives** (`.zip`, `.tar`, `.tar.gz`) and the pbrt scenes in them:
619
+
620
+ ```js
621
+ renderer.assetLoader.setArchiveImporter(new ArchiveImporter(renderer.assetLoader));
622
+ await renderer.loadFile(archiveFile);
623
+ ```
624
+
625
+ **OpenColorIO colour management** — configs, their views and looks, working spaces and export spaces. The host supplies
626
+ the OCIO runtime (the engine never names the package). Without the add-on, pick a tone mapper on the three.js renderer
627
+ instead (`renderer.renderer.toneMapping = AgXToneMapping`):
628
+
629
+ ```js
630
+ configureAssets({ ocioRuntimeFactory: () => import('@bb-studio/ocio') });
631
+ renderer.setColorManagement(ColorManagement);
632
+ await renderer.loadColorConfig({ builtin: 'ocio://cg-config-v4.0.0_aces-v2.0_ocio-v2.5' });
633
+ ```
634
+
635
+ **On-disk storage** (the browser's origin private file system), for the download, environment and scene caches and
636
+ the `memorySpill` option. Asking for it without the add-on (`storage: 'auto'`) records a `capability.missing` warning;
637
+ `storage: false` turns it off either way:
638
+
639
+ ```js
640
+ const renderer = new RayzeeRenderer(canvas);
641
+ renderer.setStorageOpener(acquireSharedStorage);
642
+ await renderer.init();
643
+ ```
644
+
645
+ Several renderers, core or full, can live in one page; they share only the colour management and the on-disk storage,
646
+ which are page-wide.
647
+
648
+ Code of your own that adds a setting declares it on the renderer's settings, so it gets the same provenance, change
649
+ events and session saving as the built-in ones:
650
+
651
+ ```js
652
+ renderer.settings.define('myGlowStrength', { apply: (value) => glow.setStrength(value), reset: true });
653
+ renderer.settings.set('myGlowStrength', 2);
654
+ ```
655
+
483
656
  ### engine.cameraManager
484
657
 
485
658
  Camera switching, auto-focus, DOF, and direct Three.js access.
@@ -641,6 +814,8 @@ A property a three.js material lacks falls back to `MATERIAL_DEFAULTS` (exported
641
814
 
642
815
  ### Colour Management
643
816
 
817
+ On `rayzee/core` this is the `rayzee/addons/color` add-on — see [Renderer core](#renderer-core-rayzeecore).
818
+
644
819
  `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
820
 
646
821
  ```js
@@ -679,7 +854,7 @@ engine.environmentManager.texture // The loaded environment texture
679
854
  await engine.loadEnvironment(url) // Load HDR/EXR environment map (method on engine)
680
855
  await engine.environmentManager.setEnvironmentMap(tex) // Set a custom environment texture
681
856
  await engine.environmentManager.setMode(mode) // 'hdri' | 'procedural' | 'color'
682
- await engine.environmentManager.generateProcedural() // Physical sky: spectral, multiple scattering, analytic sun
857
+ await engine.environmentManager.generateProcedural() // Physical sky: spectral, multiple scattering, analytic sun (core: needs rayzee/addons/physical-sky)
683
858
  await engine.environmentManager.generateSolid() // Solid color sky
684
859
  engine.environmentManager.markDirty() // Flag environment for GPU re-upload
685
860
  ```
@@ -707,15 +882,15 @@ Denoiser strategy, ASVGF, OIDN, upscaler, and auto-exposure.
707
882
 
708
883
  ```js
709
884
  // Strategy
710
- engine.denoisingManager.setStrategy('asvgf', 'medium') // 'none' | 'asvgf' | 'edgeaware'
885
+ engine.denoisingManager.setStrategy('asvgf', 'medium') // 'none' | 'asvgf' | 'nrd' | 'edgeaware' | 'oidn'
711
886
  engine.denoisingManager.denoiserStrategy // read back the active strategy (derived from stage state)
712
887
  engine.denoisingManager.setASVGFEnabled(true, 'medium')
713
888
  engine.denoisingManager.applyASVGFPreset('high') // 'low' | 'medium' | 'high'
714
889
  engine.denoisingManager.setAutoExposure(true)
715
890
 
716
891
  // Fine-grained parameters
717
- engine.denoisingManager.setASVGFParams({ temporalAlpha: 0.1, phiColor: 10 })
718
- engine.denoisingManager.setEdgeAwareParams({ pixelEdgeSharpness: 1.0 })
892
+ engine.denoisingManager.setASVGFParams({ temporalAlpha: 0.1, maxAccumFrames: 16 })
893
+ engine.denoisingManager.setEdgeAwareParams({ phiLuminance: 4.0, atrousIterations: 5 })
719
894
  engine.denoisingManager.setAutoExposureParams({ keyValue: 0.18 })
720
895
 
721
896
  // OIDN & Upscaler
@@ -726,7 +901,7 @@ engine.denoisingManager.setTemporalHistory(false) // live OIDN without th
726
901
  engine.denoisingManager.continuousDenoiseInterval = 250 // cap refreshes at 4/sec (default 8 = uncapped)
727
902
  engine.denoisingManager.setUpscalerEnabled(true)
728
903
  engine.denoisingManager.setUpscalerScaleFactor(2) // 2 or 4
729
- engine.denoisingManager.setUpscalerQuality('high') // ESRGAN only
904
+ engine.denoisingManager.setUpscalerQuality('quality') // 'fast' | 'balanced' | 'quality'
730
905
  ```
731
906
 
732
907
  ### engine.interactionManager
@@ -832,6 +1007,9 @@ surface** — pin a version and branch on the strings; they are never renamed or
832
1007
  | `output.source_fallback` | `renderToBuffer( { source: 'display' } )` found no denoised picture and returned the raw accumulation |
833
1008
  | `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
1009
  | `light.placeholder_skipped` | a `RectAreaLightPlaceholder` node lacked `userData.name` or `userData.type: 'RectAreaLight'`, so no light was made for it |
1010
+ | `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 |
1011
+ | `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 |
1012
+ | `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
1013
 
836
1014
  `asset.unreachable` also covers what the engine fetches for itself: OIDN weights, IES profiles and
837
1015
  gobos (`detail.asset` says which).
@@ -1101,7 +1279,9 @@ app.dispose();
1101
1279
  JPEG or WebP to RGBA8, straight alpha, top row first — since the engine carries no decoder. It decodes
1102
1280
  every glTF image, embedded or not, and JPEG/PNG skies. PNGs with bytes after `IEND`, which browsers
1103
1281
  accept and strict decoders refuse, are trimmed first; a texture that still fails is recorded as
1104
- `texture.build_failed` rather than dropped. Measured on a 91-texture model: `sharp` and
1282
+ `texture.build_failed` rather than dropped. Without `decodeImage`, each glTF image is recorded that way with what to
1283
+ configure (a strict host's load throws), and the model loads untextured. KTX2 (Basis) textures need no
1284
+ `decodeImage`: three's KTX2 loader decodes them, in a `NodeWorker` the engine lends it. Measured on a 91-texture model: `sharp` and
1105
1285
  `@napi-rs/canvas` (`await loadImage()`, then a 2D canvas) both decode in parallel, ~0.3 s against
1106
1286
  pngjs's 2.5 s serial. The canvas route premultiplies, which zeroes colour under alpha 0 and loses
1107
1287
  it under low alpha; `sharp` is exact. `jpeg-js` differs from libjpeg-turbo by up to 63 levels.
@@ -1115,8 +1295,9 @@ app.dispose();
1115
1295
  memory): on the main thread it held up the BVH workers, and a 1.9M-triangle, 91-texture model
1116
1296
  loaded in 4.1–4.9 s. It now loads in 2.1 s, against Chrome's 2.9 s on the same machine.
1117
1297
  - `nodePlatform()` also defines `ProgressEvent`, which three.js's `FileLoader` constructs while
1118
- streaming; that is the only global it sets. three.js's own Draco and KTX2 workers call the global
1119
- `Worker`, so a model using either also needs `globalThis.Worker = NodeWorker`.
1298
+ streaming; that is the only global it sets. three.js's own Draco and KTX2 loaders call the global
1299
+ `Worker`; the engine lends them `NodeWorker` for the length of each glTF parse, so a Draco or KTX2
1300
+ model loads with nothing set by the host.
1120
1301
 
1121
1302
  Measured on this bench's corpus: all 29 scenes match the Chrome goldens (`npm run bench:node`, RMSE
1122
1303
  ≤ 0.0036, no pixel over 0.02 — the readback's tone map accounts for most of it), and a textured glTF with an
@@ -1151,6 +1332,8 @@ list. Both need `timestamp-query`, and `getDenoiseProfile()` returns `null` when
1151
1332
 
1152
1333
  ### On-disk Storage (OPFS)
1153
1334
 
1335
+ On `rayzee/core`, storage needs the `rayzee/addons/storage` add-on (`setStorageOpener`) — see [Renderer core](#renderer-core-rayzeecore).
1336
+
1154
1337
  `engine.storage` is a `StorageManager` over the browser's origin private file system, or `null` where
1155
1338
  there is none (a private window, Node) — everything works without it, only slower. The engine keeps
1156
1339
  its caches there: downloads (models, skies, OIDN weights — revalidated at most daily with a 1-byte `Range` request, and served from the cache meanwhile),
@@ -1247,6 +1430,7 @@ engine.addEventListener(EngineEvents.RENDER_COMPLETE, (e) => {
1247
1430
  | Event | Fired when |
1248
1431
  |---|---|
1249
1432
  | `RENDER_COMPLETE` | Rendering has converged |
1433
+ | `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 |
1250
1434
  | `RENDER_RESET` | Accumulation buffer is reset |
1251
1435
  | `FRAME` | Fires once per `animate()` tick — hook external instrumentation (stats panels, telemetry) here |
1252
1436
  | `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 |
@@ -1300,12 +1484,30 @@ class MyCustomStage extends RenderStage {
1300
1484
  }
1301
1485
  ```
1302
1486
 
1487
+ To run between the path tracer and the compositor, subclass the renderer and return the stage from
1488
+ `_createExtraStages()` (call the parent's and add yours); for the compositor to show its picture, list
1489
+ `'my-stage:output'` in `_displaySources()`. `pipeline.addStage()` after `init()` appends after the
1490
+ compositor. A stage that needs an extra path-tracer output asks for it with
1491
+ `stages.pathTracer.requestOutput( name, options )` — `'gBuffer'` (the normal/depth and albedo a denoiser reads; the
1492
+ viewer asks for it itself) or `'hitDistance'`. Each is compiled into the path tracer only while asked for.
1493
+
1303
1494
  ### All Exports
1304
1495
 
1305
1496
  ```js
1306
- // Core
1497
+ // The full engine (it also exports RayzeeRenderer)
1307
1498
  import { PathTracerApp, EngineEvents, LEGACY_EVENT_NAMES } from 'rayzee';
1308
1499
 
1500
+ // The renderer core and its add-ons (see Renderer core)
1501
+ import { RayzeeRenderer } from 'rayzee/core';
1502
+ import { PhysicalSky } from 'rayzee/addons/physical-sky';
1503
+ import { ArchiveImporter } from 'rayzee/addons/archives';
1504
+ import { BidirectionalIntegrator } from 'rayzee/addons/bidirectional';
1505
+ import { ColorManagement } from 'rayzee/addons/color';
1506
+ import { acquireSharedStorage } from 'rayzee/addons/storage';
1507
+
1508
+ // Headless rendering (see Deterministic & Headless Rendering)
1509
+ import { renderHeadless, openHeadless, captureHeadless } from 'rayzee';
1510
+
1309
1511
  // Platform services for hosts without a browser (see Running in Node)
1310
1512
  import { configurePlatform, getPlatform } from 'rayzee';
1311
1513
  import { nodePlatform, NodeWorker } from 'rayzee/node';
@@ -1430,7 +1632,7 @@ import { setBindingAudit, getBindingAuditFindings, clearBindingAuditFindings } f
1430
1632
  OIDN provides high-quality AI denoising. It runs automatically once the render converges (reaches
1431
1633
  `maxSamples`), and — in `'interactive'` mode — also on a cadence while the image is still
1432
1634
  accumulating, so a preview shows a clean picture as it refines instead of only at the end. See
1433
- [Continuous denoising](#continuous-denoising).
1635
+ [When the denoiser runs](#when-the-denoiser-runs).
1434
1636
 
1435
1637
  1. **Install the package**
1436
1638
 
@@ -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 };