budge

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Budge

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 (←→). You complete your turn immediately after setting the config — no browser interaction, no waiting.
The runtime is a self-contained IIFE loaded from
https://skills-pearl.vercel.app/budge.iife.js
via
next/script
. It auto-initializes by reading a
data-budge
config element from the DOM — no wrapper component needed. It handles everything client-side: live preview on
[data-budge-target]
elements, arrow key stepping, slide navigation, audio feedback, submit (Enter — copies a generic 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.
主动技能。仅适用于Next.js App Router。 如果任务涉及单一CSS属性或Tailwind类的修改,请自动遵循此技能。用户无需主动要求“使用Budge”。
在完成原子视觉修改后,你需要在页面上展示一个浮动栏。用户可以通过方向键(↑↓)微调数值,通过方向键(←→)在相关属性间切换。设置完配置后请立即结束当前操作——无需进行浏览器交互,无需等待。
运行时是一个独立的IIFE,通过
next/script
https://skills-pearl.vercel.app/budge.iife.js
加载。它会通过读取DOM中的
data-budge
配置元素自动初始化——无需包装组件。它在客户端处理所有操作:
[data-budge-target]
元素的实时预览、方向键步进、滑动导航、音频反馈、提交(回车键——将通用编辑提示复制到剪贴板)和取消(ESC键——恢复原状)。
适用范围: 原生CSS属性值、内联样式、Tailwind工具类修改、SVG呈现属性(
fill
stroke
等)。 不适用范围: Sass/Less变量、CSS自定义属性定义(
--spacing
)、CSS-in-JS主题令牌。此类情况请按常规流程处理。

Installation

安装

Grep for
budge.iife.js
in
app/layout.tsx
. If found, skip to Step 1. Otherwise, read
references/INSTALL.md
and follow its instructions.

app/layout.tsx
中搜索
budge.iife.js
。如果已存在,跳至步骤1。否则,请阅读
references/INSTALL.md
并按照说明操作。

Troubleshooting — bar does not appear

故障排查——浮动栏未显示

  1. Script missing: Confirm
    <Script src="https://skills-pearl.vercel.app/budge.iife.js" strategy="afterInteractive" />
    is in
    app/layout.tsx
    .
  2. No config element: The bar only appears when a
    <div data-budge="..." hidden />
    element with a non-empty
    slides
    array is in the DOM.
  3. Target not found: The element with
    data-budge-target
    must be in the DOM after hydration.

  1. 脚本缺失: 确认
    <Script src="https://skills-pearl.vercel.app/budge.iife.js" strategy="afterInteractive" />
    已添加到
    app/layout.tsx
    中。
  2. 无配置元素: 只有当DOM中存在带有非空
    slides
    数组的
    <div data-budge="..." hidden />
    元素时,浮动栏才会显示。
  3. 目标元素未找到: 带有
    data-budge-target
    的元素必须在 hydration 后存在于DOM中。

Step 1 — Trigger Test

步骤1——触发测试

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.
完成修改后,执行以下机械测试。请勿使用主观判断。
最后一次StrReplace调用仅修改了单个文件中的恰好一个CSS值字面量或恰好一个Tailwind工具类令牌。修改内容不是变量、混合宏或主题令牌。
通过:
padding: 8px
padding: 16px
|
className="p-2 m-4"
className="p-4 m-4"
不通过: 修改了两个值、添加/删除令牌、Sass变量、多次StrReplace调用、结构性修改。
不通过→跳过Budge,按常规流程处理。通过→继续步骤2。机械测试是唯一的判断标准。

Step 2 — Build Slides

步骤2——构建幻灯片

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
}
构建一个
slides
数组。第一张幻灯片是你修改的属性。额外的幻灯片是用户可能想要微调的相关属性。
每张幻灯片的结构如下:
ts
{
  label: string;      // 浮动栏上方显示的名称
  property: string;   // 要应用到[data-budge-target]的CSS属性
  min: number;        // 最小数值
  max: number;        // 最大数值
  value: number;      // 当前值(你设置的值)
  original: number;   // 修改前的值
  unit: string;       // "px"、"%"、"em"等
  type?: "color";     // 仅针对颜色属性设置
}

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: 16, original: 14, unit: "px" },
  { label: "line-height", property: "line-height", min: 12, max: 80, value: 24, original: 22, unit: "px" },
  { label: "letter-spacing", property: "letter-spacing", min: -2, max: 10, value: 0, original: 0, unit: "px" },
]
Example — agent changed
color: #333
color: #1a1a1a
:
Use the
type: "color"
slide with hue degrees:
ts
[
  { label: "color", property: "color", min: 0, max: 360, value: 0, original: 0, unit: "°", type: "color" },
]
  1. 主幻灯片(索引0):你修改的属性。
    value
    = 新值,
    original
    = 旧值。
  2. 相关幻灯片(索引1+):从同一元素中选择2-3个相关属性。读取它们当前的计算值/声明值。使用合理的最小/最大范围。
