"Auto" GUI
The autoGUI() function traverses an object, adding controllers for all applicable properties. Nested objects become folders. It also returns a "proxy" for the object passed. Assignments to that object will update the GUI display, sort of like a lazy listen().
import { autoGUI, range, options, color } from './autoGUI.js'
const { object, gui } = autoGUI( {
foo: 'bar',
bar: false,
baz: 0,
Folders: {
foo: 'bar',
bar: true,
nestedFolder1: {
foo: 'bar',
bar: false
},
nestedFolder2: {
foo: 'bar',
bar: 10
}
},
Directives: {
color: color( 0xff00ff ),
options: options( 'a', 'b', 'c' ),
range: range( 2.5, 0, 10 )
}
} );
window.object = object;
Try modifying the object variable in your console to see the GUI update.
import GUI from '../../dist/lil-gui.esm.js';
export function autoGUI( object, gui = new GUI() ) {
const controllers = {};
for ( let prop in object ) {
const val = object[ prop ];
switch ( typeof val ) {
case 'number':
case 'string':
case 'boolean':
controllers[ prop ] = gui.add( object, prop );
break;
default:
if ( val instanceof Directive ) {
switch ( val.type ) {
case 'range':
object[ prop ] = val.initial;
controllers[ prop ] = gui.add( object, prop, val.min, val.max );
break;
case 'options':
object[ prop ] = val.options[ 0 ];
controllers[ prop ] = gui.add( object, prop, val.options );
break;
case 'color':
object[ prop ] = val.value;
controllers[ prop ] = gui.addColor( object, prop );
break;
}
} else if ( Object( val ) === val ) {
const folder = gui.addFolder( prop ).close();
object[ prop ] = autoGUI( val, folder ).object;
}
break;
}
}
const proxy = new Proxy( object, {
set( _, prop, value ) {
object[ prop ] = value;
if ( prop in controllers ) {
controllers[ prop ].updateDisplay();
}
return true;
}
} );
return { object: proxy, gui };
}
export function options( ...options ) {
return new Directive( { options, type: 'options' } );
}
export function color( value ) {
return new Directive( { value, type: 'color' } );
}
export function range( initial, min, max ) {
return new Directive( { initial, min, max, type: 'range' } );
}
function Directive( obj ) {
Object.assign( this, obj );
}
In production, you could swap autoGUI.js for autoGUI.shim.js and the function would pass back the original object, untouched, along with an undefined GUI.
const pass = v => v;
const autoGUI = object => ( { object } );
export {
autoGUI,
pass as range,
pass as color,
pass as options
};