Perfect GUI v4

A nice, simple and (probably not) perfect GUI for JavaScript.

Basics

See code
const position = { x: 0 };

const gui = new GUI({ name: 'Basics' });

gui.button('Button', changeColor);

gui.slider({ name: 'Slider (simple callback)', value: 1 }, 
    value => element.style.opacity = value 
);

gui.slider({ 
    name: 'Slider 2 (object binding)', 
    obj: position, 
    prop: 'x', 
    min: -30, 
    max: 30, 
    step: .1 
}, () => {
    element.style.transform = `translateX(${position.x}px)`;
});

gui.toggle({ name: 'Switch', value: true }, state => {
    if (state) element.classList.remove('round');
    else element.classList.add('round');
});

gui.list({ name: 'List', options: ['red', 'pink', 'yellow', 'blue'] }, option => {
    element.style.backgroundColor = option;
});

gui.image({ name: 'Image 1', path: 'path/to/image-1.jpg' }, e => {
    element.style.backgroundImage = `url(${e.path})`;
});

gui.image({ name: 'Image 2', path: 'path/to/image-2.jpg' }, e => {
    element.style.backgroundImage = `url(${e.path})`;
});

gui.image({ name: 'Image 3', path: 'path/to/image-3.jpg' }, e => {
    element.style.backgroundImage = `url(${e.path})`;
});

gui.color({ name: 'Color', value: '#ff0000' }, color => {
    element.style.backgroundColor = color;
});

.button( parameters, callback )

Parameter Type Description
name string Optional.
color string Optional.
hoverColor string Optional. Default is equal to color if defined.
tooltip string|boolean Descriptive text showing up on hover. If set to true, its value will be the same as the name.
import GUI from 'perfect-gui';

const gui = new GUI();

gui.button('Button 1', changeColor);
// or
// gui.button({ name: 'Button 1' }, changeColor);

gui.button({ name: 'Button 2', color: '#bb3333', hoverColor: '#cc3333' }, changeColor);

.slider( parameters, callback )

Parameter Type Description
name string Defaults to the prop parameter if one is provided.
value number Defaults to the average value between min and max properties.
min number Default is 0.
max number Default is 1.
step number Increment by which to change the value.
Default is calculated so that there are 100 steps between min and max.
obj object Target object. Ignored if a value is specified.
prop string Target object property. Ignored if a value is specified.
tooltip string|boolean Descriptive text showing up on hover. If set to true, its value will be the same as the name.

This method can be used in 2 ways:

import GUI from 'perfect-gui';

const position = { x: 0 };
const gui = new GUI();

// Simple slider with value & callback
gui.slider({ name: 'Simple slider (value & callback)', value: 1 }, 
    value => {
        element.style.opacity = value;
    }
);

// Object binding
gui.slider({ name: 'Slider with object binding', obj: position, prop: 'x', min: -30, max: 30 },
    () => {
        element.style.transform = `translateX(${position.x}px)`;
    }
);

.toggle( parameters, callback )

Parameter Type Description
name string Optional.
value boolean Optional. Default is false.
obj object Optional. Target object. Ignored if a value is specified.
prop string Optional. Target object property. Ignored if a value is specified.
tooltip string|boolean Descriptive text showing up on hover. If set to true, its value will be the same as the name.

This method can be used in 2 ways:

import GUI from 'perfect-gui';

const gui = new GUI();

// Approach 1: using a callback function
gui.toggle({ name: 'Toggle (simple callback)', value: true }, value => {
    if ( value ) element.classList.remove('round');
    else element.classList.add('round');
});

// Approach 2: using object binding
const isRound = { state: true };
gui.toggle({ name: 'Toggle (object binding)', obj: isRound, prop: 'value' }, () => {
    if ( isRound.state ) element.classList.remove('round');
    else element.classList.add('round');
});

.list( parameters, callback )

Parameter Type Description
name string Optional.
values array Options to be displayed.
value string | number Optional. Defines the default selected value in the options array. This can either be a string, which must correspond to one of the values within the options array, or a number, representing the index of the selected value in the array of options.
obj object Optional. Target object. Ignored if a value is specified.
prop string Optional. Target object property. This can either be a string, which must correspond to one of the values within the options array, or a number, representing the index of the selected value in the array of options. Ignored if a value is specified.
tooltip string|boolean Descriptive text showing up on hover. If set to true, its value will be the same as the name.

