AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Dialkit

skill-wyattjoh-skills-dialkit · by wyattjoh

Live parameter tweaking and design exploration for React projects using the dialkit npm package. Triggers on "design with dialkit", "live parameter tweaking", "interactive design exploration", "tweak parameters", "tune values", "explore design directions", "dial in this component", "design exploration", or invokes /dialkit. Installs dialkit temporarily, instruments components with sliders, colors…

No reviews yet
0 installs
32 views
0.0% view→install

Install

$ agentstack add skill-wyattjoh-skills-dialkit

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-wyattjoh-skills-dialkit)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
1mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Dialkit? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

DialKit

Overview

This skill walks the user through a temporary, exploratory integration of the dialkit npm package: a real-time parameter-tweaking panel for React. The user instruments one or more components with useDialKit calls, tweaks values live in the browser via a floating panel (sliders, color pickers, selects, spring editors, toggles), then the skill fully removes dialkit and bakes the chosen values into the source as inline literals.

> dialkit is never committed to source control. It exists only for the > duration of an exploration session.

Two Modes

Exploration Mode (primary)

The user has a vague idea or wants to discover. Instrument the component(s) with a wide set of controls, then explicitly guide the user to save 2 to 4 named presets ("Compact", "Bold", "Airy") using dialkit's "+" button. Once presets are saved, help them compare, pick a winner, or merge across presets ("I like Bold's color but Airy's spacing, synthesize").

Tweak Mode

The user has a specific component and a few specific knobs to dial in. Skip the multi-preset workflow. Instrument, let the user dial, capture the JSON, integrate.

When unsure, ask which mode. Default to Exploration.

Workflow

Phase 0: Setup detection

Before installing anything, gather:

  1. Confirm React project: read package.json, look for react. dialkit

itself also ships Solid, Svelte, and Vue integrations, but this skill's workflow only covers React. If react is absent, stop and explain that this skill's workflow is React-only.

  1. Check for motion: dialkit requires motion (formerly

framer-motion) for spring controls. Record one of:

  • motion already in package.json: don't reinstall, don't remove on