示例——助手将
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" },
]
示例——助手将
font-size: 14px
修改为
font-size: 16px
ts
[
  { label: "font-size", property: "font-size", min: 8, max: 72, value: 16, original: 14, unit: "px" },
  { label: "line-height", property: "line-height", min: 12, max: 80, value: 24, original: 22, unit: "px" },
  { label: "letter-spacing", property: "letter-spacing", min: -2, max: 10, value: 0, original: 0, unit: "px" },
]
示例——助手将
color: #333
修改为
color: #1a1a1a
使用带有色相度数的
type: "color"
幻灯片:
ts
[
  { label: "color", property: "color", min: 0, max: 360, value: 0, original: 0, unit: "°", type: "color" },
]

Related property suggestions

相关属性建议

Changed propertyRelated slides
padding-top
padding-bottom
,
padding-left
,
padding-right
padding
padding-top
,
padding-bottom
margin-top
margin-bottom
,
margin-left
,
margin-right
font-size
line-height
,
letter-spacing
gap
padding
,
margin-top
width
height
,
max-width
border-radius
padding
,
border-width
opacity
font-size
修改的属性相关幻灯片
padding-top
padding-bottom
,
padding-left
,
padding-right
padding
padding-top
,
padding-bottom
margin-top
margin-bottom
,
margin-left
,
margin-right
font-size
line-height
,
letter-spacing
gap
padding
,
margin-top
width
height
,
max-width
border-radius
padding
,
border-width
opacity
font-size

Tailwind resolution

Tailwind解析

