rayzee 7.27.1 → 7.28.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/dist/rayzee.es.js +3607 -3394
- package/dist/rayzee.umd.js +49 -49
- package/package.json +1 -1
- package/src/EngineDefaults.js +42 -3
- package/src/EngineEvents.js +6 -0
- package/src/EngineIssues.js +93 -0
- package/src/Headless.js +114 -0
- package/src/PathTracerApp.js +208 -21
- package/src/Pipeline/RenderPipeline.js +31 -4
- package/src/Processor/AssetLoader.js +25 -2
- package/src/Processor/SceneProcessor.js +2 -1
- package/src/Processor/TextureCreator.js +37 -95
- package/src/Processor/ToneMapCPU.js +39 -0
- package/src/RenderSettings.js +94 -25
- package/src/index.js +12 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { DataArrayTexture, RGBAFormat, LinearFilter, UnsignedByteType, SRGBColorSpace, RepeatWrapping } from "three";
|
|
2
2
|
import { TEXTURE_CONSTANTS, MEMORY_CONSTANTS, DEFAULT_TEXTURE_MATRIX, MATERIAL_DATA_LAYOUT, normalizeAttenuationDistance } from '../EngineDefaults.js';
|
|
3
3
|
import TexturesWorker from './Workers/TexturesWorker.js?worker&inline';
|
|
4
|
+
import { ISSUE_CODES } from '../EngineIssues.js';
|
|
4
5
|
|
|
5
6
|
// Canvas pooling for efficient reuse of canvas elements
|
|
6
7
|
class CanvasPool {
|
|
@@ -460,6 +461,8 @@ export class TextureCreator {
|
|
|
460
461
|
this.maxConcurrentWorkers = TEXTURE_CONSTANTS.MAX_CONCURRENT_WORKERS;
|
|
461
462
|
this.activeWorkers = 0;
|
|
462
463
|
|
|
464
|
+
this._issues = options.issues ?? null;
|
|
465
|
+
|
|
463
466
|
// Longest-edge cap for material-texture arrays. Clamped to the hardware ceiling.
|
|
464
467
|
this.maxTextureSize = this._clampTextureSize(
|
|
465
468
|
options.maxTextureSize ?? TEXTURE_CONSTANTS.DEFAULT_MAX_TEXTURE_SIZE
|
|
@@ -479,6 +482,17 @@ export class TextureCreator {
|
|
|
479
482
|
|
|
480
483
|
}
|
|
481
484
|
|
|
485
|
+
/** A failed map array leaves those surfaces untextured — complete-looking and wrong. @private */
|
|
486
|
+
_reportTextureFailure( map, error ) {
|
|
487
|
+
|
|
488
|
+
this._issues?.record(
|
|
489
|
+
ISSUE_CODES.TEXTURE_BUILD_FAILED,
|
|
490
|
+
`${map} texture array failed to build — those surfaces render untextured`,
|
|
491
|
+
{ map, cause: String( error?.message ?? error ) }
|
|
492
|
+
);
|
|
493
|
+
|
|
494
|
+
}
|
|
495
|
+
|
|
482
496
|
_clampTextureSize( size ) {
|
|
483
497
|
|
|
484
498
|
const n = Math.floor( Number( size ) || TEXTURE_CONSTANTS.DEFAULT_MAX_TEXTURE_SIZE );
|
|
@@ -573,7 +587,11 @@ export class TextureCreator {
|
|
|
573
587
|
|
|
574
588
|
} catch ( error ) {
|
|
575
589
|
|
|
576
|
-
|
|
590
|
+
this._issues?.warn(
|
|
591
|
+
ISSUE_CODES.TEXTURE_PROCESSING_FALLBACK,
|
|
592
|
+
'worker texture processing failed — retrying on the main thread',
|
|
593
|
+
{ cause: String( error?.message ?? error ) }
|
|
594
|
+
);
|
|
577
595
|
return await this.processOnMainThreadSync( normalized );
|
|
578
596
|
|
|
579
597
|
} finally {
|
|
@@ -1114,105 +1132,25 @@ export class TextureCreator {
|
|
|
1114
1132
|
// Create texture arrays
|
|
1115
1133
|
const texturePromises = [];
|
|
1116
1134
|
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
} )
|
|
1128
|
-
);
|
|
1129
|
-
|
|
1130
|
-
}
|
|
1131
|
-
|
|
1132
|
-
if ( normalMaps && normalMaps.length > 0 ) {
|
|
1133
|
-
|
|
1134
|
-
texturePromises.push(
|
|
1135
|
-
this.createTexturesToDataTexture( normalMaps )
|
|
1136
|
-
.then( tex => ( { type: 'normal', texture: tex } ) )
|
|
1137
|
-
.catch( error => {
|
|
1138
|
-
|
|
1139
|
-
console.warn( 'Failed to create normal textures:', error );
|
|
1140
|
-
return { type: 'normal', texture: null };
|
|
1141
|
-
|
|
1142
|
-
} )
|
|
1143
|
-
);
|
|
1144
|
-
|
|
1145
|
-
}
|
|
1146
|
-
|
|
1147
|
-
if ( bumpMaps && bumpMaps.length > 0 ) {
|
|
1148
|
-
|
|
1149
|
-
texturePromises.push(
|
|
1150
|
-
this.createTexturesToDataTexture( bumpMaps )
|
|
1151
|
-
.then( tex => ( { type: 'bump', texture: tex } ) )
|
|
1152
|
-
.catch( error => {
|
|
1153
|
-
|
|
1154
|
-
console.warn( 'Failed to create bump textures:', error );
|
|
1155
|
-
return { type: 'bump', texture: null };
|
|
1156
|
-
|
|
1157
|
-
} )
|
|
1158
|
-
);
|
|
1159
|
-
|
|
1160
|
-
}
|
|
1135
|
+
for ( const [ type, list ] of [
|
|
1136
|
+
[ 'albedo', maps ],
|
|
1137
|
+
[ 'normal', normalMaps ],
|
|
1138
|
+
[ 'bump', bumpMaps ],
|
|
1139
|
+
[ 'roughness', roughnessMaps ],
|
|
1140
|
+
[ 'metalness', metalnessMaps ],
|
|
1141
|
+
[ 'emissive', emissiveMaps ],
|
|
1142
|
+
[ 'displacement', displacementMaps ],
|
|
1143
|
+
] ) {
|
|
1161
1144
|
|
|
1162
|
-
|
|
1145
|
+
if ( ! list || list.length === 0 ) continue;
|
|
1163
1146
|
|
|
1164
1147
|
texturePromises.push(
|
|
1165
|
-
this.createTexturesToDataTexture(
|
|
1166
|
-
.then(
|
|
1148
|
+
this.createTexturesToDataTexture( list )
|
|
1149
|
+
.then( texture => ( { type, texture } ) )
|
|
1167
1150
|
.catch( error => {
|
|
1168
1151
|
|
|
1169
|
-
|
|
1170
|
-
return { type
|
|
1171
|
-
|
|
1172
|
-
} )
|
|
1173
|
-
);
|
|
1174
|
-
|
|
1175
|
-
}
|
|
1176
|
-
|
|
1177
|
-
if ( metalnessMaps && metalnessMaps.length > 0 ) {
|
|
1178
|
-
|
|
1179
|
-
texturePromises.push(
|
|
1180
|
-
this.createTexturesToDataTexture( metalnessMaps )
|
|
1181
|
-
.then( tex => ( { type: 'metalness', texture: tex } ) )
|
|
1182
|
-
.catch( error => {
|
|
1183
|
-
|
|
1184
|
-
console.warn( 'Failed to create metalness textures:', error );
|
|
1185
|
-
return { type: 'metalness', texture: null };
|
|
1186
|
-
|
|
1187
|
-
} )
|
|
1188
|
-
);
|
|
1189
|
-
|
|
1190
|
-
}
|
|
1191
|
-
|
|
1192
|
-
if ( emissiveMaps && emissiveMaps.length > 0 ) {
|
|
1193
|
-
|
|
1194
|
-
texturePromises.push(
|
|
1195
|
-
this.createTexturesToDataTexture( emissiveMaps )
|
|
1196
|
-
.then( tex => ( { type: 'emissive', texture: tex } ) )
|
|
1197
|
-
.catch( error => {
|
|
1198
|
-
|
|
1199
|
-
console.warn( 'Failed to create emissive textures:', error );
|
|
1200
|
-
return { type: 'emissive', texture: null };
|
|
1201
|
-
|
|
1202
|
-
} )
|
|
1203
|
-
);
|
|
1204
|
-
|
|
1205
|
-
}
|
|
1206
|
-
|
|
1207
|
-
if ( displacementMaps && displacementMaps.length > 0 ) {
|
|
1208
|
-
|
|
1209
|
-
texturePromises.push(
|
|
1210
|
-
this.createTexturesToDataTexture( displacementMaps )
|
|
1211
|
-
.then( tex => ( { type: 'displacement', texture: tex } ) )
|
|
1212
|
-
.catch( error => {
|
|
1213
|
-
|
|
1214
|
-
console.warn( 'Failed to create displacement textures:', error );
|
|
1215
|
-
return { type: 'displacement', texture: null };
|
|
1152
|
+
this._reportTextureFailure( type, error );
|
|
1153
|
+
return { type, texture: null };
|
|
1216
1154
|
|
|
1217
1155
|
} )
|
|
1218
1156
|
);
|
|
@@ -1222,6 +1160,10 @@ export class TextureCreator {
|
|
|
1222
1160
|
// Wait for all texture arrays to complete
|
|
1223
1161
|
const textureResults = await Promise.allSettled( texturePromises );
|
|
1224
1162
|
|
|
1163
|
+
// allSettled would otherwise swallow a strict host's EngineIssueError.
|
|
1164
|
+
const refused = textureResults.find( ( r ) => r.status === 'rejected' );
|
|
1165
|
+
if ( refused ) throw refused.reason;
|
|
1166
|
+
|
|
1225
1167
|
// Organize results
|
|
1226
1168
|
const textures = {};
|
|
1227
1169
|
|
|
@@ -214,3 +214,42 @@ export function applySaturation( out, saturation ) {
|
|
|
214
214
|
out[ 2 ] = luma + ( out[ 2 ] - luma ) * saturation;
|
|
215
215
|
|
|
216
216
|
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Linear float RGBA → sRGB bytes, in the output pass's order: exposure, saturation, curve,
|
|
220
|
+
* transfer function. Not interchangeable — moving any step shifts every mid-tone.
|
|
221
|
+
*
|
|
222
|
+
* @param {Float32Array} linear - RGBA, 4 floats per pixel
|
|
223
|
+
* @param {Object} options
|
|
224
|
+
* @param {number} options.exposure - renderer.toneMappingExposure, raw
|
|
225
|
+
* @param {number} options.toneMapping - Three.js ToneMapping constant
|
|
226
|
+
* @param {number} [options.saturation=1]
|
|
227
|
+
* @param {boolean} [options.preserveAlpha=false]
|
|
228
|
+
* @returns {Uint8ClampedArray} RGBA bytes
|
|
229
|
+
*/
|
|
230
|
+
export function toneMapToRGBA8( linear, { exposure, toneMapping, saturation = 1, preserveAlpha = false } ) {
|
|
231
|
+
|
|
232
|
+
const curve = TONE_MAP_FNS.get( toneMapping ) ?? TONE_MAP_FNS.get( NoToneMapping );
|
|
233
|
+
const gain = effectiveExposure( exposure, toneMapping );
|
|
234
|
+
const out = new Uint8ClampedArray( linear.length );
|
|
235
|
+
const scratch = [ 0, 0, 0 ];
|
|
236
|
+
|
|
237
|
+
for ( let i = 0; i < linear.length; i += 4 ) {
|
|
238
|
+
|
|
239
|
+
scratch[ 0 ] = linear[ i ] * gain;
|
|
240
|
+
scratch[ 1 ] = linear[ i + 1 ] * gain;
|
|
241
|
+
scratch[ 2 ] = linear[ i + 2 ] * gain;
|
|
242
|
+
|
|
243
|
+
applySaturation( scratch, saturation );
|
|
244
|
+
curve( scratch[ 0 ], scratch[ 1 ], scratch[ 2 ], 1.0, scratch );
|
|
245
|
+
|
|
246
|
+
out[ i ] = linearToSRGB( scratch[ 0 ] ) * 255 + 0.5;
|
|
247
|
+
out[ i + 1 ] = linearToSRGB( scratch[ 1 ] ) * 255 + 0.5;
|
|
248
|
+
out[ i + 2 ] = linearToSRGB( scratch[ 2 ] ) * 255 + 0.5;
|
|
249
|
+
out[ i + 3 ] = preserveAlpha ? linear[ i + 3 ] * 255 + 0.5 : 255;
|
|
250
|
+
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
return out;
|
|
254
|
+
|
|
255
|
+
}
|
package/src/RenderSettings.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { EventDispatcher, Color, Vector2, MathUtils } from 'three';
|
|
2
2
|
import { ENGINE_DEFAULTS } from './EngineDefaults.js';
|
|
3
3
|
import { EngineEvents } from './EngineEvents.js';
|
|
4
|
+
import { ISSUE_CODES } from './EngineIssues.js';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Routing table: maps each setting key to its target stage/handler.
|
|
@@ -78,6 +79,14 @@ const SETTING_ROUTES = {
|
|
|
78
79
|
* Default keys to extract from ENGINE_DEFAULTS for initializing the values map.
|
|
79
80
|
* Maps ENGINE_DEFAULTS key → RenderSettings key when they differ.
|
|
80
81
|
*/
|
|
82
|
+
/** Provenance tags for getEffective(). Add-only — hosts branch on them. */
|
|
83
|
+
export const SETTING_SOURCE = Object.freeze( {
|
|
84
|
+
DEFAULT: 'default',
|
|
85
|
+
HOST: 'host',
|
|
86
|
+
SCENE_METADATA: 'scene-metadata',
|
|
87
|
+
MODE_PRESET: 'mode-preset',
|
|
88
|
+
} );
|
|
89
|
+
|
|
81
90
|
const DEFAULTS_KEY_MAP = {
|
|
82
91
|
bounces: 'maxBounces',
|
|
83
92
|
debugMode: 'visMode',
|
|
@@ -96,13 +105,23 @@ const DEFAULTS_KEY_MAP = {
|
|
|
96
105
|
*/
|
|
97
106
|
export class RenderSettings extends EventDispatcher {
|
|
98
107
|
|
|
99
|
-
|
|
108
|
+
/**
|
|
109
|
+
* @param {Object} [defaults]
|
|
110
|
+
* @param {Object} [options]
|
|
111
|
+
* @param {import('./EngineIssues.js').IssueLog} [options.issues] - records unroutable keys
|
|
112
|
+
*/
|
|
113
|
+
constructor( defaults = ENGINE_DEFAULTS, { issues = null } = {} ) {
|
|
100
114
|
|
|
101
115
|
super();
|
|
102
116
|
|
|
117
|
+
this._issues = issues;
|
|
118
|
+
|
|
103
119
|
/** @type {Map<string, *>} */
|
|
104
120
|
this._values = new Map();
|
|
105
121
|
|
|
122
|
+
/** @type {Map<string, string>} - see getEffective() */
|
|
123
|
+
this._sources = new Map();
|
|
124
|
+
|
|
106
125
|
/** @type {import('./Stages/PathTracer.js').PathTracer|null} */
|
|
107
126
|
this._pathTracer = null;
|
|
108
127
|
|
|
@@ -272,24 +291,17 @@ export class RenderSettings extends EventDispatcher {
|
|
|
272
291
|
* @param {boolean} [options.reset] - Override the route's default reset behavior
|
|
273
292
|
* @param {boolean} [options.silent] - Suppress the settingChanged event
|
|
274
293
|
*/
|
|
275
|
-
set( key, value, { reset, silent } = {} ) {
|
|
294
|
+
set( key, value, { reset, silent, source = SETTING_SOURCE.HOST } = {} ) {
|
|
276
295
|
|
|
277
|
-
const
|
|
278
|
-
if (
|
|
279
|
-
|
|
280
|
-
this._values.set( key, value );
|
|
281
|
-
|
|
282
|
-
const route = SETTING_ROUTES[ key ];
|
|
283
|
-
if ( ! route ) return;
|
|
284
|
-
|
|
285
|
-
this._applyRoute( route, value, prev );
|
|
296
|
+
const applied = this._applyOne( key, value, source );
|
|
297
|
+
if ( ! applied?.route ) return;
|
|
286
298
|
|
|
287
|
-
const shouldReset = reset !== undefined ? reset : ( route.reset ?? true );
|
|
299
|
+
const shouldReset = reset !== undefined ? reset : ( applied.route.reset ?? true );
|
|
288
300
|
if ( shouldReset ) this._resetCallback?.();
|
|
289
301
|
|
|
290
302
|
if ( ! silent ) {
|
|
291
303
|
|
|
292
|
-
this.dispatchEvent( { type: EngineEvents.SETTING_CHANGED, key, value, prev } );
|
|
304
|
+
this.dispatchEvent( { type: EngineEvents.SETTING_CHANGED, key, value, prev: applied.prev } );
|
|
293
305
|
|
|
294
306
|
}
|
|
295
307
|
|
|
@@ -301,28 +313,22 @@ export class RenderSettings extends EventDispatcher {
|
|
|
301
313
|
* @param {Object} [options]
|
|
302
314
|
* @param {boolean} [options.silent] - Suppress settingChanged events
|
|
303
315
|
* @param {boolean} [options.reset] - Override the routes' default reset behavior
|
|
316
|
+
* @param {string} [options.source] - Provenance tag; see SETTING_SOURCE
|
|
304
317
|
*/
|
|
305
|
-
setMany( updates, { silent, reset } = {} ) {
|
|
318
|
+
setMany( updates, { silent, reset, source = SETTING_SOURCE.HOST } = {} ) {
|
|
306
319
|
|
|
307
320
|
let needsReset = false;
|
|
308
321
|
|
|
309
322
|
for ( const [ key, value ] of Object.entries( updates ) ) {
|
|
310
323
|
|
|
311
|
-
const
|
|
312
|
-
if (
|
|
324
|
+
const applied = this._applyOne( key, value, source );
|
|
325
|
+
if ( ! applied?.route ) continue;
|
|
313
326
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
const route = SETTING_ROUTES[ key ];
|
|
317
|
-
if ( ! route ) continue;
|
|
318
|
-
|
|
319
|
-
this._applyRoute( route, value, prev );
|
|
320
|
-
|
|
321
|
-
if ( route.reset ?? true ) needsReset = true;
|
|
327
|
+
if ( applied.route.reset ?? true ) needsReset = true;
|
|
322
328
|
|
|
323
329
|
if ( ! silent ) {
|
|
324
330
|
|
|
325
|
-
this.dispatchEvent( { type: EngineEvents.SETTING_CHANGED, key, value, prev } );
|
|
331
|
+
this.dispatchEvent( { type: EngineEvents.SETTING_CHANGED, key, value, prev: applied.prev } );
|
|
326
332
|
|
|
327
333
|
}
|
|
328
334
|
|
|
@@ -333,12 +339,73 @@ export class RenderSettings extends EventDispatcher {
|
|
|
333
339
|
|
|
334
340
|
}
|
|
335
341
|
|
|
342
|
+
/**
|
|
343
|
+
* Stores one value, tags its provenance and pushes it to its stage.
|
|
344
|
+
* @returns {?{route: ?Object, prev: *}} null when the value did not change
|
|
345
|
+
* @private
|
|
346
|
+
*/
|
|
347
|
+
_applyOne( key, value, source ) {
|
|
348
|
+
|
|
349
|
+
const prev = this._values.get( key );
|
|
350
|
+
if ( prev === value ) return null;
|
|
351
|
+
|
|
352
|
+
this._values.set( key, value );
|
|
353
|
+
this._sources.set( key, source );
|
|
354
|
+
|
|
355
|
+
const route = SETTING_ROUTES[ key ];
|
|
356
|
+
if ( ! route ) {
|
|
357
|
+
|
|
358
|
+
this._reportUnknownKey( key );
|
|
359
|
+
return { route: null, prev };
|
|
360
|
+
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
this._applyRoute( route, value, prev );
|
|
364
|
+
return { route, prev };
|
|
365
|
+
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/** Stored but never applied: a typo becoming a wrong image. @private */
|
|
369
|
+
_reportUnknownKey( key ) {
|
|
370
|
+
|
|
371
|
+
this._issues?.record(
|
|
372
|
+
ISSUE_CODES.SETTING_UNKNOWN_KEY,
|
|
373
|
+
`unknown setting "${key}" — stored but never applied to any stage`,
|
|
374
|
+
{ key }
|
|
375
|
+
);
|
|
376
|
+
|
|
377
|
+
}
|
|
378
|
+
|
|
336
379
|
get( key ) {
|
|
337
380
|
|
|
338
381
|
return this._values.get( key );
|
|
339
382
|
|
|
340
383
|
}
|
|
341
384
|
|
|
385
|
+
/**
|
|
386
|
+
* Every live setting with the value in force and who put it there. `routed: false` means
|
|
387
|
+
* stored but reaching no stage — see _reportUnknownKey.
|
|
388
|
+
*
|
|
389
|
+
* @returns {Object<string, {value: *, source: string, routed: boolean}>}
|
|
390
|
+
*/
|
|
391
|
+
getEffective() {
|
|
392
|
+
|
|
393
|
+
const out = {};
|
|
394
|
+
|
|
395
|
+
for ( const [ key, value ] of this._values ) {
|
|
396
|
+
|
|
397
|
+
out[ key ] = {
|
|
398
|
+
value,
|
|
399
|
+
source: this._sources.get( key ) ?? SETTING_SOURCE.DEFAULT,
|
|
400
|
+
routed: SETTING_ROUTES[ key ] !== undefined,
|
|
401
|
+
};
|
|
402
|
+
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
return out;
|
|
406
|
+
|
|
407
|
+
}
|
|
408
|
+
|
|
342
409
|
getAll() {
|
|
343
410
|
|
|
344
411
|
return Object.fromEntries( this._values );
|
|
@@ -396,6 +463,7 @@ export class RenderSettings extends EventDispatcher {
|
|
|
396
463
|
if ( key in defaults ) {
|
|
397
464
|
|
|
398
465
|
this._values.set( key, defaults[ key ] );
|
|
466
|
+
this._sources.set( key, SETTING_SOURCE.DEFAULT );
|
|
399
467
|
|
|
400
468
|
}
|
|
401
469
|
|
|
@@ -407,6 +475,7 @@ export class RenderSettings extends EventDispatcher {
|
|
|
407
475
|
if ( defaultsKey in defaults ) {
|
|
408
476
|
|
|
409
477
|
this._values.set( settingsKey, defaults[ defaultsKey ] );
|
|
478
|
+
this._sources.set( settingsKey, SETTING_SOURCE.DEFAULT );
|
|
410
479
|
|
|
411
480
|
}
|
|
412
481
|
|
package/src/index.js
CHANGED
|
@@ -9,11 +9,20 @@
|
|
|
9
9
|
import './TSL/patches.js';
|
|
10
10
|
|
|
11
11
|
// Main application
|
|
12
|
-
export { PathTracerApp } from './PathTracerApp.js';
|
|
12
|
+
export { PathTracerApp, describeAdapter } from './PathTracerApp.js';
|
|
13
13
|
|
|
14
14
|
// Event types
|
|
15
15
|
export { EngineEvents } from './EngineEvents.js';
|
|
16
16
|
|
|
17
|
+
// Headless rendering — the supported entry point for a caller with no screen
|
|
18
|
+
export { renderHeadless, openHeadless, captureHeadless } from './Headless.js';
|
|
19
|
+
|
|
20
|
+
// Degradation contract — what the engine survived instead of failing on
|
|
21
|
+
export { ISSUE_CODES, ISSUE_SEVERITY, IssueLog, EngineIssueError } from './EngineIssues.js';
|
|
22
|
+
|
|
23
|
+
// Settings provenance + viewer-vs-physical tuning
|
|
24
|
+
export { SETTING_SOURCE } from './RenderSettings.js';
|
|
25
|
+
|
|
17
26
|
// Asset URL / cache namespace overrides (call before constructing PathTracerApp)
|
|
18
27
|
export { configureAssets, getAssetConfig } from './AssetConfig.js';
|
|
19
28
|
|
|
@@ -43,6 +52,8 @@ export {
|
|
|
43
52
|
PRODUCTION_RENDER_CONFIG,
|
|
44
53
|
INTERACTIVE_RENDER_CONFIG,
|
|
45
54
|
MAX_RESERVABLE_RENDER_SIZE,
|
|
55
|
+
RENDER_PROFILES,
|
|
56
|
+
getRenderProfile,
|
|
46
57
|
} from './EngineDefaults.js';
|
|
47
58
|
|
|
48
59
|
// Settings & managers (for advanced consumers)
|