Wire your
parameters
Modular controls for React. Knobs, faders, and toggles wired to your UI values. Link parameters together. Morph between scenes. Export as code.
Turn the knobs. See the change.
Every control is wired to the simulated app. Twist a knob, drag a fader, switch a scene. Everything updates live.
Build better products
The platform that helps teams ship faster with confidence. Start building today.
Fast
Sub-millisecond response times across the board.
Modular
Composable primitives that fit your architecture.
Typed
Full TypeScript coverage from API to components.
Not just another slider panel.
PATCH rethinks parameter controls from the ground up.
Rotary Knobs
Hardware-inspired knobs with arc indicators. Drag to adjust, use arrow keys, or double-click to type a value. Feels like turning a real dial.
Scene Morphing
Save parameter states as scenes. Drag the morph slider to crossfade between them. Every parameter interpolates smoothly.
Parameter Linking
Wire parameters together with expressions. When shadow depth increases, blur follows. When scale grows, opacity adapts. Reactive by default.
Modules
Group parameters into collapsible modules with solo and mute. Focus on typography, then spacing, then surfaces. One group at a time.
Copy as Code
One click to export current values as React props, CSS custom properties, Tailwind config, or a JSON snapshot. Paste into your codebase.
Keyboard First
Tab between knobs, arrow keys to adjust, Enter to confirm. Number keys jump to scenes. Fully operable without a mouse.
Three lines. Full control.
-
Declare
Call usePatch with your parameter config. Numbers get knobs. Booleans get toggles. Colors get wells. Nested objects become modules.
-
Tweak
Open the panel. Turn knobs, flip toggles, drag faders. Every change updates your component in real time. Save states as scenes.
-
Ship
Found the right values? Copy as code. Paste into your component. Remove the hook. The panel is dev-only and tree-shakes out in production.
Prompts to get started.
The fastest way to use PATCH is to tell your coding agent what you want. Here are some that work well.
Add to existing component
I have a card component with hover effects. Add PATCH controls for border radius, shadow depth, hover scale, and background opacity. Group shadow controls into their own module. Link shadow blur to shadow offset so they scale together.
Build with scenes
Create a hero section with PATCH. Add controls for font size, weight, letter spacing, padding, and accent color. Define three scenes: editorial with large light type, bold with tight heavy type, and playful with rounded colorful elements. Enable scene morphing.
Tune layout
Add PATCH to this dashboard grid. I want knobs for column count, gap, card padding, and card border radius. Add compact and spacious scenes. Group card-specific controls into a Card module with solo and mute.
Animation tuning
Create a modal with spring animation using Motion. Add PATCH controls for the entrance spring, backdrop blur, content border radius, and a replay action button. Link backdrop opacity to blur amount.
Drop it in.
npm install patchui
import { PatchRoot } from 'patchui'
import 'patchui/styles.css'
export default function Layout({ children }) {
return (
<>
{children}
<PatchRoot />
</>
)
}
Wire it up.
Call usePatch in any component. Each call creates a module in the panel.
import { usePatch, link } from 'patchui'
import { motion } from 'motion/react'
function Card() {
const p = usePatch('Card', {
blur: [24, 0, 100], // [default, min, max] → knob
opacity: [0.8, 0, 1],
scale: 1.18, // auto-range → knob
color: '#ff5500', // → color well
visible: true, // → toggle
// Nested objects become modules
shadow: {
offsetY: [8, 0, 24],
blur: link('shadow.offsetY', v => v * 2), // linked!
spread: [0, -10, 10],
},
spring: {
type: 'spring',
visualDuration: 0.3,
bounce: 0.2,
},
})
return (
<motion.div
style={{
filter: `blur(${p.blur}px)`,
opacity: p.visible ? p.opacity : 0,
color: p.color,
boxShadow: `0 ${p.shadow.offsetY}px ${p.shadow.blur}px rgba(0,0,0,0.2)`,
}}
animate={{ scale: p.scale }}
transition={p.spring}
/>
)
}
Save. Morph. Compare.
Define named scenes and crossfade between them at any speed.
const p = usePatch('Hero', {
fontSize: [48, 24, 96],
weight: [800, 300, 900],
padding: [40, 16, 80],
radius: [16, 0, 32],
accent: '#f59e0b',
}, {
scenes: {
editorial: { fontSize: 72, weight: 300, padding: 64, radius: 0, accent: '#ffffff' },
playful: { fontSize: 36, weight: 900, padding: 24, radius: 24, accent: '#f472b6' },
corporate: { fontSize: 42, weight: 600, padding: 48, radius: 8, accent: '#3b82f6' },
},
morphDuration: 400, // ms to crossfade
})
Wire parameters together.
The link() helper creates reactive connections between parameters. When the source changes, the linked parameter updates automatically.
import { usePatch, link } from 'patchui'
const p = usePatch('Card', {
elevation: [2, 0, 5],
// These follow elevation automatically
shadowY: link('elevation', e => e * 4),
shadowBlur: link('elevation', e => e * 8),
shadowOpacity: link('elevation', e => e * 0.04),
translateY: link('elevation', e => e * -1),
// Cross-module links work too
borderOpacity: link('elevation', e => 1 - e * 0.15),
})
// Turn one knob. Five values respond.
Config types.
The config object determines what controls appear in the panel.
| Format | Control | Description |
|---|---|---|
| [default, min, max, step?] | Knob | Explicit range with optional step. Renders a rotary knob. |
| number | Knob | Auto-inferred range based on value magnitude. |
| boolean | Toggle | On/off switch with physical toggle appearance. |
| "#ff5500" | Color Well | Auto-detected from hex strings. Shows swatch and editable hex. |
| "Hello" | Text Input | Non-hex strings become editable text fields. |
| link(path, fn) | Linked Knob | Computed from another parameter. Shows a cable indicator. |
| { type: "spring", ... } | Spring Editor | Visual spring curve with physics mode. |
| { type: "select", options } | Selector | Dropdown with string options array. |
| { type: "action" } | Button | Triggers onAction callback when pressed. |
| { nested: ... } | Module | Collapsible group with solo/mute. Use _collapsed: true to start closed. |
usePatch API
| Prop | Type | Description |
|---|---|---|
| name | string | Module title in the panel |
| config | PatchConfig | Parameter definitions (see config types) |
| options.scenes | Record<string, Partial> | Named parameter snapshots for morphing |
| options.morphDuration | number | Crossfade duration in ms (default 300) |
| options.onAction | (action: string) => void | Callback for action buttons |
| options.collapsed | boolean | Start module collapsed (default false) |
PatchRoot
Mount once at your app root. The panel renders via a portal.
| Prop | Type | Default |
|---|---|---|
| position | 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left' | 'top-right' |
| shortcut | string | 'Alt+P' |
| theme | 'dark' | 'light' | 'auto' | 'dark' |
| zIndex | number | 99999 |