DialKit
Josh Puckett's floating or inline tuning panel, plus individually exported controls: sliders, segmented toggles, color/image pickers, XY pads, and spring/Bézier editors wired to real UI values.
What It Does
DialKit renders a draggable floating panel that auto-generates controls from a config object. Call useDialKit("name", config) in any component and get a collapsible folder in the panel with sliders, toggles, pickers, spring/easing editors, and action buttons. Source: Obsidian-LLM-Wiki/Clippings/Josh Puckett.md; https://joshpuckett.me/dialkit
The panel is dev-only by default (productionEnabled: false). Supports popover and inline modes.
Config Types
| Format | Control | Description |
|---|---|---|
[default, min, max, step?] |
Slider | Explicit range with optional step |
number |
Slider | Auto-inferred range |
boolean |
Toggle | On/off segmented control |
"#ff5500" |
Color Picker | Auto-detected from hex strings |
"Hello" |
Text Input | Auto-detected from non-hex strings |
{ type: "spring", ... } |
Spring Editor | Visual spring curve, Time/Physics modes |
{ type: "easing", ... } |
Easing Editor | Cubic bezier curve with duration preview |
{ type: "select", ... } |
Select | Dropdown with options array |
{ type: "color", default: ... } |
Color Picker | Explicit color; supports alpha, OKLCH, and Display P3 as well as hex/RGB/HSL |
{ type: "image", options: [...] } |
Image Picker | Labeled URL choices or a local image upload |
{ type: "pad", x: [...], y: [...] } |
XY Pad | Bounded two-axis values with snapping and keyboard adjustment |
{ type: "action" } |
Button | Triggers onAction callback |
{ nested: ... } |
Folder | Collapsible group |
Keyboard Shortcuts
Assign keyboard shortcuts to controls: hold key + scroll, drag, or move mouse to adjust values without touching the panel. Interaction types: scroll, drag, move, scroll-only.
Installation
npm install dialkit motion
Add <DialRoot /> as sibling to {children} in root layout. Import dialkit/styles.css.
Use Cases
- Tuning spring physics (visualDuration, bounce) on hover animations
- Adjusting layout values (gap, padding, columns, radius) in real-time
- Exploring visual variations (colors, opacity, blur) on components
- Triggering replay of entrance animations via action buttons
- Live-tweaking Motion transition parameters during development
Tuning Console Pattern
Soren Blank's Linear parallax-bar recreation shows the high-leverage use case: use a DialKit-like floating panel as a temporary console for spatial/motion parameters while the component updates live. The reviewed video exposes bar count, step sizes, diagonal offsets, peak nodes, peak height, falloff, and floor. The lesson is to make hard-to-see motion geometry explicit while developing, then preserve the final values as constants or design tokens. Source: X/@sorenblank and local video contact sheet, 2026-07-03
Frameworks
React (default), Solid (dialkit/solid), Svelte 5 (dialkit/svelte), Vue 3 (dialkit/vue), and imperative DOM (dialkit/vanilla). Config concepts are shared, but hooks, accessors, lifecycle, and component bindings are framework-specific; do not paste one adapter's API unchanged into another. Store and timeline entry points are also exported. Source: pinned repository package.json, docs/reference.md, and docs/timeline.md
Source-Verified Adoption Boundary
The 2026-09-05 review binds npm dialkit@2.0.0 to repository commit
d408597c85b118dc497a209c5f1dc396922f8cc7. The repository's package.json
still says 1.4.4, while npm has no release at that version. npm's gitHead
matches the pinned commit, the tarball's SHA-512 integrity was verified, and
published dist/styles.css is byte-identical to src/styles/theme.css.
Treat the package metadata mismatch as a versioning hazard, not evidence of a
different stylesheet. License: MIT, copyright 2026 Josh Puckett; preserve
the notice when copying source or styles. Source: pinned repository,
published npm metadata and tarball; outputs/2026-09-05/source-compile/dialkit.md
Controlled components, not a second settings owner
The React package exposes useful controls separately from DialRoot:
| Public export | Controlled contract / adoption boundary |
|---|---|
Slider |
value, onChange, bounded min/max/step, optional unit; drag, keyboard, and precise numeric editing |
Toggle |
checked, onChange; a two-button Off/On radio group, not a switch |
SelectControl |
value, options, onChange; portal-backed, keyboard-operable menu |
TextControl |
value, onChange, optional placeholder; autosizing text input |
ColorControl |
Color string plus onChange; real picker, gamut/alpha controls, and format editing |
ImageControl |
URL/string value, optional labeled choices, onChange; uploads become data URLs, not remote storage |
DialPad |
{x,y} value and onChange; separate axis ranges; use only for a genuine two-axis relation |
EasingVisualization |
Easing object and optional onChange; editable cubic-Bézier geometry without a registered panel |
SpringVisualization |
Read-only curve from spring parameters and a mode flag |
Folder |
Optional controlled open/onOpenChange; group related controls without requiring a floating root |
ButtonGroup |
Array of {label,onClick} actions in a vertical stack, not a segmented value selector |
SegmentedControl exists internally but is not a public package export.
SpringControl and TransitionControl accept values and callbacks, but their
Time/Physics/Easing mode uses a registered DialStore panel. With no panel,
updateTransitionMode is a no-op; they are not fully store-independent
standalone editors. ControlRenderer, PresetManager, and ShortcutsMenu
likewise depend on the library store. Read the exported declaration rather
than guessing from a component's screenshot or filename. Source: pinned
src/index.ts, src/components/{Toggle,ButtonGroup,TransitionControl}.tsx,
src/store/DialStore.ts, published dist/index.d.ts
For a product inspector that already has saved settings, the preferred host
interpretation is to pass those settings into the real controlled exports and
keep one existing persistence owner. This is an adoption decision, not an
upstream requirement. If using DialRoot, its default production visibility
is off, its persistence default is false, and mode="inline" avoids a second
floating panel. A stable panel ID retains in-memory state across mounts;
explicit local/session persistence also owns presets and values. Source: pinned docs/reference.md; Personal Website integration direction, 2026-09-05
Visual and runtime checks before shipping
- The actual source grammar is compact: 36px rows, 6px row gaps, 13px labels, 8px control radius, 14px panel radius, and low-contrast nested surfaces. Preserve that hierarchy when fitting the host; do not reduce it to a generic collection of sliders. These measurements describe the source, not universal application spacing rules.
- The CSS begins with a remote Google Geist Mono import. A self-hosted-font
application should remove that import in an attributed scoped copy and map
its existing text/value fonts deliberately. Keep
.dialkit-roottokens and theme ownership consistent, including portal content. - Dark tertiary text is 40% white. Verify actual composited contrast and focus visibility instead of assuming the upstream alpha values satisfy the host's small-text requirements.
- Slider release/fill springs use imperative Motion
animate(). The source's reduced-motion CSS rules cover selected CSS transitions, not every imperative animation. Verify the host reduced-motion branch explicitly. - Image uploads are data URLs with a 10MB file cap; persisting several can exhaust browser storage. Only expose uploads if the product needs them.
- Color parsing does not accept CSS variables, named colors, or arbitrary CSS expressions. Resolve host tokens before passing a color to the picker.
- Root/picker menus use portals, fixed positioning, and optional browser top-layer popovers. Verify theme inheritance, clipping, scroll, touch, and keyboard focus in the actual sidebar.
- The separate timeline clock defaults to autoplay; hiding its UI does not stop playback. Do not add it merely for appearance or replace an existing owned animation clock without an explicit lifecycle decision.
These boundaries come from the pinned source, not a general accessibility or
production-readiness claim. 45 upstream pure tests passed for numeric
values, keyboard helpers, color/gamut handling, XY geometry, Bézier geometry,
popover measurement, image values, panel drag helpers, and copy instructions.
Framework/browser interaction, host theme contrast, reduced motion, and app
integration were not exercised by this source review. Source: outputs/2026-09-05/source-compile/dialkit.md
Timeline
- 2026-09-05 | Verified published
2.0.0against commitd408597c, expanded the source route to actual image/XY/Bézier and controlled exports, corrected adapter parity, and recorded store, font, motion, theme, license, and versioning boundaries. Retained the existing tuning-console owner rather than creating a second tool page. Source:reviews/source-signals/personal-website-dialkit-20260905.review.json - 2026-07-03 | Added Soren Blank's parallax-bar artifact as evidence for DialKit's role as a motion/layout tuning console, especially for visible geometry parameters that are tedious to tune by code edits alone. Source: X/@sorenblank, 2026-05-01
- 2026-06-17 | Added inline provenance and timeline. Source: Obsidian-LLM-Wiki/Clippings/Josh Puckett.md; https://joshpuckett.me/dialkit
- 2026-04-07 | Created DialKit tool page from Josh Puckett clipping. Source: Obsidian-LLM-Wiki/Clippings/Josh Puckett.md