This method can be used in 2 ways:

import GUI from 'perfect-gui';

const gui = new GUI();

// Approach 1: using a callback function
gui.list({ name: 'List', values: ['red', 'pink', 'yellow', 'blue'], value: 1 }, selected_value => {
    element.style.backgroundColor = selected_value;
});

// Approach 2: using object binding with an array of strings
const values = ['red', 'pink', 'yellow', 'blue'];
const color = { value: 2 };
gui.list({ name: 'List (object binding)', values, obj: color, prop: 'value' }, 
    ( value, index ) => {
        element.style.backgroundColor = values[color.value];
    }
);

// Approach 3: using object binding with an array of objects
// The "name" property is only used to control what's displayed in the option list
// The intrinsec value of each item is the "value" property
const color2 = { value: '#993333' };
const objectValues = [
    {name: 'reddish', value: '#993333'}, 
    {name: 'pinkish', value: '#aa33aa'}, 
    {name: 'yellowish', value: '#999933'}, 
    {name: 'blueish', value: '#333399'}
];
gui.list({ name: 'Object binding (objects)', values: objectValues, obj: color2, prop: 'value' }, 
    (obj, index) => {
        element.style.backgroundColor = obj.value;
    }
);

.image( parameters, callback )

Parameter Type Description
name string Optional. Default is the image file name.
path string Image file path.
selected boolean Default state of the item. Default is false.
selectionBorder boolean Defines if a border is visible around the selected element. Default is true.
width number | string A number type value specifies the width in pixels, while a string value allows for defining the width using various units of measurement, such as '50%' or '5vw'. Default is 33.333%.
height number Defines the height of the element in pixels. Default is 90.
tooltip string|boolean Descriptive text showing up on hover. If set to true, its value will be the same as the name.
import GUI from 'perfect-gui';

const gui = new GUI();

gui.image({ name: 'Image 1', path: 'path/to/image1.jpg'}, changeBackground);
gui.image({ name: 'Image 2', path: 'path/to/image2.jpg', selected: true}, changeBackground);
gui.image({ name: 'Image 3', path: 'path/to/image3.jpg'}, changeBackground);
gui.image({ name: 'Image 4', path: 'path/to/image4.jpg'}, changeBackground);
gui.image({ name: 'Image 5', path: 'path/to/image5.jpg'}, changeBackground);

function changeBackground(evt) {
    element.style.backgroundImage = `url( ${evt.path} )`;
}

To select a button programmatically, you can use the click() method on the element like this:

const imageButton = gui.image(...);
imageButton.click();

.color( parameters, callback )

Parameter Type Description
name string Optional.
value string Hexadecimal color value.
Optional. Default is #000000.
obj object Optional. Target object. Ignored if a value is specified.
prop string Optional. Target object property. Ignored if a value is specified.
tooltip string|boolean Descriptive text showing up on hover. If set to true, its value will be the same as the name.
import GUI from 'perfect-gui';

const gui = new GUI();

// Simple value & callback
gui.color({ name: 'Color (value & callback)', value: '#06ff89' }, color => {
    element.style.backgroundColor = color;
});

// Object binding
const color = { value: '#06ff89' };
gui.color({ name: 'Color (object binding)', obj: color, prop: 'value' }, () => {
    element.style.backgroundColor = color.value;
});

vector2( parameters, callback );

Parameter Type Description
name string Optional.
x object An object containing the x-axis properties
{ obj<object>, prop<string>, min<number>, max<number> }
y object An object containing the y-axis properties
{ obj<object>, prop<string>, min<number>, max<number> }
tooltip string|boolean Descriptive text showing up on hover. If set to true, its value will be the same as the name.

A vector2() component will automatically update the value of the target object property, therefore a callback isn't necessarily needed. Directly updating the object property will also update the vector2() component.

import GUI from 'perfect-gui';
        
const position = { x: 0, y: 0 };
const gui = new GUI();

gui.vector2({ name: 'Position',
    x: { obj: position, prop: 'x', min: -50, max: 50 },
    y: { obj: position, prop: 'y', min: -50, max: 50 },
}, (x, y) => {
    element.style.transform = `translate(${x}px, ${-y}px)`;
});