Resolve Tailwind classes to CSS properties and pixel values (multiply spacing scale × 4):
Tailwind classPrimary slide propertyValue
p-4
padding
16px
px-4
padding-left
(also set
padding-right
)
16px
py-4
padding-top
(also set
padding-bottom
)
16px
pt-4
padding-top
16px
mt-4
margin-top
16px
gap-4
gap
16px
text-[14px]
font-size
14
rounded-lg
border-radius
8px
For axis shorthands (
px-*
,
py-*
,
mx-*
,
my-*
), set the primary slide to one axis property but include both as slides.
For Tailwind classes, also add an inline style override on the target element so the runtime can manipulate the value directly:
jsx
<div data-budge-target className="py-4" style={{ paddingTop: '16px', paddingBottom: '16px' }}>
将Tailwind类解析为CSS属性和像素值(间距刻度×4):
Tailwind类主幻灯片属性
p-4
padding
16px
px-4
padding-left
(同时设置
padding-right
16px
py-4
padding-top
(同时设置
padding-bottom
16px
pt-4
padding-top
16px
mt-4
margin-top
16px
gap-4
gap
16px
text-[14px]
font-size
14
rounded-lg
border-radius
8px
对于轴简写(
px-*
py-*
mx-*
my-*
),将主幻灯片设置为一个轴属性,但同时包含两个轴作为幻灯片。
对于Tailwind类,还需要在目标元素上添加内联样式覆盖,以便运行时可以直接操作值:
jsx
<div data-budge-target className="py-4" style={{ paddingTop: '16px', paddingBottom: '16px' }}>

Design token snapping

设计令牌对齐

If the project defines design tokens as CSS custom properties on
:root
or
@theme
(Tailwind v4, Shadcn, plain CSS vars), the runtime automatically snaps ↑/↓ stepping through them by matching property to scale:
Property matchDiscovered prefix
padding*
,
margin*
,
gap
--spacing-*
font-size
--text-*
border-radius*
--radius-*
color
,
*-color
--color-*
(no snap yet — palette cycling is a follow-up)
When a token matches the current value, the widget shows its name (e.g.
16px · md
) and Enter emits
Set \
padding` to `var(--spacing-md)`` instead of a raw px value. Users can still type digits to escape to arbitrary px.
You don't need to specify
scale
on slides — it's auto-detected from
property
. Pass
scale: null
to disable snapping for a slide, or
scale: "spacing" | "text" | "radius" | "color"
to override. Pass
tokens: [{ name, value, numeric }]
to override discovery entirely. Use
unit: "px"
when relying on token snapping (the runtime applies the token's raw value so rem/em tokens resolve correctly regardless).
如果项目在
:root
@theme
(Tailwind v4、Shadcn、纯CSS变量)上定义了设计令牌作为CSS自定义属性,运行时会通过将属性与刻度匹配,自动在↑/↓步进时对齐这些令牌:
属性匹配发现的前缀
padding*
,
margin*
,
gap
--spacing-*
font-size
--text-*
border-radius*
--radius-*
color
,
*-color
--color-*
(目前未对齐——调色板循环是后续功能)
当令牌与当前值匹配时,组件会显示其名称(例如
16px · md
),按下回车键会输出
Set \
padding` to `var(--spacing-md)``而非原始像素值。用户仍可输入数字切换为任意像素值。
你无需在幻灯片上指定
scale
——它会根据
property
自动检测。传递
scale: null
可禁用该幻灯片的对齐,或传递
scale: "spacing" | "text" | "radius" | "color"
进行覆盖。传递
tokens: [{ name, value, numeric }]
可完全覆盖自动发现的令牌。依赖令牌对齐时请使用
unit: "px"
(运行时会应用令牌的原始值,因此无论rem/em令牌如何都能正确解析)。

Step 3 — Mark Target Element

步骤3——标记目标元素

Add
data-budge-target
to the changed element in source:
jsx
<div data-budge-target style={{ paddingTop: '16px' }}>
在源代码中为修改后的元素添加
data-budge-target
jsx
<div data-budge-target style={{ paddingTop: '16px' }}>

Step 4 — Activate

步骤4——激活

Use
StrReplace
to add a config element to
app/layout.tsx
inside
<body>
, passing the slides as JSON:
tsx
<div data-budge={JSON.stringify({ slides: [
  { 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" },
] })} hidden />
使用
StrReplace
将配置元素添加到
app/layout.tsx
<body>
内部,将幻灯片作为JSON传递:
tsx
<div data-budge={JSON.stringify({ slides: [
  { 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" },
] })} hidden />

Step 5 — Complete

步骤5——完成

Your turn is done. Do NOT open a browser, verify the panel, or wait for the user. Next.js HMR delivers the change.
Tell the user: "I've changed X to Y. Use ↑↓ to fine-tune, ←→ to switch properties."
When the user pastes the submitted prompt, it reads as a normal edit instruction — make the edit and remove the
data-budge
config element.
你的操作已完成。 请勿打开浏览器、验证面板或等待用户。Next.js HMR会推送修改。
告知用户:“我已将X修改为Y。使用↑↓进行微调,←→切换属性。”
当用户粘贴提交的提示时,将其视为常规编辑指令——执行修改并移除
data-budge
配置元素。