Describe a UI as plain objects bound to your data, and render it as a live panel with Tweakpane, Blueprint or your own components.
Website · Examples · API docs · Guide
const settings = {exposure: 1, tonemap: 'ACES', grid: true}
const config = {
type: 'folder',
label: 'Render',
expanded: true,
children: [
{type: 'slider', label: 'Exposure', bounds: [0, 4], stepSize: 0.1, property: [settings, 'exposure']},
{type: 'dropdown', label: 'Tone map', property: [settings, 'tonemap'], children: ['Linear', 'ACES', 'AgX'].map(label => ({label}))},
{type: 'checkbox', label: 'Grid', property: [settings, 'grid']},
{type: 'button', label: 'Reset', onClick: () => { settings.exposure = 1; config.uiRefresh?.(true) }},
],
}
import {UI} from 'uiconfig-tweakpane' // or 'uiconfig-blueprint'
new UI().appendChild(config)Moving the slider writes settings.exposure. Changing settings in code and calling config.uiRefresh() updates the panel.
- The UI lives next to the data. A config is a plain object, so a library or a game object can describe its own controls without depending on any UI package. Only the app that shows the panel imports a renderer, and a debug panel can stay optional.
- One config, any renderer. The same config renders with Tweakpane for a compact tool panel, or with Blueprint for a full editor. Switching is a one-line import change.
- Two-way binding.
property: [object, 'key']binds a control to a property;value, orgetValue/setValue, work when there is no object. Labels, bounds,hiddenanddisabledcan be functions, evaluated on each refresh. - Built for editors. Folders, panels, sliders, dropdowns, colors and vectors, undo, three.js
ColorandVectortypes, and custom components per renderer. threepipe builds its editor UI with it.
In a class, decorators generate the config:
import {uiContainer, uiSlider, uiDropdown, uiToggle, uiButton, IUiConfigContainer, UiObjectConfig} from 'uiconfig.js'
@uiContainer('Render')
class RenderSettings implements IUiConfigContainer {
uiConfig: UiObjectConfig
@uiSlider('Exposure', [0, 4], 0.1)
exposure = 1
@uiDropdown('Tone map', ['Linear', 'ACES', 'AgX'])
tonemap = 'ACES'
@uiToggle('Grid')
grid = true
@uiButton('Reset')
reset = () => {
this.exposure = 1
this.uiConfig.uiRefresh?.(true)
}
}
new UI().appendChild(new RenderSettings().uiConfig)Decorators need "experimentalDecorators": true in tsconfig.json.
npm install uiconfig.js uiconfig-tweakpane # or uiconfig-blueprintuiconfig.js holds the types and decorators. Plain JavaScript configs do not need it at all. Each renderer is a separate package:
| Package | What it is | |
|---|---|---|
| uiconfig.js | Config types, decorators, renderer base classes | |
| uiconfig-tweakpane | Renderer on Tweakpane 3: a compact floating panel | |
| uiconfig-blueprint | Renderer on Blueprint 5 (React): panels and editor layouts | |
| uiconfig-react | React base classes and un-styled components | in development |
| uiconfig-shadcn | Components on shadcn/ui for uiconfig-react | in development |
The renderer READMEs list their components and options.
- Guide: defining configs, the full config reference, binding, three.js.
- Examples: live panels with their code, in Tweakpane and Blueprint: configs as objects, classes and decorators, bindings, every component, dynamic panels, undo, three.js and threepipe.
- API docs: the three packages in one reference, with one search.
Issues and pull requests are welcome. CONTRIBUTING.md explains the setup, the builds and the release flow.
MIT, except uiconfig-blueprint: Apache 2.0.