folder( parameters )

Parameter Type Description
name string Optional.
closed boolean Optional. Default is false.
color string Optional. Background color of the folder.
maxHeight number Optional.
import GUI from 'perfect-gui';

const gui = new GUI();

let folder_1 = gui.folder({ name: 'Folder 1' });
folder_1.button('Random color', changeColor);
folder_1.slider({ name: 'Size', value: 1 }, changeScale);

let folder_2 = gui.folder({ name: 'Folder 2', color: '#993333' });
folder_2.button('Random color', changeColor);

let folder_3 = gui.folder({ name: 'Folder 3', closed: true });
folder_3.button('Random color', changeColor);

toggleClose()

import GUI from 'perfect-gui';
        
const gui_1 = new GUI();

gui_1.button('gui_2.toggleClose();', () => {
    gui_2.toggleClose();
});

const gui_2 = new GUI();

gui_2.button('gui_1.toggleClose();', () => {
    gui_1.toggleClose();
});

Positioning

GUI instances can be positioned in any corner of the screen / container.

When multiple instances share the same position (like GUI 1 and GUI 2 in the example below), they are stacked next to each other.

See code
const gui_1 = new GUI({
    name: 'GUI 1',
    width: 200
});

gui_1.button('Buttons can handle multiple lines of text.', () => {
    element.style.backgroundColor = getRandomColor();
});

const gui_2 = new GUI({
    name: 'GUI 2',
    width: 200
});

gui_2.button('Button', () => element.style.backgroundColor = getRandomColor() );

const gui_3 = new GUI({
    name: 'GUI 3',
    position: 'top left'
});

gui_3.button('Button', () => element.style.backgroundColor = getRandomColor() );

const gui_4 = new GUI({
    name: 'GUI 4',
    position: 'bottom right'
});

gui_4.button('Button', () => element.style.backgroundColor = getRandomColor() );

Options

GUI panels can be dragged around with the draggable option.

They can also have a custom width, by using the width option.

Just like folders, GUI panels can be closed by default by setting the close option to true.

The maxHeight option can be used to define the maximum height of a panel beyond which scrolling is necessary. Default is the smallest value between the height of the window and the height of the container.

The color option can be used for both GUI panels and folders to customize their background color.

The opacity option sets the default transparency of panels. When a panel is hovered over, its opacity returns to 1.

The onUpdate option can be used to define a callback function, triggered each time the GUI is updated.

See code
const gui_1 = new GUI({
    container,
    name: 'GUI 1 (drag me!)',
    width: 450,
    draggable: true,
});
gui_1.button('Custom width using the `width` option', () => {});

const gui_2 = new GUI({
    container,
    name: 'GUI 2 (closed, scrollable)',
    closed: true,
});

let f1 = gui_2.folder({ name: 'folder', color: '#33329f' });
for (let i = 0; i < 3; i ++) {
    f1.button('btn '+ i, () => {});
}
let f2 = gui_2.folder({ name: 'folder', color: '#9f3293' });
for (let i = 0; i < 3; i ++) {
    f2.button('btn '+ i, () => {});
}
for (let i = 0; i < 10; i ++) {
    gui_2.button('btn '+ i, () => {});
}

const gui_3 = new GUI({
    container,
    position: 'bottom right',
    name: 'GUI 3 (custom color + opacity)',
    color: '#ff00ff',
    opacity: .5
});
gui_3.button('lorem', () => {});

Killing and creating dynamically

There is no .kill() method at the moment, so instances have to be killed "manually".

See code
const guis = [];

let gui_1 = new GUI({
    name: 'GUI 1',
});

gui_1.button('Create GUI panel', () => {
    guis[guis.length] = new GUI({
        name: 'Created GUI',
        position: 'bottom left',
        width: 150,
        color: 'red'
    });
});

gui_1.button('Kill GUI panel', () => {
    const index = guis.length - 1;
    if ( index >= 0 ) {
        // Removes html elements
        guis[index].wrapper.remove(); 

        // Frees up memory
        guis[index] = null;

        // Removes null value from array
        guis.splice(index, 1);
    }
});