algorithmic-color-pale…
Derive a full UI colour palette algorithmically from one or two brand colours. Darker and lighter variants for interactive states, desaturated greys from the…
Every interactive element needs a complete set of visual states — rest, hover, active/pressed, focus, disabled, and loading. States should be derived algorithmically from the base colour, not chosen arbitrarily. Use when designing buttons, links, inputs, or any clickable
$ npx -y skills add dembrandt/dembrandt-skills --skill button-states --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/button-statesContext preview
The summary Claude sees to decide when to auto-load this skill.
Every interactive element needs a complete set of visual states — rest, hover, active/pressed, focus, disabled, and loading. States should be derived algorithmically from the base colour, not chosen arbitrarily. Use when designing buttons, links, inputs, or any clickable
name: button-states
description: Every interactive element needs a complete set of visual states — rest, hover, active/pressed, focus, disabled, and loading. States should be derived algorithmically from the base colour, not chosen arbitrarily. Use when designing buttons, links, inputs, or any clickable component.
metadata:
priority: 8
pathPatterns:
- "components/**"
- "src/components/**"
- "**/*.css"
- "**/*.scss"
- "**/tokens/**"
- "**/*.tsx"
- "**/*.jsx"
- "design-system/**"
promptSignals:
phrases:
- "hover state"
- "active state"
- "focus state"
- "disabled"
- "button states"
- "interactive states"
- "loading state"
- "pressed"
retrieval:
aliases:
- button states
- hover state
- interactive states
- focus ring
- disabled state
- loading button
intents:
- design button states
- add hover and active states
- style focus ring
- handle disabled state
- add loading state to button
examples:
- what colour should the hover state be
- design all states for this button
- how do I show a loading state on a button
- make the focus ring visibleEvery interactive component must have a complete, visually distinct state for each interaction mode. Missing or ambiguous states make the UI feel unfinished and reduce user confidence.
| State | Trigger | Visual signal | |---|---|---| | **Rest** | Default | Base colour, cursor: pointer | | **Hover** | Mouse over | Slightly darker, subtle background shift | | **Active / Pressed** | Mouse down / tap | Noticeably darker, slight scale-down | | **Focus** | Keyboard navigation | Visible focus ring, no change to fill | | **Disabled** | Not available | Low contrast, cursor: not-allowed, no interaction | | **Loading** | Async action in progress | Spinner or pulse, non-interactive |
State colours are not chosen independently — they are derived from the base colour by adjusting lightness in HSL. This guarantees coherence across the entire palette.
base: hsl(H, S%, L%) hover: hsl(H, S%, L% - 8%) ← darken 8% active: hsl(H, S%, L% - 14%) ← darken 14%
.btn-primary {
background: hsl(243, 100%, 68%); /* rest #635BFF */
}
.btn-primary:hover {
background: hsl(243, 100%, 60%); /* hover #4A40FF */
}
.btn-primary:active {
background: hsl(243, 100%, 54%); /* active #3429FF */
}For light buttons on dark backgrounds, invert the logic — lighten on hover instead of darkening.
.btn-secondary {
background: transparent;
border: 1px solid var(--color-border);
color: var(--color-text);
}
.btn-secondary:hover {
background: var(--color-grey-100); /* subtle fill */
border-color: var(--color-grey-300);
}
.btn-secondary:active {
background: var(--color-grey-200);
}Focus is a keyboard navigation requirement (WCAG 2.2). It must be visible and must not rely on the hover style alone — keyboard users do not trigger hover.
.btn:focus-visible {
outline: 2px solid var(--color-primary);
outline-offset: 3px;
}.btn:disabled,
.btn[aria-disabled="true"] {
opacity: 0.4;
cursor: not-allowed;
pointer-events: none;
}When a button triggers an async action, replace the label with a spinner and prevent re-submission.
.btn--loading {
pointer-events: none;
cursor: wait;
opacity: 0.7;
}A subtle scale-down on press adds physical feedback — borrowed from Disney's squash principle.
.btn:active {
transform: scale(0.97);
transition: transform 80ms ease-out;
}Keep the scale value between `0.95–0.98`. Below `0.95` feels like the button is breaking.
.btn {
cursor: pointer;
background: var(--color-primary);
color: white;
border-radius: var(--radius-button);
padding: var(--component-padding-y-md) var(--component-padding-x-md);
height: var(--component-height-md);
border: none;
transition: background 120ms ease-out, transform 80ms ease-out;
}
.btn:hover { background: var(--color-primary-hover); }
.btn:active { background: var(--color-primary-active); transform: scale(0.97); }
.btn:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 3px; }
.btn:disabled { opacity: 0.4; cursor: not-allowed; pointer-events: none; }
.btn.btn--loading { opacity: 0.7; cursor: wait; pointer-events: none; }UX and design-system skills for AI agents. Install once, and your agent knows how to design. --all installs every skill at once. They load only when a prompt needs them, so there is no runtime cost to having them all. Want to pick by hand?
Repo: dembrandt/dembrandt-skills
Derive a full UI colour palette algorithmically from one or two brand colours. Darker and lighter variants for interactive states, desaturated greys from the…
The persistent shell around an application — the top bar, the app launcher, the tenant and environment cue, and in heavy tools a status bar. In an estate of…
Product visuals — hero shots, demos, screenshots, landing-page panels — must reproduce the real product, not a stylised poster of it. Design with real content…
A brand's visual tone — playful or serious, rounded or angular — should be consistent across all UI elements. Shape language in typography, border-radius, and…
Rebuild an existing web page 1:1 from measurement instead of by eye — into Figma, Penpot, or code. Captures the rendered page, the raw source and the computed…
Choose light, dark, or combined color mode deliberately based on brand tone and user context. Offer a theme selector only when user control genuinely matters —…