Generate beautiful, distinctive HTML/CSS/JS control panels for MATLAB uihtml components. 8 built-in styles (Clean, Material, Cosmic Dark, Neumorphic, Dashboard Light, Midnight Gradient, Minimal Mono, Warm Dark) plus custom aesthetics. Produces production-grade UI with sliders, buttons, toggles, and panels. Use when building visually polished MATLAB app UIs with uihtml.
npx skills add https://github.com/matlab/agent-skills-playground --skill matlab-uihtml-design
Generate production-grade HTML/CSS/JS control panels for MATLAB uihtml components with distinctive, configurable visual styles.
uihtmluihtml controlsBuilt-in styles are documented in references/design-styles.md. To apply a style:
references/styles/<name>.md start "" "<skill-directory>/assets/style-gallery.html" # Windows
open "<skill-directory>/assets/style-gallery.html" # macOS
Then ask: "I've opened the style gallery in your browser. Which style would you like? You can also describe a custom aesthetic."
The gallery shows interactive previews of all 8 built-in styles with a Dark/Light toggle. The available styles are:
| Style | Vibe |
|-------|------|
| Clean | Frosted glass, depth layers, spring animations |
| Material | Tonal surfaces, elevation, rounded shapes |
| Cosmic Dark | Deep space, neon glow, glassmorphism |
| Neumorphic Dark | Embossed/debossed, soft shadow pairs |
| Dashboard Light | White cards, indigo accent, data-dense |
| Midnight Gradient | Blue-to-purple gradients, luxury glow |
| Minimal Mono | Ultra-flat, pill buttons, single accent |
| Warm Dark | Amber/yellow accent, friendly, smart home |
If the user says "just pick one" or wants to move fast, default to Clean.
Each style reference follows the 9-section DESIGN.md format and provides complete specifications for colors, typography, components, motion, and guardrails.
Before generating code, commit to a clear aesthetic direction:
Execute the chosen direction with precision. Bold maximalism and refined minimalism both work, as long as the choice is intentional.
setup(htmlComponent) boilerplate; defer full MATLAB-side wiring to the matlab-uihtml-app-builder skillAll styles use CSS custom properties for theming. The base architecture:
:root {
/* Semantic colors, filled by chosen style */
--color-bg-primary: ...;
--color-bg-secondary: ...;
--color-bg-surface: ...;
--color-accent: ...;
--color-accent-hover: ...;
--color-text-primary: ...;
--color-text-secondary: ...;
--color-border: ...;
/* Spacing */
--space-xs: 4px;
--space-sm: 8px;
--space-md: 16px;
--space-lg: 24px;
/* Typography */
--font-family: ...;
--font-size-sm: ...;
--font-size-md: ...;
--font-size-lg: ...;
/* Radii & Shadows */
--radius-sm: ...;
--radius-md: ...;
--shadow-sm: ...;
--shadow-md: ...;
/* Motion */
--transition-fast: ...;
--transition-med: ...;
}
Support both light and dark modes via prefers-color-scheme media query or a data-theme attribute on <html>:
@media (prefers-color-scheme: dark) { ... }
/* or */
[data-theme="dark"] { ... }
uihtml containers in MATLAB apps are often height-constrained (e.g., a narrow side panel). When applying any style:
overflow: hidden is set on the body, clipped controls are invisible and unusableWhen the control set genuinely can't be compacted further (4+ panels, mixed sliders + toggles + buttons), make the panel container scroll instead of clipping. Keep body non-scrolling so the background gradient stays anchored, and let the inner .app (or whatever you named the flex column) scroll:
html, body {
overflow: hidden; /* body never scrolls; background gradient stays put */
}
.app {
height: 100%;
overflow-y: auto;
overflow-x: hidden;
scrollbar-width: thin; /* Firefox */
scrollbar-color: rgba(255, 255, 255, 0.12) transparent; /* Firefox */
}
/* Chromium (uihtml uses CEF/Chromium) */
.app::-webkit-scrollbar { width: 6px; }
.app::-webkit-scrollbar-track { background: transparent; }
.app::-webkit-scrollbar-thumb {
background: rgba(255, 255, 255, 0.10);
border-radius: 3px;
transition: background var(--t-fast);
}
.app::-webkit-scrollbar-thumb:hover { background: var(--accent-glow); }
Adapt the colors to the chosen palette:
| Style | Thumb default | Thumb hover |
|---|---|---|
| Dark styles (Cosmic Dark, Midnight, Neumorphic, Warm Dark, Minimal Mono) | rgba(255,255,255,0.10) | var(--accent-glow) |
| Light styles (Clean, Dashboard Light, Material light mode) | rgba(0,0,0,0.12) | rgba(0,0,0,0.22) or var(--accent) |
Keep the scrollbar 6px wide and the thumb under 20% alpha; anything heavier breaks the style. Don't show track borders or arrows.
These are cross-cutting rules that apply on top of whatever style is chosen. They exist to keep generated control panels from reading as "AI made that." A named built-in style that deliberately uses one of these moves as its identity (Cosmic Dark's neon glow, Midnight Gradient's blue-to-purple, Clean's glass) is intentional *voice* and is fine. The guardrails target the unconscious reflex of reaching for these on every panel.
font-variant-numeric: tabular-nums so the width doesn't jitter as digits change while dragging.@media (prefers-reduced-motion: reduce) fallback, typically a crossfade or an instant state change. Include this in the template's <style> block: @media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
uihtml (a headless Chromium/CEF render) a transition that never fires ships the panel blank. --ease-out-quart: cubic-bezier(0.25, 1, 0.5, 1); /* smooth */
--ease-out-quint: cubic-bezier(0.22, 1, 0.36, 1); /* snappier */
--ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1); /* decisive */
A subtle spring/compression on a control *press* is fine; a bouncy elastic entrance applied uniformly to every panel is a tell.
transform / opacity / filter, not layout properties (width, height, top, margin).uihtml panels frequently set overflow: hidden or overflow: auto (see Scrollable Panels above), a position: absolute menu inside them is cut off. The reliable fix across uihtml's embedded Chromium is position: fixed with coordinates computed from the trigger's getBoundingClientRect() (flip above / left when near a viewport edge). Native <dialog> + showModal() (top layer) also escapes clipping. The Popover API and CSS anchor positioning are cleaner but need a recent Chromium. Only rely on them if you've confirmed the installed MATLAB's uihtml renderer supports them; otherwise fall back to position: fixed.:focus-visible state for keyboard users: ≥3:1 against adjacent colors, 2–3px, offset *outside* the element. A box-shadow ring or outline + outline-offset both work; never ship outline: none with no replacement.999 / 9999.Every control needs its states designed, not just the default. Keyboard users never see :hover, so focus is separate from hover and is not optional.
| State | Applies to | Treatment |
|---|---|---|
| Default / hover / active | all controls | base; subtle lift or color shift on hover; press feedback (e.g. transform: scale(0.97)) on active |
| Focus | all controls | visible :focus-visible ring per the rule above |
| Disabled | buttons, inputs | reduced opacity, cursor: not-allowed, no hover response |
| Loading / busy | actions that call MATLAB | spinner, pulse, or a busy-styled button; a long MATLAB op (>~1s) should show progress and stay cancellable |
| Error / success | status feedback | color plus an icon or text message, never color alone |
Loading / error / success are usually driven from the MATLAB backend; see matlab-uihtml-app-builder for the event wiring (e.g. SimComplete / SimError, busy-button state machine).
If you're about to write any of these, restructure instead:
/* ❌ all of these render the same orange side-stripe */
.panel { border-left: 4px solid var(--accent); } /* the obvious one */
.panel { border-inline-start: 3px solid var(--accent); } /* logical-property alias */
.panel { box-shadow: inset 4px 0 0 var(--accent); } /* inset shadow, no `border-left` in sight */
.panel { border-width: 1px 1px 1px 4px; border-color: … var(--accent); } /* asymmetric border widths */
.panel::before { content: ''; position: absolute; left: 0; width: 4px; height: 100%; background: var(--accent); }
/* ✅ mark state another way */
.panel[data-state="active"] { border: 1px solid var(--accent); } /* full hairline border */
.panel[data-state="active"] { background: var(--accent-soft); } /* an ~8% accent wash, defined as a token */
.panel[data-state="active"] .title::before { content: '● '; color: var(--accent); } /* leading glyph */
Rule of thumb: any left/right border wider than 1px, or any accent-colored fill narrower than ~8px running the full height of one edge, is a side-stripe. Rewrite it.
background-clip: text over a gradient. Emphasize with weight, size, or a single solid color.box-shadow (blur ≥16px) on the same element. Pick one: a defined border, or a shadow at ≤8px blur.border-radius ≥32px on panels or inputs. Panels top out around 12–16px; full-pill radius is only for tags and buttons.Panel text is part of the design. Slop in a label or a status line reads as "AI made that" as loudly as a side-stripe does. These are engineer-facing MATLAB tools, so write like the product does: declarative, plain, and trusting the reader's competence.
MATLAB-driven status text (wired in matlab-uihtml-app-builder) follows the same rules: the string that MATLAB sends to a status line is microcopy too.
uihtml container sizes; use flexbox/grid with relative unitssetup(htmlComponent) function pattern:function setup(htmlComponent) {
window.htmlComponent = htmlComponent;
// Listen for events from MATLAB
htmlComponent.addEventListener("EventName", function(event) {
// Handle event.Data
});
// Send events to MATLAB
htmlComponent.sendEventToMATLAB("EventName", { key: value });
}
SetTheme event. The MATLAB side can detect the desktop theme and push it to the HTML component. The settings path is R2025a+, so wrap it in try/catch with a sensible default so the app still works on older releases:% Detect MATLAB desktop theme (R2025a+); fall back to a default on older releases
themeStr = 'dark'; % or 'light', whichever the style is designed for
try
s = settings;
themeStr = lower(char(s.matlab.appearance.MATLABTheme.ActiveValue));
catch
% settings.matlab.appearance not available on this release; keep the default
end
sendEventToHTMLSource(htmlComp, "SetTheme", struct("theme", themeStr));
The HTML setup() function already includes a SetTheme listener that sets data-theme on the root element, triggering the CSS variable swap.
-apple-system, 'Segoe UI', system-ui, sans-serif) is a legitimate, fast, offline-safe default. The built-in templates use one, and it's the right call for control panels. What reads as "AI made that" is reaching for a *distinctive-but-overused* display face for personality: Inter, Roboto, Geist, Space Grotesk, Plus Jakarta Sans, Fraunces (and plain Arial). Avoid those. If you pair fonts, pair on a real contrast axis (serif + sans); don't pair two similar sans-serifs. Also avoid purple-on-white cliches and cookie-cutter layouts; see the refuse-and-rewrite list in Design Guardrails above<a href="…" target="_blank" rel="noopener"> opens in the system default browser from uihtml, not inside the MATLAB figure. Useful for "view docs / view source" links in the app header. Style the link to fit the palette (accent color on hover, no underline by default): .external-link {
color: var(--text-secondary);
text-decoration: none;
transition: color var(--t-fast), text-shadow var(--t-fast);
}
.external-link:hover {
color: var(--accent-secondary);
text-shadow: 0 0 8px var(--accent-glow); /* dark styles */
}
Toolkit for styling artifacts with a theme. These artifacts can be slides, docs, reportings, HTML landing pages, etc. There are 10 pre-set themes with colors/fonts that you can apply to any artifact that has been creating, or can generate a new theme on-the-fly.
Applies Anthropic's official brand colors and typography to any sort of artifact that may benefit from having Anthropic's look-and-feel. Use it when brand colors or style guidelines, visual formatting, or company design standards apply.
Suite of tools for creating elaborate, multi-component claude.ai HTML artifacts using modern frontend web technologies (React, Tailwind CSS, shadcn/ui). Use for complex artifacts requiring state management, routing, or shadcn/ui components - not for simple single-file HTML/JSX artifacts.
Suite of tools for creating elaborate, multi-component claude.ai HTML artifacts using modern frontend web technologies (React, Tailwind CSS, shadcn/ui). Use for complex artifacts requiring state management, routing, or shadcn/ui components - not for simple single-file HTML/JSX artifacts.
Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
Guidance for distinctive, intentional visual design when building new UI or reshaping an existing one. Helps with aesthetic direction, typography, and making choices that don't read as templated defaults.
Set up Tailwind CSS v4 in Expo with react-native-css and NativeWind v5 for universal styling
Use Expo DOM components to run web code in a webview on native and as-is on web. Migrate web code to native incrementally.
Take matlab/matlab-uihtml-design from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.