entangled-worlds-orbiters-shared 1.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.
Files changed (38) hide show
  1. package/README.md +75 -0
  2. package/package.json +49 -0
  3. package/public/config/textures.json +332 -0
  4. package/src/arrow-ui/BooleanController.js +31 -0
  5. package/src/arrow-ui/ColorController.js +108 -0
  6. package/src/arrow-ui/Controller.js +447 -0
  7. package/src/arrow-ui/FunctionController.js +27 -0
  8. package/src/arrow-ui/GUI.js +595 -0
  9. package/src/arrow-ui/NumberController.js +567 -0
  10. package/src/arrow-ui/OptionController.js +64 -0
  11. package/src/arrow-ui/StringController.js +41 -0
  12. package/src/arrow-ui/index.js +13 -0
  13. package/src/arrow-ui/lilGuiLoader.js +10 -0
  14. package/src/arrow-ui/utils/getColorFormat.js +75 -0
  15. package/src/arrow-ui/utils/injectStyles.js +10 -0
  16. package/src/arrow-ui/utils/normalizeColorString.js +29 -0
  17. package/src/config/index.js +8 -0
  18. package/src/config/textureConfig.js +299 -0
  19. package/src/core/index.js +3 -0
  20. package/src/core/lightFresnel.js +64 -0
  21. package/src/core/lights.js +43 -0
  22. package/src/index.js +8 -0
  23. package/src/loaders/bodyTextureLoader.js +39 -0
  24. package/src/loaders/cubeMapLoader.js +264 -0
  25. package/src/loaders/glbLoader.js +71 -0
  26. package/src/loaders/index.js +4 -0
  27. package/src/moons/index.js +3 -0
  28. package/src/moons/moonsGeneration.js +228 -0
  29. package/src/moons/moonsManager.js +64 -0
  30. package/src/utils/dispose.js +20 -0
  31. package/src/utils/index.js +3 -0
  32. package/src/utils/materials.js +31 -0
  33. package/src/world/cloudShell.js +89 -0
  34. package/src/world/index.js +6 -0
  35. package/src/world/worldGLB.js +7 -0
  36. package/src/world/worldManager.js +93 -0
  37. package/src/world/worldNormal.js +25 -0
  38. package/src/world/worldTexture.js +239 -0