cleanup.

  • framer-motion only: still install motion (spring config is

interoperable). Do not remove framer-motion on cleanup.

  • Neither: install motion alongside dialkit. Must remove on cleanup.
  1. Look for design tokens (see [Design Token Detection](#design-token-detection)).
  2. Confirm dev server is running: ask the user. If not, ask them to start

it before instrumenting. The skill does not start it.

Phase 1: Mode + target selection

  1. Ask: Exploration or Tweak mode? Default to Exploration.
  2. Identify target component(s). Multiple components are supported; each gets

its own useDialKit('ComponentName', {...}) call and appears as a folder in the panel.

  1. Read each target component so you know its current values, what is

styling vs structural, and what already comes from tokens.

Phase 2: Property selection and preset directions

For each target, ask the user what aspects they want to tweak or explore. Don't infer aggressively. Surface candidates only after they answer.

If design tokens were found in Phase 0, seed defaults from them:

> "Your theme defines spacing.lg = 16 and colors.primary = #6366f1. I'll > use those as starting values, so the slider center is your existing design > language."

Translate each aspect to the appropriate dialkit control type using [Control Selection](#control-selection).

Always brainstorm 3 to 5 named design directions before instrumenting. The skill seeds these as presets so the panel opens with a comparison set ready in the dropdown. Names should match the exploration:

| Mode | Direction-name patterns that work well | | ----------- | ------------------------------------------------------------------ | | Exploration | Compact / Bold / Airy / Playful / Restrained / Dramatic | | Tweak | Subtle / Default / Strong (or Conservative / Default / Aggressive) |

For each direction, propose concrete values for the panel's controls (anchor to design tokens when they exist). Even in Tweak mode, generate at least 3 seeds so the user can A/B/C compare instead of dialing from scratch. These become the panel's seedPresets argument in Phase 3.

Phase 3: Instrument

Make these edits in this order:

  1. Install dependencies:

``bash npm install dialkit motion ``

Skip motion if already present.

  1. Mount `` once at the app root. Locations vary:

| Setup | File | | -------------------- | -------------------------------- | | Next.js App Router | app/layout.tsx inside ` | | Next.js Pages Router | pages/_app.tsx | | Vite / CRA | src/main.tsx or src/App.tsx | | Remix | app/root.tsx inside ` |

``tsx import { DialRoot } from "dialkit"; import "dialkit/styles.css"; // ... ; ``

Never set productionEnabled. dialkit auto-hides in prod builds, which guarantees the panel never ships.

  1. **Add `** next to ` to survive HMR and

page refreshes. dialkit has no built-in persistence; values and presets live in a module-level singleton (DialStore) that wipes on full reloads. See [Persistence](#persistence) for the snippet to drop in.

  1. Instrument target components with useDialKit. Replace the values the

user wants to vary with p. references. Leave other values untouched. Each component gets its own panel folder via the name argument:

``tsx const p = useDialKit("Card", { shadow: { blur: [12, 0, 60], offsetY: [4, 0, 24], opacity: [0.1, 0, 0.4], }, }); ``

  1. Tell the user where to look:

> "The panel is at the top-right of your dev server. Open the disclosure to > see the controls. Tweak as long as you like. Refreshes and HMR reloads > preserve your values and presets via sessionStorage."

Phase 4A: Exploration loop (presets-as-design-directions)

This is the killer pattern for exploration mode. The panel ships already populated with the seeded presets from Phase 3.

  1. Tell the user: "The dropdown at the top of the panel has the directions we

pre-seeded ('Compact', 'Bold', 'Airy', etc.). Click each to switch in the live preview. Drag any control to refine within a preset (auto-saves to the active one). Click + to add a new preset for any direction we missed."

  1. When the user has narrowed down, ask them to either:
  • Tell you which preset wins ("Bold feels right"), or
  • Click Copy on each preset they're considering and paste the JSONs

in chat for side-by-side comparison.

  1. When you have multiple preset JSONs in chat, help with:
  • Compare: "Compact has 8/12/16 spacing, Bold has 4/8/12, so Bold is

about 50% tighter overall."

  • Pick a winner: "Sounds like Airy is closest. Want to ship those

values?"

  • Merge: "Want Bold's colors with Airy's spacing? I'll synthesize the

blend. Paste it back into the panel as a new preset to verify."

  1. Iterate until the user picks a final direction.

Phase 4B: Tweak loop

Even in tweak mode the panel ships with the 3 seeded presets (Subtle / Default / Strong, or whatever names you brainstormed in Phase 2), so the user can A/B/C immediately rather than dialing from scratch.

  1. User switches between seeded presets to find the closest baseline, then

refines via the controls (auto-saves to the active preset).

  1. When satisfied, user clicks Copy in the panel toolbar.
  2. User pastes the JSON in chat.

Phase 5: Capture final values

When the user pastes JSON:

  1. Validate the shape matches the dialkit config you authored in Phase 3

(same keys, same nesting). If it doesn't (e.g. partial selection), ask them to Copy again from the panel.

  1. Echo the values back so the user can confirm: "Final values:

padding=16, shadowBlur=24, ... apply?"

Phase 6: Integrate + cleanup

This is the most important phase. The working tree must end up with only the design changes, no trace of dialkit.

In order:

  1. Replace p. references with concrete literals at every call

site. Inline literals (e.g. p.shadowBlur becomes 24).

  1. Remove the useDialKit(...) call from each instrumented component.
  2. Remove the useDialKit import from each file.
  3. If no useDialKit call remains anywhere:
  • Remove ` and ` from the root layout.
  • Remove import "dialkit/styles.css" and

import { DialRoot } from "dialkit".

  • Remove the import { DialKitPersistence } from "./DialKitPersistence".
  • Delete DialKitPersistence.tsx entirely.
  1. Uninstall:

``bash npm uninstall dialkit ``

Run npm uninstall motion only if Phase 0 recorded that we installed it.

  1. Verify (run all of these, expect zero hits):

``bash grep -r "dialkit" src/ app/ pages/ components/ 2>/dev/null grep -r "DialRoot" src/ app/ pages/ components/ 2>/dev/null grep -r "useDialKit" src/ app/ pages/ components/ 2>/dev/null ``

Also confirm package.json has no dialkit entry, and no motion entry if we installed it.

  1. Run typecheck/build: npm run typecheck or npm run build. Fix any

stragglers.

  1. Show the diff so the user can confirm only their design values changed.
  2. Offer to commit with a conventional commit message focused on the

design change:

`` style(card): refine shadow depth and motion timing ``

Don't mention dialkit; it's an implementation detail of the exploration process.

See [Cleanup Verification Checklist](#cleanup-verification-checklist) for the strict, ordered list.

Persistence

> Note: dialkit (≥1.x) now ships a built-in persist option on > useDialKit/useDialKitController (persist: true or > { key, storage: 'localStorage'|'sessionStorage', presets: boolean }) that > covers much of what the companion component below does. Check the installed > package version and its README before instrumenting; the built-in option > may let you skip copying DialKitPersistence.tsx entirely. The workflow > below remains a valid fallback for older versions or finer control.

Historically, dialkit had no built-in persistence: its DialStore is a module-level singleton (export const DialStore = new DialStoreClass()) holding panels, values, and presets in plain Maps. Anything that recreates that singleton wipes state:

| Event | Wipes state? | Why | | ---------------------------------- | ------------ | --------------------------------------------------------------------------------------- | | Editing a consumer component (HMR) | No | dialkit module untouched, singleton survives, React Fast Refresh keeps useId() stable | | Full page refresh | Yes | Browser drops all JS memory | | Hard HMR / optimize-deps reload | Yes | Fresh module graph, fresh singleton | | Editing dialkit itself (rare) | Yes | Module re-evaluates, fresh singleton | | Closing the tab | Yes | Memory gone with the document |

To survive these, mount a ` companion next to that mirrors the store to sessionStorage. It uses only dialkit's public API (DialStore.subscribe, subscribeGlobal, getPanels, getValues, getPresets, getActivePresetId, updateValue, savePreset, loadPreset`), so no monkey-patching.

Copy the prebuilt component from this skill's references folder into the user's project next to where they mount ``:

cp $SKILL_DIR/references/DialKitPersistence.tsx //

$SKILL_DIR resolves to ~/.claude/skills/dialkit/. Common destinations:

| Setup | Destination | | -------------------- | ---------------------------------------- | | Next.js App Router | app/DialKitPersistence.tsx | | Next.js Pages Router | pages/DialKitPersistence.tsx or src/ | | Vite / CRA | src/DialKitPersistence.tsx | | Remix | app/DialKitPersistence.tsx |

The file is a self-contained ~110-line React component using only dialkit's public API (subscribe, subscribeGlobal, getPanels, getValues, getPresets, getActivePresetId, updateValue, savePreset, loadPreset), so no monkey-patching. It's marked TEMPORARY in a header comment so the user knows to delete it during cleanup.

Mount it alongside ` (after, so its effect runs after consumers register their panels) and pass the **seedPresets** brainstormed in Phase 2. Each key matches a useDialKit` panel name; each entry is a list of named directions whose values populate the panel's preset dropdown on first load:

import { DialRoot } from "dialkit"
import "dialkit/styles.css"
import {
  DialKitPersistence,
  type DialKitSeedPresets,
} from "./DialKitPersistence"

const seedPresets: DialKitSeedPresets = {
  Card: [
    {
      name: "Compact",
      values: { "shadow.blur": 8, "shadow.offsetY": 2, "shadow.opacity": 0.05 },
    },
    {
      name: "Bold",
      values: { "shadow.blur": 32, "shadow.offsetY": 12, "shadow.opacity": 0.3 },
    },
    {
      name: "Airy",
      values: { "shadow.blur": 24, "shadow.offsetY": 8, "shadow.opacity": 0.12 },
    },
  ],
}

// in your root layout, inside :

Path keys are dotted strings matching the dialkit config nesting (e.g. shadow.blur for { shadow: { blur: [...] } }). Seeds only fire when sessionStorage has no prior entry for the panel name; once the user has interacted, their tweaks are preserved across reloads. To re-seed after changing the seed values, clear sessionStorage.dialkit:session in devtools and refresh.

What this covers

  • Page refresh: hydrates from sessionStorage on the next mount. Values

and preset names/contents return.

  • Hard HMR / module-level dialkit reload: same hydration path triggers

whenever a panel re-registers against a fresh DialStore.

  • Late-mounting consumers (lazy routes, conditional renders): hydrated on

first registration via the subscribeGlobal callback.

Caveats

  • Identity is by panel name: two useDialKit calls with the same name

will collide in storage. The skill already enforces unique names per component; keep it that way.

  • Preset ids change across reloads (regenerated by savePreset). Names

and contents survive, which is what the workflow uses. If your code reads preset ids directly, don't rely on stability.

  • Tab-scoped: sessionStorage clears when the tab closes. This is

intentional for ephemeral exploration. If you want presets to survive tab close (e.g. to resume tomorrow), swap sessionStorage for localStorage in the snippet (one line, two occurrences). For multi-day exploration, prefer the .dialkit.notes.md workflow described under [Edge Cases](#user-wants-to-keep-tweaking-in-a-future-session) instead, so the values land in version control as plain JSON.

  • Storage size: typical sessions stay under a few KB; far below the ~5MB

per-origin sessionStorage cap. If you hit the cap, you have too many panels with too many controls and should split them.

Cleanup

DialKitPersistence.tsx is a temporary file. The [Cleanup Verification Checklist](#cleanup-verification-checklist) below includes deleting it. After integration, the dialkit:session entry in sessionStorage becomes orphaned, but it's already cleared on tab close.

Control Selection

When translating user-stated aspects to dialkit config:

| User wants to vary | dialkit control | Example | | --------------------------------------------- | ---------------------- | --------------

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.