rayzee 5.10.2 → 6.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 +82 -22
- package/dist/assets/AIUpscalerWorker-AXN-lKWN.js +2 -0
- package/dist/assets/AIUpscalerWorker-AXN-lKWN.js.map +1 -0
- package/dist/rayzee.es.js +1299 -1843
- package/dist/rayzee.es.js.map +1 -1
- package/dist/rayzee.umd.js +50 -74
- package/dist/rayzee.umd.js.map +1 -1
- package/package.json +1 -4
- package/src/AssetConfig.js +56 -0
- package/src/EngineDefaults.js +5 -3
- package/src/EngineEvents.js +1 -0
- package/src/Passes/AIUpscaler.js +44 -22
- package/src/Passes/OIDNDenoiser.js +4 -104
- package/src/PathTracerApp.js +59 -63
- package/src/Processor/AssetLoader.js +5 -2
- package/src/Processor/TextureCreator.js +42 -15
- package/src/Processor/Workers/AIUpscalerWorker.js +21 -6
- package/src/Stages/ASVGF.js +6 -27
- package/src/Stages/AdaptiveSampling.js +10 -26
- package/src/Stages/PathTracer.js +4 -5
- package/src/TSL/BVHTraversal.js +2 -18
- package/src/TSL/Clearcoat.js +1 -2
- package/src/TSL/Common.js +0 -13
- package/src/TSL/EmissiveSampling.js +0 -16
- package/src/TSL/Environment.js +0 -7
- package/src/TSL/LightsDirect.js +3 -379
- package/src/TSL/LightsSampling.js +0 -171
- package/src/TSL/MaterialEvaluation.js +3 -103
- package/src/TSL/MaterialProperties.js +1 -56
- package/src/TSL/MaterialSampling.js +2 -284
- package/src/TSL/MaterialTransmission.js +0 -93
- package/src/TSL/Random.js +0 -23
- package/src/TSL/Struct.js +0 -21
- package/src/TSL/TextureSampling.js +0 -69
- package/src/index.js +5 -2
- package/src/managers/DenoisingManager.js +13 -5
- package/src/managers/OverlayManager.js +14 -2
- package/src/managers/VideoRenderManager.js +4 -4
- package/dist/assets/AIUpscalerWorker-D58dcMrY.js +0 -2
- package/dist/assets/AIUpscalerWorker-D58dcMrY.js.map +0 -1
- package/src/Processor/createRenderTargetHelper.js +0 -521
- package/src/TSL/RayIntersection.js +0 -162
- package/src/managers/helpers/StatsHelper.js +0 -45
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ A real-time WebGPU path tracing engine built on Three.js. Framework-agnostic —
|
|
|
8
8
|
npm install rayzee three
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
`three` (>=0.183.0) is a required peer dependency.
|
|
11
|
+
`three` (>=0.183.0) is a required peer dependency.
|
|
12
12
|
|
|
13
13
|
## Getting Started
|
|
14
14
|
|
|
@@ -66,7 +66,9 @@ npm install rayzee three
|
|
|
66
66
|
// Use namespaced APIs and direct methods
|
|
67
67
|
engine.cameraManager.switchCamera(0);
|
|
68
68
|
engine.lightManager.add('PointLight');
|
|
69
|
-
|
|
69
|
+
|
|
70
|
+
// Capture the current frame as a Blob (host handles save/upload)
|
|
71
|
+
const blob = await engine.screenshot();
|
|
70
72
|
```
|
|
71
73
|
|
|
72
74
|
4. **Run**
|
|
@@ -92,7 +94,6 @@ A single HTML file — no Node.js, no build step. Uses [ES module import maps](h
|
|
|
92
94
|
"three/tsl": "https://cdn.jsdelivr.net/npm/three@0.183.0/build/three.tsl.js",
|
|
93
95
|
"three/webgpu": "https://cdn.jsdelivr.net/npm/three@0.183.0/build/three.webgpu.js",
|
|
94
96
|
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.183.0/examples/jsm/",
|
|
95
|
-
"stats-gl": "https://cdn.jsdelivr.net/npm/stats-gl@4.0.2/dist/main.js",
|
|
96
97
|
"oidn-web": "https://cdn.jsdelivr.net/npm/oidn-web@0.3.5/dist/oidn.js",
|
|
97
98
|
"rayzee": "https://cdn.jsdelivr.net/npm/rayzee/dist/rayzee.es.js"
|
|
98
99
|
}
|
|
@@ -217,6 +218,41 @@ export default defineConfig({
|
|
|
217
218
|
|
|
218
219
|
## API Reference
|
|
219
220
|
|
|
221
|
+
### Configuring Assets (CDN URLs & cache namespace)
|
|
222
|
+
|
|
223
|
+
By default, the engine loads STBN blue-noise atlases, GLTF Draco/KTX2 decoders, OIDN denoiser weights, ONNX upscaler models, and the onnxruntime-web bundle from upstream CDNs. If you're self-hosting, embedding the engine alongside a different consumer of the same caches, or operating offline, override them **once before constructing `PathTracerApp`**:
|
|
224
|
+
|
|
225
|
+
```js
|
|
226
|
+
import { configureAssets } from 'rayzee';
|
|
227
|
+
|
|
228
|
+
configureAssets({
|
|
229
|
+
// STBN atlases (PNG, decoded as Float textures)
|
|
230
|
+
stbnScalarAtlas: '/assets/stbn_scalar_atlas.png',
|
|
231
|
+
stbnVec2Atlas: '/assets/stbn_vec2_atlas.png',
|
|
232
|
+
|
|
233
|
+
// onnxruntime-web (loaded by AI upscaler worker via dynamic import)
|
|
234
|
+
ortRuntimeUrl: '/ort/ort.webgpu.bundle.min.mjs',
|
|
235
|
+
ortWasmPaths: '/ort/',
|
|
236
|
+
|
|
237
|
+
// GLTFLoader extension decoders
|
|
238
|
+
dracoDecoderPath: '/draco/',
|
|
239
|
+
ktx2TranscoderPath: '/basis/',
|
|
240
|
+
|
|
241
|
+
// Denoiser & upscaler weights
|
|
242
|
+
oidnWeightsBaseUrl: '/oidn-tzas/',
|
|
243
|
+
upscalerModelBaseUrl: '/upscaler-onnx/',
|
|
244
|
+
|
|
245
|
+
// Prefix for engine-managed IndexedDB stores. Set to a unique value if multiple
|
|
246
|
+
// apps embed the engine on the same origin to avoid cache collisions.
|
|
247
|
+
cacheNamespace: 'my-app',
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
const engine = new PathTracerApp(canvas);
|
|
251
|
+
await engine.init();
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
All keys are optional — only what you pass is overridden. Call `getAssetConfig()` to read the current values.
|
|
255
|
+
|
|
220
256
|
### PathTracerApp
|
|
221
257
|
|
|
222
258
|
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.
|
|
@@ -229,8 +265,9 @@ const engine = new PathTracerApp(canvas, options?)
|
|
|
229
265
|
|---|---|---|
|
|
230
266
|
| `canvas` | `HTMLCanvasElement` | Rendering target |
|
|
231
267
|
| `options.autoResize` | `boolean` | Auto-resize on window resize (default: `true`) |
|
|
232
|
-
| `options.
|
|
233
|
-
|
|
268
|
+
| `options.container` | `HTMLElement` | Single DOM parent the engine mounts auxiliary elements into — HUD overlay (tile borders, helpers) and denoiser canvas. Defaults to `canvas.parentNode`. |
|
|
269
|
+
|
|
270
|
+
The engine creates and mounts everything it needs (denoiser canvas, tile/HUD overlay) into a single parent on `init()`. Performance HUDs (e.g. `stats-gl`) are not bundled — listen to `EngineEvents.FRAME` and tick your own panel.
|
|
234
271
|
|
|
235
272
|
#### Lifecycle
|
|
236
273
|
|
|
@@ -296,11 +333,12 @@ See `ENGINE_DEFAULTS` for the full list with default values.
|
|
|
296
333
|
#### Rendering Modes
|
|
297
334
|
|
|
298
335
|
```js
|
|
299
|
-
engine.configureForMode('
|
|
300
|
-
engine.configureForMode('
|
|
301
|
-
engine.configureForMode('results') // Paused rendering for image viewing
|
|
336
|
+
engine.configureForMode('production') // High quality (tiled, 20 bounces, OIDN, controls disabled)
|
|
337
|
+
engine.configureForMode('interactive') // Real-time navigation (3 bounces, controls enabled)
|
|
302
338
|
```
|
|
303
339
|
|
|
340
|
+
To pause rendering for image-viewing UI, set `engine.pauseRendering = true` and disable camera controls directly — the engine doesn't model viewport visibility.
|
|
341
|
+
|
|
304
342
|
---
|
|
305
343
|
|
|
306
344
|
### engine.cameraManager
|
|
@@ -355,10 +393,17 @@ engine.reset() // Re-upload all material data to GPU
|
|
|
355
393
|
engine.stages.pathTracer.materialData.updateMaterial(index, mat) // Replace a material
|
|
356
394
|
await engine.rebuildMaterials(scene) // Full rebuild (after texture changes)
|
|
357
395
|
|
|
358
|
-
// Per-mesh visibility (
|
|
359
|
-
|
|
360
|
-
engine.
|
|
361
|
-
|
|
396
|
+
// Per-mesh visibility — recommended UUID-based API (handles lookup + sync internally)
|
|
397
|
+
engine.setMeshVisibilityByUuid(uuid, true) // explicit set
|
|
398
|
+
engine.setMeshVisibilityByUuid(uuid, prev => !prev) // toggle via updater fn
|
|
399
|
+
// Returns the new visibility state, or null if the mesh wasn't found.
|
|
400
|
+
|
|
401
|
+
// Lower-level — for callers that already have a meshIndex or have mutated object.visible directly
|
|
402
|
+
engine.setMeshVisibility(meshIndex, visible)
|
|
403
|
+
engine.updateAllMeshVisibility() // re-sync after manual object.visible mutations
|
|
404
|
+
|
|
405
|
+
// Read access to the active scene (returns the mesh-bearing scene)
|
|
406
|
+
engine.getScene()
|
|
362
407
|
```
|
|
363
408
|
|
|
364
409
|
### engine.environmentManager
|
|
@@ -432,13 +477,24 @@ engine.transformManager.controls // Access the underlying TransformC
|
|
|
432
477
|
Canvas output, screenshots, and scene statistics — accessed as direct methods on the engine.
|
|
433
478
|
|
|
434
479
|
```js
|
|
435
|
-
engine.getCanvas()
|
|
436
|
-
engine.screenshot()
|
|
437
|
-
engine.
|
|
438
|
-
engine.
|
|
439
|
-
engine.
|
|
440
|
-
engine.
|
|
441
|
-
engine.
|
|
480
|
+
engine.getCanvas() // Get the canvas with the final rendered image
|
|
481
|
+
const blob = await engine.screenshot() // Capture frame as Blob (default 'image/png')
|
|
482
|
+
const jpg = await engine.screenshot({ type: 'image/jpeg', quality: 0.9 })
|
|
483
|
+
engine.getStatistics() // Triangle count, mesh count, etc.
|
|
484
|
+
engine.setCanvasSize(1920, 1080) // Set explicit canvas dimensions
|
|
485
|
+
engine.onResize() // Trigger manual resize recalculation
|
|
486
|
+
engine.isComplete() // Check if rendering has converged
|
|
487
|
+
engine.getFrameCount() // Get the current accumulated frame count
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
`screenshot()` returns a `Blob` for the host to save, upload, or display. To trigger a browser download:
|
|
491
|
+
|
|
492
|
+
```js
|
|
493
|
+
const blob = await engine.screenshot();
|
|
494
|
+
const url = URL.createObjectURL(blob);
|
|
495
|
+
const a = Object.assign(document.createElement('a'), { href: url, download: 'render.png' });
|
|
496
|
+
a.click();
|
|
497
|
+
URL.revokeObjectURL(url);
|
|
442
498
|
```
|
|
443
499
|
|
|
444
500
|
---
|
|
@@ -459,6 +515,7 @@ engine.addEventListener(EngineEvents.RENDER_COMPLETE, (e) => {
|
|
|
459
515
|
|---|---|
|
|
460
516
|
| `RENDER_COMPLETE` | Rendering has converged |
|
|
461
517
|
| `RENDER_RESET` | Accumulation buffer is reset |
|
|
518
|
+
| `FRAME` | Fires once per `animate()` tick — hook external instrumentation (stats panels, telemetry) here |
|
|
462
519
|
| `DENOISING_START` / `DENOISING_END` | Denoiser runs |
|
|
463
520
|
| `UPSCALING_START` / `UPSCALING_PROGRESS` / `UPSCALING_END` | AI upscaler runs |
|
|
464
521
|
| `LOADING_UPDATE` / `LOADING_RESET` | Asset loading progress |
|
|
@@ -516,10 +573,13 @@ import {
|
|
|
516
573
|
TEXTURE_CONSTANTS,
|
|
517
574
|
DEFAULT_TEXTURE_MATRIX,
|
|
518
575
|
MEMORY_CONSTANTS,
|
|
519
|
-
|
|
520
|
-
|
|
576
|
+
PRODUCTION_RENDER_CONFIG,
|
|
577
|
+
INTERACTIVE_RENDER_CONFIG,
|
|
521
578
|
} from 'rayzee';
|
|
522
579
|
|
|
580
|
+
// Asset URL / cache namespace overrides
|
|
581
|
+
import { configureAssets, getAssetConfig } from 'rayzee';
|
|
582
|
+
|
|
523
583
|
// Advanced: managers & pipeline
|
|
524
584
|
import {
|
|
525
585
|
RenderSettings,
|
|
@@ -585,7 +645,7 @@ OIDN provides high-quality AI denoising for final renders. It runs automatically
|
|
|
585
645
|
| `'balance'` | ~50 MB | Moderate | General use (default) |
|
|
586
646
|
| `'high'` | ~100 MB | Slowest | Final quality renders |
|
|
587
647
|
|
|
588
|
-
> **Note:** The neural network model is downloaded on first use. Subsequent runs use the browser cache. OIDN also works with `configureForMode('
|
|
648
|
+
> **Note:** The neural network model is downloaded on first use. Subsequent runs use the browser cache. OIDN also works with `configureForMode('production')`, which enables it automatically alongside high-quality render settings.
|
|
589
649
|
|
|
590
650
|
### Enabling the AI Upscaler
|
|
591
651
|
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
(function(){let e={ortRuntimeUrl:`https://cdn.jsdelivr.net/npm/onnxruntime-web@1.24.3/dist/ort.webgpu.bundle.min.mjs`,ortWasmPaths:`https://cdn.jsdelivr.net/npm/onnxruntime-web@1.24.3/dist/`,cacheNamespace:`rayzee`},t=null;async function n(){return t||(t=await import(e.ortRuntimeUrl),t.env.wasm.wasmPaths=e.ortWasmPaths,t.env.logLevel=`error`,t)}function r(){return`${e.cacheNamespace}:ai-upscaler-models`}let i=`models`,a=null,o=null;function s(){return new Promise((e,t)=>{let n=indexedDB.open(r(),1);n.onupgradeneeded=()=>n.result.createObjectStore(i),n.onsuccess=()=>e(n.result),n.onerror=()=>t(n.error)})}async function c(e){try{let t=await s();return await new Promise((n,r)=>{let a=t.transaction(i,`readonly`).objectStore(i).get(e);a.onsuccess=()=>n(a.result||null),a.onerror=()=>r(a.error)})}catch{return null}}async function l(e,t){try{let n=await s();await new Promise((r,a)=>{let o=n.transaction(i,`readwrite`);o.objectStore(i).put(t,e),o.oncomplete=()=>r(),o.onerror=()=>a(o.error)})}catch{}}async function u(e){let t=await c(e);if(t)return console.log(`AI Upscaler Worker: model loaded from cache (${(t.byteLength/1024/1024).toFixed(1)}MB)`),t;let n=await fetch(e);if(!n.ok)throw Error(`Failed to fetch model: ${n.status}`);let r=await n.arrayBuffer();return l(e,r.slice(0)),r}async function d(e,t){if(a&&o===e){self.postMessage({type:`loaded`,backend:`webgpu`});return}a&&=(await a.release(),null);let[r,i]=await Promise.all([u(e),n()]);a=await i.InferenceSession.create(r,t),o=e;let s=512;try{let e=await navigator.gpu?.requestAdapter(),t=await e?.requestAdapterInfo?.()||e?.info,n=/apple|swiftshader|llvmpipe/i.test(t?.vendor||``)||/apple|swiftshader/i.test(t?.architecture||``),r=t?.device?.toLowerCase?.()?.includes(`integrated`)||/intel.*iris|intel.*uhd|intel.*hd|amd.*vega|radeon.*graphics/i.test(t?.description||``);s=n?128:r?256:512,console.log(`AI Upscaler Worker: GPU="${t?.description||t?.device||`unknown`}", tileSize=${s}`)}catch{}let c=(r.byteLength/1024/1024).toFixed(1);console.log(`AI Upscaler Worker: model loaded (${c}MB), backend: webgpu`),self.postMessage({type:`loaded`,backend:`webgpu`,tileSize:s})}async function f(e,t,r,i){let o=await n(),s=a.inputNames[0],c=a.outputNames[0],l=new o.Tensor(`float32`,e,[1,3,r,t]),u=(await a.run({[s]:l}))[c].data;self.postMessage({type:`inferred`,outputData:u,id:i},[u.buffer])}self.onmessage=async t=>{let{type:n}=t.data;try{n===`load`?(t.data.ortRuntimeUrl&&(e.ortRuntimeUrl=t.data.ortRuntimeUrl),t.data.ortWasmPaths&&(e.ortWasmPaths=t.data.ortWasmPaths),t.data.cacheNamespace&&(e.cacheNamespace=t.data.cacheNamespace),await d(t.data.url,t.data.sessionOptions)):n===`infer`?await f(t.data.tileData,t.data.width,t.data.height,t.data.id):n===`dispose`&&a&&(await a.release(),a=null,o=null)}catch(e){self.postMessage({type:`error`,message:e.message,id:t.data?.id})}}})();
|
|
2
|
+
//# sourceMappingURL=AIUpscalerWorker-AXN-lKWN.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AIUpscalerWorker-AXN-lKWN.js","names":[],"sources":["../../src/Processor/Workers/AIUpscalerWorker.js"],"sourcesContent":["/**\n * Web Worker for AI Upscaler inference.\n * Handles ONNX model loading and tile-based inference off the main thread.\n *\n * Messages:\n * Main → Worker:\n * { type: 'load', url, sessionOptions } — load/switch model\n * { type: 'infer', tileData, width, height, id } — run inference on a tile\n * { type: 'dispose' } — release session\n *\n * Worker → Main:\n * { type: 'loaded', backend }\n * { type: 'inferred', outputData, id }\n * { type: 'error', message, id? }\n */\n\n// Asset config supplied via 'load' message from the main thread.\n// Defaults match the upstream Rayzee deployment; override via configureAssets().\nlet _assetConfig = {\n\tortRuntimeUrl: 'https://cdn.jsdelivr.net/npm/onnxruntime-web@1.24.3/dist/ort.webgpu.bundle.min.mjs',\n\tortWasmPaths: 'https://cdn.jsdelivr.net/npm/onnxruntime-web@1.24.3/dist/',\n\tcacheNamespace: 'rayzee',\n};\n\nlet ort = null;\n\nasync function getOrt() {\n\n\tif ( ort ) return ort;\n\n\tort = await import( /* @vite-ignore */ _assetConfig.ortRuntimeUrl );\n\n\t// WASM paths for CDN delivery — WebGPU EP still uses WASM for lightweight shape ops\n\tort.env.wasm.wasmPaths = _assetConfig.ortWasmPaths;\n\tort.env.logLevel = 'error';\n\n\treturn ort;\n\n}\n\n// IndexedDB names are namespaced so multiple consumers on the same origin don't collide.\nfunction getIdbName() {\n\n\treturn `${_assetConfig.cacheNamespace}:ai-upscaler-models`;\n\n}\n\nconst IDB_STORE = 'models';\n\nlet session = null;\nlet currentModelUrl = null;\n\n// ─── IndexedDB Model Cache ───────────────────────────────────────────────────\n\nfunction openDB() {\n\n\treturn new Promise( ( resolve, reject ) => {\n\n\t\tconst req = indexedDB.open( getIdbName(), 1 );\n\t\treq.onupgradeneeded = () => req.result.createObjectStore( IDB_STORE );\n\t\treq.onsuccess = () => resolve( req.result );\n\t\treq.onerror = () => reject( req.error );\n\n\t} );\n\n}\n\nasync function getCachedModel( url ) {\n\n\ttry {\n\n\t\tconst db = await openDB();\n\t\treturn await new Promise( ( resolve, reject ) => {\n\n\t\t\tconst tx = db.transaction( IDB_STORE, 'readonly' );\n\t\t\tconst req = tx.objectStore( IDB_STORE ).get( url );\n\t\t\treq.onsuccess = () => resolve( req.result || null );\n\t\t\treq.onerror = () => reject( req.error );\n\n\t\t} );\n\n\t} catch {\n\n\t\treturn null;\n\n\t}\n\n}\n\nasync function cacheModel( url, buffer ) {\n\n\ttry {\n\n\t\tconst db = await openDB();\n\t\tawait new Promise( ( resolve, reject ) => {\n\n\t\t\tconst tx = db.transaction( IDB_STORE, 'readwrite' );\n\t\t\ttx.objectStore( IDB_STORE ).put( buffer, url );\n\t\t\ttx.oncomplete = () => resolve();\n\t\t\ttx.onerror = () => reject( tx.error );\n\n\t\t} );\n\n\t} catch {\n\n\t\t// Cache write failure is non-fatal\n\t}\n\n}\n\n// ─── Model Loading ───────────────────────────────────────────────────────────\n\nasync function fetchModel( url ) {\n\n\t// Try IndexedDB cache first\n\tconst cached = await getCachedModel( url );\n\tif ( cached ) {\n\n\t\tconsole.log( `AI Upscaler Worker: model loaded from cache (${( cached.byteLength / 1024 / 1024 ).toFixed( 1 )}MB)` );\n\t\treturn cached;\n\n\t}\n\n\t// Network fetch + cache\n\tconst response = await fetch( url );\n\tif ( ! response.ok ) throw new Error( `Failed to fetch model: ${response.status}` );\n\tconst buffer = await response.arrayBuffer();\n\n\t// Cache in background (don't block session creation)\n\tcacheModel( url, buffer.slice( 0 ) );\n\n\treturn buffer;\n\n}\n\nasync function loadModel( url, sessionOptions ) {\n\n\tif ( session && currentModelUrl === url ) {\n\n\t\tconst backend = 'webgpu';\n\t\tself.postMessage( { type: 'loaded', backend } );\n\t\treturn;\n\n\t}\n\n\t// Dispose previous session\n\tif ( session ) {\n\n\t\tawait session.release();\n\t\tsession = null;\n\n\t}\n\n\tconst [ modelBuffer, ortLib ] = await Promise.all( [ fetchModel( url ), getOrt() ] );\n\n\tsession = await ortLib.InferenceSession.create( modelBuffer, sessionOptions );\n\tcurrentModelUrl = url;\n\n\t// Detect GPU and recommend tile size based on device type\n\tlet tileSize = 512; // default\n\ttry {\n\n\t\tconst adapter = await navigator.gpu?.requestAdapter();\n\t\tconst info = await adapter?.requestAdapterInfo?.() || adapter?.info;\n\t\tconst isMobile = /apple|swiftshader|llvmpipe/i.test( info?.vendor || '' )\n\t\t\t|| /apple|swiftshader/i.test( info?.architecture || '' );\n\t\tconst isIntegrated = info?.device?.toLowerCase?.()?.includes( 'integrated' )\n\t\t\t|| /intel.*iris|intel.*uhd|intel.*hd|amd.*vega|radeon.*graphics/i.test( info?.description || '' );\n\n\t\tif ( isMobile ) {\n\n\t\t\ttileSize = 128;\n\n\t\t} else if ( isIntegrated ) {\n\n\t\t\ttileSize = 256;\n\n\t\t} else {\n\n\t\t\ttileSize = 512;\n\n\t\t}\n\n\t\tconsole.log( `AI Upscaler Worker: GPU=\"${info?.description || info?.device || 'unknown'}\", tileSize=${tileSize}` );\n\n\t} catch { /* fallback to default */ }\n\n\tconst sizeMB = ( modelBuffer.byteLength / 1024 / 1024 ).toFixed( 1 );\n\tconsole.log( `AI Upscaler Worker: model loaded (${sizeMB}MB), backend: webgpu` );\n\n\tself.postMessage( { type: 'loaded', backend: 'webgpu', tileSize } );\n\n}\n\nasync function inferTile( tileData, width, height, id ) {\n\n\tconst ortLib = await getOrt();\n\tconst inputName = session.inputNames[ 0 ];\n\tconst outputName = session.outputNames[ 0 ];\n\tconst inputTensor = new ortLib.Tensor( 'float32', tileData, [ 1, 3, height, width ] );\n\n\tconst results = await session.run( { [ inputName ]: inputTensor } );\n\tconst outputData = results[ outputName ].data;\n\n\t// Transfer the output buffer (zero-copy)\n\tself.postMessage( { type: 'inferred', outputData, id }, [ outputData.buffer ] );\n\n}\n\nself.onmessage = async ( e ) => {\n\n\tconst { type } = e.data;\n\n\ttry {\n\n\t\tif ( type === 'load' ) {\n\n\t\t\t// Apply asset overrides from main thread before any network or cache access\n\t\t\tif ( e.data.ortRuntimeUrl ) _assetConfig.ortRuntimeUrl = e.data.ortRuntimeUrl;\n\t\t\tif ( e.data.ortWasmPaths ) _assetConfig.ortWasmPaths = e.data.ortWasmPaths;\n\t\t\tif ( e.data.cacheNamespace ) _assetConfig.cacheNamespace = e.data.cacheNamespace;\n\t\t\tawait loadModel( e.data.url, e.data.sessionOptions );\n\n\t\t} else if ( type === 'infer' ) {\n\n\t\t\tawait inferTile( e.data.tileData, e.data.width, e.data.height, e.data.id );\n\n\t\t} else if ( type === 'dispose' ) {\n\n\t\t\tif ( session ) {\n\n\t\t\t\tawait session.release();\n\t\t\t\tsession = null;\n\t\t\t\tcurrentModelUrl = null;\n\n\t\t\t}\n\n\t\t}\n\n\t} catch ( error ) {\n\n\t\tself.postMessage( { type: 'error', message: error.message, id: e.data?.id } );\n\n\t}\n\n};\n"],"mappings":"YAkBA,IAAI,EAAe,CAClB,cAAe,qFACf,aAAc,4DACd,eAAgB,SAChB,CAEG,EAAM,KAEV,eAAe,GAAS,CAUvB,OARK,IAEL,EAAM,MAAM,OAA2B,EAAa,eAGpD,EAAI,IAAI,KAAK,UAAY,EAAa,aACtC,EAAI,IAAI,SAAW,QAEZ,GAKR,SAAS,GAAa,CAErB,MAAO,GAAG,EAAa,eAAe,qBAIvC,IAAM,EAAY,SAEd,EAAU,KACV,EAAkB,KAItB,SAAS,GAAS,CAEjB,OAAO,IAAI,SAAW,EAAS,IAAY,CAE1C,IAAM,EAAM,UAAU,KAAM,GAAY,CAAE,EAAG,CAC7C,EAAI,oBAAwB,EAAI,OAAO,kBAAmB,EAAW,CACrE,EAAI,cAAkB,EAAS,EAAI,OAAQ,CAC3C,EAAI,YAAgB,EAAQ,EAAI,MAAO,EAErC,CAIJ,eAAe,EAAgB,EAAM,CAEpC,GAAI,CAEH,IAAM,EAAK,MAAM,GAAQ,CACzB,OAAO,MAAM,IAAI,SAAW,EAAS,IAAY,CAGhD,IAAM,EADK,EAAG,YAAa,EAAW,WAAY,CACnC,YAAa,EAAW,CAAC,IAAK,EAAK,CAClD,EAAI,cAAkB,EAAS,EAAI,QAAU,KAAM,CACnD,EAAI,YAAgB,EAAQ,EAAI,MAAO,EAErC,MAEI,CAEP,OAAO,MAMT,eAAe,EAAY,EAAK,EAAS,CAExC,GAAI,CAEH,IAAM,EAAK,MAAM,GAAQ,CACzB,MAAM,IAAI,SAAW,EAAS,IAAY,CAEzC,IAAM,EAAK,EAAG,YAAa,EAAW,YAAa,CACnD,EAAG,YAAa,EAAW,CAAC,IAAK,EAAQ,EAAK,CAC9C,EAAG,eAAmB,GAAS,CAC/B,EAAG,YAAgB,EAAQ,EAAG,MAAO,EAEnC,MAEI,GAST,eAAe,EAAY,EAAM,CAGhC,IAAM,EAAS,MAAM,EAAgB,EAAK,CAC1C,GAAK,EAGJ,OADA,QAAQ,IAAK,iDAAkD,EAAO,WAAa,KAAO,MAAO,QAAS,EAAG,CAAC,KAAM,CAC7G,EAKR,IAAM,EAAW,MAAM,MAAO,EAAK,CACnC,GAAK,CAAE,EAAS,GAAK,MAAU,MAAO,0BAA0B,EAAS,SAAU,CACnF,IAAM,EAAS,MAAM,EAAS,aAAa,CAK3C,OAFA,EAAY,EAAK,EAAO,MAAO,EAAG,CAAE,CAE7B,EAIR,eAAe,EAAW,EAAK,EAAiB,CAE/C,GAAK,GAAW,IAAoB,EAAM,CAGzC,KAAK,YAAa,CAAE,KAAM,SAAU,QADpB,SAC6B,CAAE,CAC/C,OAKD,AAGC,KADA,MAAM,EAAQ,SAAS,CACb,MAIX,GAAM,CAAE,EAAa,GAAW,MAAM,QAAQ,IAAK,CAAE,EAAY,EAAK,CAAE,GAAQ,CAAE,CAAE,CAEpF,EAAU,MAAM,EAAO,iBAAiB,OAAQ,EAAa,EAAgB,CAC7E,EAAkB,EAGlB,IAAI,EAAW,IACf,GAAI,CAEH,IAAM,EAAU,MAAM,UAAU,KAAK,gBAAgB,CAC/C,EAAO,MAAM,GAAS,sBAAsB,EAAI,GAAS,KACzD,EAAW,8BAA8B,KAAM,GAAM,QAAU,GAAI,EACrE,qBAAqB,KAAM,GAAM,cAAgB,GAAI,CACnD,EAAe,GAAM,QAAQ,eAAe,EAAE,SAAU,aAAc,EACxE,+DAA+D,KAAM,GAAM,aAAe,GAAI,CAElG,AAUC,EAVI,EAEO,IAEA,EAEA,IAIA,IAIZ,QAAQ,IAAK,4BAA4B,GAAM,aAAe,GAAM,QAAU,UAAU,cAAc,IAAY,MAE3G,EAER,IAAM,GAAW,EAAY,WAAa,KAAO,MAAO,QAAS,EAAG,CACpE,QAAQ,IAAK,qCAAqC,EAAO,sBAAuB,CAEhF,KAAK,YAAa,CAAE,KAAM,SAAU,QAAS,SAAU,WAAU,CAAE,CAIpE,eAAe,EAAW,EAAU,EAAO,EAAQ,EAAK,CAEvD,IAAM,EAAS,MAAM,GAAQ,CACvB,EAAY,EAAQ,WAAY,GAChC,EAAa,EAAQ,YAAa,GAClC,EAAc,IAAI,EAAO,OAAQ,UAAW,EAAU,CAAE,EAAG,EAAG,EAAQ,EAAO,CAAE,CAG/E,GADU,MAAM,EAAQ,IAAK,EAAI,GAAa,EAAa,CAAE,EACvC,GAAa,KAGzC,KAAK,YAAa,CAAE,KAAM,WAAY,aAAY,KAAI,CAAE,CAAE,EAAW,OAAQ,CAAE,CAIhF,KAAK,UAAY,KAAQ,IAAO,CAE/B,GAAM,CAAE,QAAS,EAAE,KAEnB,GAAI,CAEE,IAAS,QAGR,EAAE,KAAK,gBAAgB,EAAa,cAAgB,EAAE,KAAK,eAC3D,EAAE,KAAK,eAAe,EAAa,aAAe,EAAE,KAAK,cACzD,EAAE,KAAK,iBAAiB,EAAa,eAAiB,EAAE,KAAK,gBAClE,MAAM,EAAW,EAAE,KAAK,IAAK,EAAE,KAAK,eAAgB,EAEzC,IAAS,QAEpB,MAAM,EAAW,EAAE,KAAK,SAAU,EAAE,KAAK,MAAO,EAAE,KAAK,OAAQ,EAAE,KAAK,GAAI,CAE/D,IAAS,WAEf,IAEJ,MAAM,EAAQ,SAAS,CACvB,EAAU,KACV,EAAkB,YAMX,EAAQ,CAEjB,KAAK,YAAa,CAAE,KAAM,QAAS,QAAS,EAAM,QAAS,GAAI,EAAE,MAAM,GAAI,CAAE"}
|