@@ -0,0 +1,567 @@
1
+ import Controller from './Controller';
2
+
3
+ export default class NumberController extends Controller {
4
+
5
+ constructor( parent, object, property, min, max, step ) {
6
+
7
+ super( parent, object, property, 'number' );
8
+
9
+ this._initInput();
10
+
11
+ this.min( min );
12
+ this.max( max );
13
+
14
+ const stepExplicit = step !== undefined;
15
+ this.step( stepExplicit ? step : this._getImplicitStep(), stepExplicit );
16
+
17
+ this.updateDisplay();
18
+
19
+ }
20
+
21
+ decimals( decimals ) {
22
+ this._decimals = decimals;
23
+ this.updateDisplay();
24
+ return this;
25
+ }
26
+
27
+ min( min ) {
28
+ this._min = min;
29
+ this._onUpdateMinMax();
30
+ return this;
31
+ }
32
+
33
+ max( max ) {
34
+ this._max = max;
35
+ this._onUpdateMinMax();
36
+ return this;
37
+ }
38
+
39
+ step( step, explicit = true ) {
40
+ this._step = step;
41
+ this._stepExplicit = explicit;
42
+ return this;
43
+ }
44
+
45
+ updateDisplay() {
46
+
47
+ const value = this.getValue();
48
+
49
+ if ( this._hasSlider ) {
50
+
51
+ let percent = ( value - this._min ) / ( this._max - this._min );
52
+ percent = Math.max( 0, Math.min( percent, 1 ) );
53
+
54
+ if ( this.$slider ) {
55
+ const rect = this.$slider.getBoundingClientRect();
56
+ const trackWidth = Math.max( 0, rect.width );
57
+
58
+ // Set fill width
59
+ this.$fill.style.width = ( percent * trackWidth ) + 'px';
60
+
61
+ // Position arrow
62
+ if ( this.$pointer ) {
63
+ const arrowX = percent * trackWidth;
64
+ this.$pointer.style.left = arrowX + 'px';
65
+ }
66
+ }
67
+ }
68
+
69
+ if ( !this._inputFocused ) {
70
+ this.$input.value = this._decimals === undefined ? value : value.toFixed( this._decimals );
71
+ }
72
+
73
+ return this;
74
+ }
75
+
76
+ _initInput() {
77
+
78
+ this.$input = document.createElement( 'input' );
79
+ this.$input.setAttribute( 'type', 'text' );
80
+ this.$input.setAttribute( 'aria-labelledby', this.$name.id );
81
+
82
+ // On touch devices only, use input[type=number] to force a numeric keyboard.
83
+ // Ideally we could use one input type everywhere, but [type=number] has quirks
84
+ // on desktop, and [inputmode=decimal] has quirks on iOS.
85
+ // See https://github.com/georgealways/lil-gui/pull/16
86
+
87
+ const isTouch = window.matchMedia( '(pointer: coarse)' ).matches;
88
+
89
+ if ( isTouch ) {
90
+ this.$input.setAttribute( 'type', 'number' );
91
+ this.$input.setAttribute( 'step', 'any' );
92
+ }
93
+
94
+ this.$widget.appendChild( this.$input );
95
+
96
+ this.$disable = this.$input;
97
+
98
+ const onInput = () => {
99
+
100
+ let value = parseFloat( this.$input.value );
101
+
102
+ if ( isNaN( value ) ) return;
103
+
104
+ if ( this._stepExplicit ) {
105
+ value = this._snap( value );
106
+ }
107
+
108
+ this.setValue( this._clamp( value ) );
109
+
110
+ };
111
+
112
+ // Keys & mouse wheel
113
+ // ---------------------------------------------------------------------
114
+
115
+ const increment = delta => {
116
+
117
+ const value = parseFloat( this.$input.value );
118
+
119
+ if ( isNaN( value ) ) return;
120
+
121
+ this._snapClampSetValue( value + delta );
122
+
123
+ // Force the input to updateDisplay when it's focused
124
+ this.$input.value = this.getValue();
125
+
126
+ };
127
+
128
+ const onKeyDown = e => {
129
+ // Using `e.key` instead of `e.code` also catches NumpadEnter
130
+ if ( e.key === 'Enter' ) {
131
+ this.$input.blur();
132
+ }
133
+ if ( e.code === 'ArrowUp' ) {
134
+ e.preventDefault();
135
+ increment( this._step * this._arrowKeyMultiplier( e ) );
136
+ }
137
+ if ( e.code === 'ArrowDown' ) {
138
+ e.preventDefault();
139
+ increment( this._step * this._arrowKeyMultiplier( e ) * -1 );
140
+ }
141
+ };
142
+
143
+ const onWheel = e => {
144
+ if ( this._inputFocused ) {
145
+ e.preventDefault();
146
+ increment( this._step * this._normalizeMouseWheel( e ) );
147
+ }
148
+ };
149
+
150
+ // Vertical drag
151
+ // ---------------------------------------------------------------------
152
+
153
+ let testingForVerticalDrag = false,
154
+ initClientX,
155
+ initClientY,
156
+ prevClientY,
157
+ initValue,
158
+ dragDelta;
159
+
160
+ // Once the mouse is dragged more than DRAG_THRESH px on any axis, we decide
161
+ // on the user's intent: horizontal means highlight, vertical means drag.
162
+ const DRAG_THRESH = 5;
163
+
164
+ const onMouseDown = e => {
165
+
166
+ initClientX = e.clientX;
167
+ initClientY = prevClientY = e.clientY;
168
+ testingForVerticalDrag = true;
169
+
170
+ initValue = this.getValue();
171
+ dragDelta = 0;
172
+
173
+ window.addEventListener( 'mousemove', onMouseMove );
174
+ window.addEventListener( 'mouseup', onMouseUp );
175
+
176
+ };
177
+
178
+ const onMouseMove = e => {
179
+
180
+ if ( testingForVerticalDrag ) {
181
+
182
+ const dx = e.clientX - initClientX;
183
+ const dy = e.clientY - initClientY;
184
+
185
+ if ( Math.abs( dy ) > DRAG_THRESH ) {
186
+
187
+ e.preventDefault();
188
+ this.$input.blur();
189
+ testingForVerticalDrag = false;
190
+ this._setDraggingStyle( true, 'vertical' );
191
+
192
+ } else if ( Math.abs( dx ) > DRAG_THRESH ) {
193
+
194
+ onMouseUp();
195
+
196
+ }
197
+
198
+ }
199
+
200
+ // This isn't an else so that the first move counts towards dragDelta
201
+ if ( !testingForVerticalDrag ) {
202
+
203
+ const dy = e.clientY - prevClientY;
204
+
205
+ dragDelta -= dy * this._step * this._arrowKeyMultiplier( e );
206
+
207
+ // Clamp dragDelta so we don't have 'dead space' after dragging past bounds.
208
+ // We're okay with the fact that bounds can be undefined here.
209
+ if ( initValue + dragDelta > this._max ) {
210
+ dragDelta = this._max - initValue;
211
+ } else if ( initValue + dragDelta < this._min ) {
212
+ dragDelta = this._min - initValue;
213
+ }
214
+
215
+ this._snapClampSetValue( initValue + dragDelta );
216
+
217
+ }
218
+
219
+ prevClientY = e.clientY;
220
+
221
+ };
222
+
223
+ const onMouseUp = () => {
224
+ this._setDraggingStyle( false, 'vertical' );
225
+ this._callOnFinishChange();
226
+ window.removeEventListener( 'mousemove', onMouseMove );
227
+ window.removeEventListener( 'mouseup', onMouseUp );
228
+ };
229
+
230
+ // Focus state & onFinishChange
231
+ // ---------------------------------------------------------------------
232
+
233
+ const onFocus = () => {
234
+ this._inputFocused = true;
235
+ };
236
+
237
+ const onBlur = () => {
238
+ this._inputFocused = false;
239
+ this.updateDisplay();
240
+ this._callOnFinishChange();
241
+ };
242
+
243
+ this.$input.addEventListener( 'input', onInput );
244
+ this.$input.addEventListener( 'keydown', onKeyDown );
245
+ this.$input.addEventListener( 'wheel', onWheel, { passive: false } );
246
+ this.$input.addEventListener( 'mousedown', onMouseDown );
247
+ this.$input.addEventListener( 'focus', onFocus );
248
+ this.$input.addEventListener( 'blur', onBlur );
249
+
250
+ }
251
+
252
+ _initSlider() {
253
+
254
+ this._hasSlider = true;
255
+
256
+ // Build DOM
257
+ // ---------------------------------------------------------------------
258
+
259
+ this.$slider = document.createElement( 'div' );
260
+ this.$slider.classList.add( 'slider' );
261
+
262
+ this.$fill = document.createElement( 'div' );
263
+ this.$fill.classList.add( 'fill' );
264
+ this.$slider.appendChild( this.$fill );
265
+
266
+ // Triangle arrow pointer element
267
+ this.$pointer = document.createElement( 'div' );
268
+ this.$pointer.classList.add( 'valueArrow' );
269
+ this.$slider.appendChild( this.$pointer );
270
+
271
+ this.$widget.insertBefore( this.$slider, this.$input );
272
+ this.domElement.classList.add( 'hasSlider' );
273
+
274
+ this._injectArrowStyles();
275
+
276
+ // Map clientX to value
277
+ // ---------------------------------------------------------------------
278
+
279
+ const map = ( v, a, b, c, d ) => ( v - a ) / ( b - a ) * ( d - c ) + c;
280
+ const setValueFromX = clientX => {
281
+ const rect = this.$slider.getBoundingClientRect();
282
+ const x = Math.max( rect.left, Math.min( clientX, rect.right ) );
283
+ let value = map( x, rect.left, rect.right, this._min, this._max );
284
+ this._snapClampSetValue( value );
285
+ };
286
+
287
+ // Mouse drag
288
+ // ---------------------------------------------------------------------
289
+
290
+ const mouseDown = e => {
291
+ this._setDraggingStyle( true );
292
+ setValueFromX( e.clientX );
293
+ window.addEventListener( 'mousemove', mouseMove );
294
+ window.addEventListener( 'mouseup', mouseUp );
295
+ };
296
+
297
+ const mouseMove = e => {
298
+ setValueFromX( e.clientX );
299
+ };
300
+
301
+ const mouseUp = () => {
302
+ this._callOnFinishChange();
303
+ this._setDraggingStyle( false );
304
+ window.removeEventListener( 'mousemove', mouseMove );
305
+ window.removeEventListener( 'mouseup', mouseUp );
306
+ };
307
+
308
+ // Touch drag
309
+ // ---------------------------------------------------------------------
310
+
311
+ let testingForScroll = false, prevClientX, prevClientY;
312
+
313
+ const beginTouchDrag = e => {
314
+ e.preventDefault();
315
+ this._setDraggingStyle( true );
316
+ setValueFromX( e.touches[ 0 ].clientX );
317
+ testingForScroll = false;
318
+ };
319
+
320
+ const onTouchStart = e => {
321
+
322
+ if ( e.touches.length > 1 ) return;
323
+
324
+ // If we're in a scrollable container, we should wait for the first
325
+ // touchmove to see if the user is trying to slide or scroll.
326
+ if ( this._hasScrollBar ) {
327
+
328
+ prevClientX = e.touches[ 0 ].clientX;
329
+ prevClientY = e.touches[ 0 ].clientY;
330
+ testingForScroll = true;
331
+
332
+ } else {
333
+
334
+ // Otherwise, we can set the value straight away on touchstart.
335
+ beginTouchDrag( e );
336
+
337
+ }
338
+
339
+ window.addEventListener( 'touchmove', onTouchMove, { passive: false } );
340
+ window.addEventListener( 'touchend', onTouchEnd );
341
+
342
+ };
343
+
344
+ const onTouchMove = e => {
345
+
346
+ if ( testingForScroll ) {
347
+
348
+ const dx = e.touches[ 0 ].clientX - prevClientX;
349
+ const dy = e.touches[ 0 ].clientY - prevClientY;
350
+
351
+ if ( Math.abs( dx ) > Math.abs( dy ) ) {
352
+
353
+ // We moved horizontally, set the value and stop checking.
354
+ beginTouchDrag( e );
355
+
356
+ } else {
357
+
358
+ // This was, in fact, an attempt to scroll. Abort.
359
+ window.removeEventListener( 'touchmove', onTouchMove );
360
+ window.removeEventListener( 'touchend', onTouchEnd );
361
+
362
+ }
363
+
364
+ } else {
365
+
366
+ e.preventDefault();
367
+ setValueFromX( e.touches[ 0 ].clientX );
368
+
369
+ }
370
+
371
+ };
372
+
373
+ const onTouchEnd = () => {
374
+ this._callOnFinishChange();
375
+ this._setDraggingStyle( false );
376
+ window.removeEventListener( 'touchmove', onTouchMove );
377
+ window.removeEventListener( 'touchend', onTouchEnd );
378
+ };
379
+
380
+ // Mouse wheel
381
+ // ---------------------------------------------------------------------
382
+
383
+ // We have to use a debounced function to call onFinishChange because
384
+ // there's no way to tell when the user is "done" mouse-wheeling.
385
+ const callOnFinishChange = this._callOnFinishChange.bind( this );
386
+ const WHEEL_DEBOUNCE_TIME = 400;
387
+ let wheelFinishChangeTimeout;
388
+
389
+ const onWheel = e => {
390
+
391
+ // ignore vertical wheels if there's a scrollbar
392
+ const isVertical = Math.abs( e.deltaX ) < Math.abs( e.deltaY );
393
+ if ( isVertical && this._hasScrollBar ) return;
394
+
395
+ e.preventDefault();
396
+
397
+ // set value
398
+ const delta = this._normalizeMouseWheel( e ) * this._step;
399
+ this._snapClampSetValue( this.getValue() + delta );
400
+
401
+ // force the input to updateDisplay when it's focused
402
+ this.$input.value = this.getValue();
403
+
404
+ // debounce onFinishChange
405
+ clearTimeout( wheelFinishChangeTimeout );
406
+ wheelFinishChangeTimeout = setTimeout( callOnFinishChange, WHEEL_DEBOUNCE_TIME );
407
+
408
+ };
409
+
410
+ this.$slider.addEventListener( 'mousedown', mouseDown );
411
+ this.$slider.addEventListener( 'touchstart', onTouchStart, { passive: false } );
412
+ this.$slider.addEventListener( 'wheel', onWheel, { passive: false } );
413
+
414
+ }
415
+
416
+ _injectArrowStyles() {
417
+ // Styling is now handled in external CSS file (lil-gui.css)
418
+ // This method is kept for compatibility but doesn't inject styles
419
+ return;
420
+ }
421
+
422
+ _setDraggingStyle( active, axis = 'horizontal' ) {
423
+ if ( this.$slider ) {
424
+ this.$slider.classList.toggle( 'active', active );
425
+ }
426
+ document.body.classList.toggle( 'lil-gui-dragging', active );
427
+ document.body.classList.toggle( `lil-gui-${axis}`, active );
428
+ }
429
+
430
+ _getImplicitStep() {
431
+
432
+ if ( this._hasMin && this._hasMax ) {
433
+ return ( this._max - this._min ) / 1000;
434
+ }
435
+
436
+ return 0.1;
437
+
438
+ }
439
+
440
+ _onUpdateMinMax() {
441
+
442
+ if ( !this._hasSlider && this._hasMin && this._hasMax ) {
443
+
444
+ // If this is the first time we're hearing about min and max
445
+ // and we haven't explicitly stated what our step is, let's
446
+ // update that too.
447
+ if ( !this._stepExplicit ) {
448
+ this.step( this._getImplicitStep(), false );
449
+ }
450
+
451
+ this._initSlider();
452
+ this.updateDisplay();
453
+
454
+ }
455
+
456
+ }
457
+
458
+ _normalizeMouseWheel( e ) {
459
+
460
+ let { deltaX, deltaY } = e;
461
+
462
+ // Safari and Chrome report weird non-integral values for a notched wheel,
463
+ // but still expose actual lines scrolled via wheelDelta. Notched wheels
464
+ // should behave the same way as arrow keys.
465
+ if ( Math.floor( e.deltaY ) !== e.deltaY && e.wheelDelta ) {
466
+ deltaX = 0;
467
+ deltaY = -e.wheelDelta / 120;
468
+ deltaY *= this._stepExplicit ? 1 : 10;
469
+ }
470
+
471
+ const wheel = deltaX + -deltaY;
472
+
473
+ return wheel;
474
+
475
+ }
476
+
477
+ _arrowKeyMultiplier( e ) {
478
+
479
+ let mult = this._stepExplicit ? 1 : 10;
480
+
481
+ if ( e.shiftKey ) {
482
+ mult *= 10;
483
+ } else if ( e.altKey ) {
484
+ mult /= 10;
485
+ }
486
+
487
+ return mult;
488
+
489
+ }
490
+
491
+ _snap( value ) {
492
+
493
+ // Make the steps "start" at min or max.
494
+ let offset = 0;
495
+ if ( this._hasMin ) {
496
+ offset = this._min;
497
+ } else if ( this._hasMax ) {
498
+ offset = this._max;
499
+ }
500
+
501
+ value -= offset;
502
+
503
+ value = Math.round( value / this._step ) * this._step;
504
+
505
+ value += offset;
506
+
507
+ // Used to prevent "flyaway" decimals like 1.00000000000001
508
+ value = parseFloat( value.toPrecision( 15 ) );
509
+
510
+ return value;
511
+
512
+ }
513
+
514
+ _clamp( value ) {
515
+ // either condition is false if min or max is undefined
516
+ if ( value < this._min ) value = this._min;
517
+ if ( value > this._max ) value = this._max;
518
+ return value;
519
+ }
520
+
521
+ _snapClampSetValue( value ) {
522
+ this.setValue( this._clamp( this._snap( value ) ) );
523
+ }
524
+
525
+ get _hasScrollBar() {
526
+ const root = this.parent.root.$children;
527
+ return root.scrollHeight > root.clientHeight;
528
+ }
529
+
530
+ get _hasMin() {
531
+ return this._min !== undefined;
532
+ }
533
+
534
+ get _hasMax() {
535
+ return this._max !== undefined;
536
+ }
537
+
538
+ // Public API: set the arrow size used for the left visor (in px)
539
+ arrowSize( px ) {
540
+ this._arrowSize = px;
541
+ if ( this.$slider ) this._updateSliderPadding();
542
+ this.updateDisplay();
543
+ return this;
544
+ }
545
+
546
+ // Apply left padding to the slider equal to the arrow size
547
+ _updateSliderPadding() {
548
+ const size = this._getArrowSize();
549
+ if ( this.$slider ) {
550
+ this.$slider.style.paddingLeft = size + 'px';
551
+ this.$slider.style.setProperty( '--nc-arrow-size', size + 'px' );
552
+ }
553
+ }
554
+
555
+ // Read computed left padding in pixels
556
+ _getSliderLeftPadding() {
557
+ if ( !this.$slider ) return 0;
558
+ const cs = getComputedStyle( this.$slider );
559
+ return parseFloat( cs.paddingLeft ) || 0;
560
+ }
561
+
562
+ // Resolve arrow size with a sensible default
563
+ _getArrowSize() {
564
+ return ( this._arrowSize !== undefined ) ? this._arrowSize : 12; // default 12px
565
+ }
566
+
567
+ }
@@ -0,0 +1,64 @@
1
+ import Controller from './Controller';
2
+
3
+ export default class OptionController extends Controller {
4
+
5
+ constructor( parent, object, property, options ) {
6
+
7
+ super( parent, object, property, 'option' );
8
+
9
+ this.$select = document.createElement( 'select' );
10
+ this.$select.setAttribute( 'aria-labelledby', this.$name.id );
11
+
12
+ this.$display = document.createElement( 'div' );
13
+ this.$display.classList.add( 'display' );
14
+
15
+ this.$select.addEventListener( 'change', () => {
16
+ this.setValue( this._values[ this.$select.selectedIndex ] );
17
+ this._callOnFinishChange();
18
+ } );
19
+
20
+ this.$select.addEventListener( 'focus', () => {
21
+ this.$display.classList.add( 'focus' );
22
+ } );
23
+
24
+ this.$select.addEventListener( 'blur', () => {
25
+ this.$display.classList.remove( 'focus' );
26
+ } );
27
+
28
+ this.$widget.appendChild( this.$select );
29
+ this.$widget.appendChild( this.$display );
30
+
31
+ this.$disable = this.$select;
32
+
33
+ this.options( options );
34
+
35
+ }
36
+
37
+ options( options ) {
38
+
39
+ this._values = Array.isArray( options ) ? options : Object.values( options );
40
+ this._names = Array.isArray( options ) ? options : Object.keys( options );
41
+
42
+ this.$select.replaceChildren();
43
+
44
+ this._names.forEach( name => {
45
+ const $option = document.createElement( 'option' );
46
+ $option.textContent = name;
47
+ this.$select.appendChild( $option );
48
+ } );
49
+
50
+ this.updateDisplay();
51
+
52
+ return this;
53
+
54
+ }
55
+
56
+ updateDisplay() {
57
+ const value = this.getValue();
58
+ const index = this._values.indexOf( value );
59
+ this.$select.selectedIndex = index;
60
+ this.$display.textContent = index === -1 ? value : this._names[ index ];
61
+ return this;
62
+ }
63
+
64
+ }
@@ -0,0 +1,41 @@
1
+ import Controller from './Controller';
2
+
3
+ export default class StringController extends Controller {
4
+
5
+ constructor( parent, object, property ) {
6
+
7
+ super( parent, object, property, 'string' );
8
+
9
+ this.$input = document.createElement( 'input' );
10
+ this.$input.setAttribute( 'type', 'text' );
11
+ this.$input.setAttribute( 'spellcheck', 'false' );
12
+ this.$input.setAttribute( 'aria-labelledby', this.$name.id );
13
+
14
+ this.$input.addEventListener( 'input', () => {
15
+ this.setValue( this.$input.value );
16
+ } );
17
+
18
+ this.$input.addEventListener( 'keydown', e => {
19
+ if ( e.code === 'Enter' ) {
20
+ this.$input.blur();
21
+ }
22
+ } );
23
+
24
+ this.$input.addEventListener( 'blur', () => {
25
+ this._callOnFinishChange();
26
+ } );
27
+
28
+ this.$widget.appendChild( this.$input );
29
+
30
+ this.$disable = this.$input;
31
+
32
+ this.updateDisplay();
33
+
34
+ }
35
+
36
+ updateDisplay() {
37
+ this.$input.value = this.getValue();
38
+ return this;
39
+ }
40
+
41
+ }
@@ -0,0 +1,13 @@
1
+ export { default as default } from './GUI';
2
+
3
+ export { default as GUI } from './GUI';
4
+ export { default as Controller } from './Controller';
5
+
6
+ export { default as BooleanController } from './BooleanController';
7
+ export { default as ColorController } from './ColorController';
8
+ export { default as FunctionController } from './FunctionController';
9
+ export { default as NumberController } from './NumberController';
10
+ export { default as OptionController } from './OptionController';
11
+ export { default as StringController } from './StringController';
12
+
13
+ export { ensureLilGui } from './lilGuiLoader.js';
@@ -0,0 +1,10 @@
1
+ // Minimal lilGuiLoader: directly import local ESM GUI. No CSS handling or UMD/CDN fallback.
2
+ export async function ensureLilGui() {
3
+ if (window.lil && window.lil.GUI) return window.lil.GUI;
4
+ const mod = await import('./GUI.js');
5
+ const GUIClass = mod.GUI || mod.default;
6
+ if (!GUIClass) throw new Error('[lilGuiLoader] GUI class not found in ./GUI.js');
7
+ window.lil = window.lil || {};
8
+ window.lil.GUI = GUIClass;
9
+ return window.lil.GUI;
10
+ }