rayzee 8.8.2 → 9.0.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.
package/README.md CHANGED
@@ -22,9 +22,10 @@ A real-time WebGPU path tracing engine built on Three.js. Framework-agnostic —
22
22
  - [Configuring Assets (CDN URLs & cache namespace)](#configuring-assets-cdn-urls--cache-namespace)
23
23
  - [PathTracerApp](#pathtracerapp)
24
24
  - [engine.cameraManager](#enginecameramanager)
25
- - [Camera Projection (360° Panorama)](#camera-projection-360-panorama)
25
+ - [Camera Projection (Orthographic, 360° Panorama)](#camera-projection-orthographic-360-panorama)
26
26
  - [engine.lightManager](#enginelightmanager)
27
27
  - [engine.animationManager](#engineanimationmanager)
28
+ - [engine.timeline](#enginetimeline)
28
29
  - [Materials](#materials)
29
30
  - [Colour Management](#colour-management)
30
31
  - [engine.environmentManager](#engineenvironmentmanager)
@@ -428,16 +429,19 @@ Key settings:
428
429
  | `maxSubsurfaceSteps` | `number` | 8 | Max random-walk steps for subsurface scattering (raised to 64 by `configureForMode('production')`) |
429
430
  | `enableAlphaShadows` | `boolean` | false | Alpha-tested shadow rays (enabled by `configureForMode('production')`) |
430
431
  | `enableDOF` | `boolean` | false | Enable depth of field |
431
- | `focusDistance` | `number` | 0.8 | DOF focus distance |
432
- | `aperture` | `number` | 5.6 | DOF aperture (f-stop) |
433
- | `focalLength` | `number` | 50 | DOF focal length (mm) |
432
+ | `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'` |
433
+ | `dofBlur` | `number` | 0.05 | Look mode: how far a distant background blurs, as a fraction of the image height |
434
+ | `focusDistance` | `number` | 0.8 | DOF focus distance in scene units — depth along the view axis (the focal plane is flat) |
435
+ | `aperture` | `number` | 5.6 | Physical mode: f-stop |
436
+ | `focalLength` | `number` | 50 | Physical mode: focal length (mm) |
437
+ | `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 |
434
438
  | `transparentBackground` | `boolean` | false | Transparent canvas background |
435
439
  | `interactionModeEnabled` | `boolean` | true | Render at lower resolution while the camera moves, keeping the full bounce budget ("Fast Navigation" in the app) |
436
440
  | `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 |
437
441
  | `renderMode` | `number` | 0 | Internal preview(0)/production(1) flag driving accumulation & ASVGF behavior — normally set via `configureForMode()`, not written directly |
438
442
  | `visMode` | `number` | 0 | Debug visualization mode (0 = off) |
439
443
  | `environmentMode` | `string` | 'hdri' | Sky mode: `'hdri'` \| `'procedural'` \| `'gradient'` \| `'color'` — not routed through `engine.settings`; use `engine.environmentManager.setMode()` instead |
440
- | `cameraProjection` | `string` | 'perspective' | `'perspective'` \| `'equirectangular'` — see [Camera Projection](#camera-projection-360-panorama) |
444
+ | `cameraProjection` | `string` | 'perspective' | `'perspective'` \| `'orthographic'` \| `'equirectangular'` — see [Camera Projection](#camera-projection-orthographic-360-panorama) |
441
445
  | `panoramaLonRange` | `[number, number]` | `[-180, 180]` | Panorama longitude sweep, degrees, left→right |
442
446
  | `panoramaLatRange` | `[number, number]` | `[-90, 90]` | Panorama latitude sweep, degrees, bottom→top |
443
447
  | `panoramaLevelHorizon` | `boolean` | true | Yaw-only panorama basis, so orbit pitch/roll can't tilt the horizon |
@@ -467,21 +471,45 @@ To pause rendering for image-viewing UI, set `engine.pauseRendering = true` and
467
471
  Camera switching, auto-focus, DOF, and direct Three.js access.
468
472
 
469
473
  ```js
470
- engine.cameraManager.active // The active PerspectiveCamera
474
+ engine.cameraManager.active // The active camera: a PerspectiveCamera that can turn orthographic
471
475
  engine.cameraManager.controls // The OrbitControls instance
472
476
  engine.cameraManager.switchCamera(index) // Switch between scene cameras
473
477
  engine.cameraManager.getNames() // List available cameras
474
478
  engine.cameraManager.focusOn(center) // Focus orbit camera on a world-space point
475
479
  engine.cameraManager.setAutoFocusMode(mode) // 'auto' | 'manual'
476
480
  engine.cameraManager.setAFScreenPoint(x, y) // Set normalized AF screen point (0-1)
481
+ engine.cameraManager.setNavigationMode(mode) // 'orbit' | 'walk'
482
+ engine.cameraManager.walkControls.speed // Walk speed, scene units per second
483
+ engine.cameraManager.orthoHeight // Orthographic view height, scene units, wheel zoom included
484
+ engine.cameraManager.setOrthoHeight(height) // Set it
477
485
  ```
478
486
 
479
- ### Camera Projection (360° Panorama)
487
+ **Walk mode** is first-person navigation: drag to look, W A S D or the arrow keys to walk level, E and Q to
488
+ rise and sink, Shift faster, Alt slower. A new model resets `speed` so the walk crosses it in about eight
489
+ seconds. Keys are ignored while focus is in a text field, list or menu, and when a focused control has
490
+ already used the key. The mode obeys `controls.enabled`, so anything that locks the orbit camera locks walking
491
+ too. Switching back to `'orbit'` circles the surface at the centre of the view.
480
492
 
481
- Two camera models live behind the `cameraProjection` setting. Both branches are compiled into the same kernel, so switching writes a uniform and resets accumulation — it never recompiles WGSL.
493
+ ### Camera Projection (Orthographic, 360° Panorama)
494
+
495
+ Three camera models live behind the `cameraProjection` setting. All are compiled into the same kernel, so switching writes a uniform and resets accumulation — it never recompiles WGSL.
496
+
497
+ #### Orthographic
498
+
499
+ ```js
500
+ engine.settings.set('cameraProjection', 'orthographic');
501
+ engine.cameraManager.setOrthoHeight(12); // the view's height in scene units
502
+ engine.addEventListener(EngineEvents.ORTHO_HEIGHT_UPDATED, ({ height }) => {}); // the wheel changed it
503
+ ```
504
+
505
+ Rays are parallel and start on the camera's image plane, so nothing behind the camera is seen and nothing shrinks with distance. Switching keeps what the view shows at the orbit target: turning orthographic sizes the view from the orbit distance and field of view, and turning back moves the camera to match. The wheel then zooms by changing the view's size rather than moving the camera. A new model is framed the same way.
506
+
507
+ `engine.cameraManager.active` stays the same object — it switches its own projection and reports `isOrthographicCamera` — so picking, the transform gizmo and the overlays follow without anything being re-pointed. Imported orthographic cameras (glTF, and pbrt's `Camera "orthographic"`) switch the projection to orthographic at their own size, and a camera left orthographic comes back so; any other camera switches it back to perspective. Every denoiser, auto-focus and depth of field keep working. An environment at infinity is seen from a single direction, so the background is one colour.
508
+
509
+ #### 360° Panorama
482
510
 
483
511
  ```js
484
- engine.settings.set('cameraProjection', 'equirectangular'); // 'perspective' (default) | 'equirectangular'
512
+ engine.settings.set('cameraProjection', 'equirectangular');
485
513
 
486
514
  // Optional: crop the sweep. Degrees, [min, max].
487
515
  engine.settings.set('panoramaLonRange', [-90, 90]); // VR180
@@ -496,9 +524,9 @@ Depth of field still works: the lens plane is built from each ray's own frame, n
496
524
  Two features are incompatible with a non-frustum camera and the engine switches them off for you when panorama is enabled:
497
525
 
498
526
  - **ASVGF** falls back to the `edgeaware` denoiser — ASVGF's motion vectors unproject through the projection matrix, which is meaningless when every pixel is its own direction.
499
- - **Auto-focus** switches to `'manual'` — it raycasts via `Raycaster.setFromCamera`, which only understands a frustum.
527
+ - **Auto-focus** pauses and focus holds its last distance — it raycasts via `Raycaster.setFromCamera`, which only understands a frustum. It resumes when you leave the panorama.
500
528
 
501
- Read the outcome back rather than duplicating the rule (`engine.denoisingManager.denoiserStrategy`, `engine.cameraManager.autoFocusMode`). Neither is restored automatically when you switch back to `'perspective'`.
529
+ Read the denoiser outcome back rather than duplicating the rule (`engine.denoisingManager.denoiserStrategy`); it is not restored automatically when you leave the panorama.
502
530
 
503
531
  ### engine.lightManager
504
532
 
@@ -529,6 +557,34 @@ engine.animationManager.setLoop(true) // Enable/disable looping
529
557
  engine.animationManager.clips // Get available animation clips
530
558
  ```
531
559
 
560
+ ### engine.timeline
561
+
562
+ Authored animation: keyframed tracks on one time axis, in seconds. The camera's is the first track; the timeline is where lights and objects will join it. A model's own clips stay with `engine.animationManager`, and saved cameras (`engine.addCamera()`) stay cameras — a keyframe is not a camera.
563
+
564
+ ```js
565
+ const camera = engine.timeline.camera // the camera's track
566
+ const key = camera.addKey() // key the current view, 2 s after the last key
567
+ camera.addKey(5) // …or at a time
568
+ camera.updateKey(key.id) // give a key the current view
569
+ camera.setTime(key.id, 3.5) // retime it; keys stay in time order
570
+ camera.remove(key.id)
571
+ camera.keys // [{ id, time, position, target, fov, orthoHeight }]
572
+
573
+ engine.timeline.duration // seconds to the last key of any track
574
+ engine.timeline.animates // a track has two keys or more
575
+ engine.timeline.seek(2.5) // put the scene where the timeline has it at 2.5 s
576
+ await engine.timeline.play() // run it in the viewport, controls locked
577
+ engine.timeline.stop() // or stop early
578
+
579
+ // Keys changed ({ track: 'camera' }) or playback started or stopped ({ track: undefined })
580
+ engine.addEventListener(EngineEvents.TIMELINE_CHANGED, ({ track }) => {})
581
+
582
+ // A video of the move through a still scene; pass clipIndex too to move the camera during a clip
583
+ await new VideoRenderManager(engine).renderAnimation({ timeline: engine.timeline, fps: 30, onFrame });
584
+ ```
585
+
586
+ Between keys the camera glides along a smooth curve through their positions while looking along another through their targets, so a subject every key looks at stays in frame. It leaves the first key and reaches the last at rest, runs straight through the keys between, and holds still outside them. FOV, or an orthographic view's height, blends too, in the projection in use. The curves are three.js keyframe tracks (`InterpolateSmooth`). With auto-focus on, focus is measured again on every video frame, and the view is put back when the render ends. A new model clears the keys, as it clears saved cameras.
587
+
532
588
  ### Materials
533
589
 
534
590
  Material property updates and texture transforms — accessed as direct methods on the engine.
@@ -941,7 +997,8 @@ engine.addEventListener(EngineEvents.RENDER_COMPLETE, (e) => {
941
997
  | `TRANSFORM_MODE_CHANGED` | Gizmo mode changed |
942
998
  | `SELECT_MODE_CHANGED` | Selection mode toggled |
943
999
  | `SETTING_CHANGED` | A render setting is modified |
944
- | `AUTO_FOCUS_UPDATED` | Auto-focus recalculated |
1000
+ | `AUTO_FOCUS_UPDATED` | Auto-focus recalculated — `worldDistance` in scene units, `distance` divided by the model's size |
1001
+ | `ORTHO_HEIGHT_UPDATED` | An orthographic view's height changed — `height` in scene units |
945
1002
  | `AUTO_EXPOSURE_UPDATED` | Auto-exposure recalculated |
946
1003
  | `AF_POINT_PLACED` | Focus point placed on screen |
947
1004
  | `ANIMATION_STARTED` / `ANIMATION_PAUSED` / `ANIMATION_STOPPED` / `ANIMATION_FINISHED` | Animation lifecycle |
@@ -1024,6 +1081,8 @@ import {
1024
1081
  AnimationManager,
1025
1082
  TransformManager,
1026
1083
  VideoRenderManager,
1084
+ TimelineManager,
1085
+ CameraTrack,
1027
1086
  InteractionManager,
1028
1087
  RenderPipeline,
1029
1088
  RenderStage,
@@ -21,6 +21,7 @@ var i = {
21
21
  OBJECT_TRANSFORM_END: "engine:objectTransformEnd",
22
22
  TRANSFORM_MODE_CHANGED: "engine:transformModeChanged",
23
23
  AUTO_FOCUS_UPDATED: "engine:autoFocusUpdated",
24
+ ORTHO_HEIGHT_UPDATED: "engine:orthoHeightUpdated",
24
25
  AUTO_EXPOSURE_UPDATED: "engine:autoExposureUpdated",
25
26
  AF_POINT_PLACED: "engine:afPointPlaced",
26
27
  SETTING_CHANGED: "engine:settingChanged",
@@ -28,6 +29,7 @@ var i = {
28
29
  ANIMATION_PAUSED: "engine:animationPaused",
29
30
  ANIMATION_STOPPED: "engine:animationStopped",
30
31
  ANIMATION_FINISHED: "engine:animationFinished",
32
+ TIMELINE_CHANGED: "engine:timelineChanged",
31
33
  VIDEO_RENDER_PROGRESS: "engine:videoRenderProgress",
32
34
  VIDEO_RENDER_COMPLETE: "engine:videoRenderComplete",
33
35
  DISPOSE: "engine:dispose",