budge
Back to list

millionco/budge

Budge

GitHub

Use when making single-property CSS or Tailwind visual changes in Next.js App Router projects. Presents a floating control widget for live tuning before persisting.

VisualToolingFrontend

No visual demo for this skill

Tooling or audit guidance without a UI surface to embed.

Skill markdown
# Budge

**Proactive skill. Next.js App Router only.** If a task results in a single CSS property or Tailwind class change, follow this skill automatically. The user should never need to say "use budge."

You present a floating bar on the page after making an atomic visual change. The user fine-tunes the value with arrow keys (↑↓), swipes between related properties with arrow keys (←→). **With the current runtime, complete your turn immediately after making the visual change — no browser interaction, no waiting, and no manual config unless the fallback below is needed.**

The runtime is a self-contained IIFE loaded from `https://www.budge.design/budge.iife.js` via `next/script`. On local/dev hosts it stays on the page, watches HMR-driven `class`/`style` DOM changes, infers the latest numeric visual property change, marks the changed element, and mounts Budge automatically. It also uses React Grab primitives for manual selection: press `Cmd+E`, select an element, and Budge opens. It still supports the explicit `data-budge` config element as a fallback. Everything is handled client-side: live preview on `[data-budge-target]` elements, arrow key stepping, slide navigation, audio feedback, submit (Enter — copies an edit prompt to clipboard), and cancel (Escape — reverts).

**In scope:** Raw CSS property values, inline styles, Tailwind utility class changes, SVG presentation attributes (`fill`, `stroke`, etc.).
**Out of scope:** Sass/Less variables, CSS custom property definitions (`--spacing`), CSS-in-JS theme tokens. Proceed normally for these.

## Installation

Grep for `budge.iife.js` in `app/layout.tsx`. If found, make the requested visual change and stop. Otherwise, read `references/INSTALL.md` and follow its instructions.

## Default Flow

For a single raw CSS value or Tailwind class token change, just make the source edit. The always-on runtime should attach Budge to the resulting DOM change after HMR. Tell the user: "I've changed X to Y. Use ↑↓ to fine-tune, ←→ to switch properties."

Use the manual steps below only if the bar does not appear or the change cannot be inferred from one numeric `class`/`style` DOM mutation.

---

## Troubleshooting — bar does not appear

1. **Script missing:** Confirm `<Script src="https://www.budge.design/budge.iife.js" strategy="afterInteractive" />` is in `app/layout.tsx`.
2. **Auto-detect disabled:** Auto-detect runs by default on local/dev hosts. Force it with `data-budge-autodetect="true"` on the script tag, or disable it with `"false"`.
3. **No inferable DOM change:** The fallback bar only appears when a `<div data-budge="..." hidden />` element with a non-empty `slides` array is in the DOM.
4. **Target not found:** The element with `data-budge-target` must be in the DOM after hydration.

---

## Manual Fallback — Trigger Test

After making a change, apply this mechanical test. Do NOT use subjective judgment.

> **The last StrReplace call touched exactly one CSS value literal OR exactly one Tailwind utility class token, in exactly one file. The change is not a variable, mixin, or theme token.**

**Pass:** `padding: 8px` → `padding: 16px` | `className="p-2 m-4"` → `className="p-4 m-4"`
**Fail:** two values changed, token added/removed, Sass variable, multiple StrReplace calls, structural change.

Fail → skip budge, proceed normally. Pass → continue to Step 2. The mechanical test is the only gate.

## Step 2 — Build Slides

Build a `slides` array. The **first slide** is the property you changed. Additional slides are related properties the user might want to tweak.

Each slide has this shape:

```ts
{
  label: string;      // display name shown above bar
  property: string;   // CSS property to apply to [data-budge-target]
  min: number;        // minimum numeric value
  max: number;        // maximum numeric value
  value: number;      // current value (the one you set)
  original: number;   // value before your change
  unit: string;       // "px", "%", "em", etc.
  type?: "color";     // only set for color properties
}
```

### Slide generation rules

1. **Primary slide** (index 0): the property you changed. `value` = new value, `original` = old value.
2. **Related slides** (index 1+): pick 2–3 related properties from the same element. Read their current computed/declared values. Use sensible min/max ranges.

**Example — agent changed `padding-top: 8px` → `padding-top: 16px`:**

```ts
[
  { label: "padding-top", property: "padding-top", min: 0, max: 64, value: 16, original: 8, unit: "px" },
  { label: "padding-bottom", property: "padding-bottom", min: 0, max: 64, value: 8, original: 8, unit: "px" },
  { label: "padding-left", property: "padding-left", min: 0, max: 64, value: 12, original: 12, unit: "px" },
  { label: "padding-right", property: "padding-right", min: 0, max: 64, value: 12, original: 12, unit: "px" },
]
```

**Example — agent changed `font-size: 14px` → `font-size: 16px`:**

```ts
[
  { label: "font-size", property: "font-size", min: 8, max: 72, value

…

More from millionco