# Config Panel
A collapsible, reusable configuration panel component for building interactive controls for shader templates. The config panel provides a consistent UI for adjusting shader parameters in real-time.
The config panel system consists of:
- **ConfigPanel**: Container component with collapse/expand functionality and reset button
- **ConfigPanelSlider**: Slider control for numeric values (int or float)
- **ConfigPanelBooleanControl**: Checkbox control for boolean values
- **ConfigPanelLabel**: Text label component
All controls are styled to match the tldraw UI and automatically handle state persistence.
## ConfigPanel Component
The main container component that wraps all configuration controls.
### Props
- `children`: React nodes containing the control components
- `onReset`: Callback function to reset configuration to defaults
### Features
- **Collapsible**: Click the mixer icon to expand/collapse the panel
- **Persistent State**: Panel expanded/collapsed state is saved to localStorage
- **Reset Button**: Visible when expanded, calls the `onReset` callback
- **Scroll Prevention**: Prevents wheel events from affecting the canvas behind it
### Usage
```tsx
import { ConfigPanel } from '../config-panel/ConfigPanel'
import { resetMyConfig } from './config'
function MyConfigPanel() {
return {/* Add controls here */}
}
```
## ConfigPanelSlider
A slider control for numeric values with automatic range mapping.
### Props
- `prop`: Property name (passed to onChange)
- `label`: Display label for the slider
- `min`: Minimum value
- `max`: Maximum value
- `value`: Current value
- `type`: Either `'float'` or `'int'`
- `onChange`: Callback `(prop: string, value: number) => void`
### Features
- Automatically maps between slider steps (1-100) and actual value range
- Rounds to integers when `type='int'`
- Uses tldraw's built-in `TldrawUiSlider` component
### Usage
```tsx
```
## ConfigPanelBooleanControl
A checkbox control for boolean values.
### Props
- `prop`: Property name (passed to onChange)
- `label`: Display label for the checkbox
- `value`: Current boolean value
- `onChange`: Callback `(prop: string, value: boolean) => void`
### Usage
```tsx
```
## Reactive Configuration Pattern
The config panel works with tldraw's reactive `atom` system for automatic state management and persistence.
### Setting Up Config
```tsx
import { atom, react } from 'tldraw'
// 1. Define default configuration
const DEFAULT_CONFIG = {
quality: 0.5,
paused: false,
// ... other properties
}
// 2. Load from localStorage with fallback
const STORAGE_KEY = 'my-shader-config'
let initialValue = DEFAULT_CONFIG
try {
const value = localStorage.getItem(STORAGE_KEY)
if (value) initialValue = JSON.parse(value)
} catch {
// Use defaults if parse fails
}
// 3. Create reactive atom
export const myConfig = atom('my-config', initialValue)
// 4. Reset function
export function resetMyConfig() {
myConfig.set(DEFAULT_CONFIG)
}
// 5. Auto-save to localStorage
react('save to local storage', () => {
localStorage.setItem(STORAGE_KEY, JSON.stringify(myConfig.get()))
})
```
### Using Config in Component
```tsx
import { useValue } from 'tldraw'
import { myConfig } from './config'
export function MyConfigPanel() {
// Subscribe to reactive config changes
const config = useValue('config', () => myConfig.get(), [])
// Update config properties
const handleChange = useCallback((prop: string, value: number | boolean) => {
myConfig.update((prev) => ({ ...prev, [prop]: value }))
}, [])
return (
)
}
```
## Styling
The config panel uses CSS classes that can be customized:
- `.shader-config-panel`: Main panel container
- `.shader-config-panel--expanded`: Applied when expanded
- `.shader-config-panel--collapsed`: Applied when collapsed
- `.shader-config-panel__header`: Header with reset and toggle buttons
- `.shader-config-panel__content`: Content area (only visible when expanded)
- `.shader-config-panel__control`: Base class for individual controls
- `.shader-config-panel__control--slider`: Modifier for slider controls
- `.shader-config-panel__control--boolean`: Modifier for boolean controls
- `.shader-config-panel__boolean-input`: Checkbox input element
- `.shader-config-panel__label`: Label text for controls
## Integration with Shader Manager
The config panel is typically placed in the tldraw component tree and accessed by a shader manager:
```tsx
function MyShaderRenderer({ editor }: { editor: Editor }) {
const canvas = useRef(null)
useEffect(() => {
if (!canvas.current) return
// Initialize shader with reactive config
const manager = new MyShaderManager(canvas.current, editor, myConfig)
return () => manager.dispose()
}, [editor])
return
}
export default function ShaderExample() {
return (
)
}
```
## Best Practices
1. **Group Related Controls**: Organize controls by category (e.g., "General Settings", "Simulation Settings", "Visual Effects")
2. **Sensible Ranges**: Choose min/max values that provide useful adjustment without breaking the effect
3. **Clear Labels**: Use concise, descriptive labels (abbreviate if needed to fit the UI)
4. **Reasonable Defaults**: Set defaults that work well out of the box
5. **Persist State**: Always use the reactive atom pattern with localStorage persistence
6. **Type Safety**: Define TypeScript interfaces for your config objects
7. **Reset Function**: Always provide a reset function for returning to defaults
## Example: Complete Config Panel Setup
See `templates/shader/src/fluid/` for a full example implementing:
- `config.ts`: Reactive atom with localStorage persistence
- `FluidConfigPanel.tsx`: Complete configuration UI with 20+ controls
- `FluidManager.ts`: Shader manager that reads from the config atom
- Integration with WebGL fluid simulation
This demonstrates the full pattern for creating a configurable shader effect with a professional UI.