← All UI styles
Candy Gloss
Glossy pill buttons with a highlight across the top, in flavors rather than colors.
Aqua gelexpressiveCasual gamesKids productsRewards and loyalty
Construction · Aqua gel
Controls look wet: a hard gloss cut across the top half, a bloom returning from the bottom, and a capsule shape throughout.
Every style renders this same screen, so the only thing changing between two of them is the style. The component above is the file below, running.
Prompt
Design this interface in the Candy Gloss style. Controls are glossy pills with a light band across the upper half, colored like sweets. Every interactive element looks pressable and slightly wet. Build every surface the Aqua gel way: Controls look wet: a hard gloss cut across the top half, a bloom returning from the bottom, and a capsule shape throughout. Use exactly these values: background #fff1f7, surfaces #ffffff, text #2a1522, secondary text #6b4f5e, accent #d81b60 with #ffffff on it; corner radius 999/999/999px; no borders and no separators at all; inset highlights and shading, as if the surface were pressed; system-ui for body at 15px, line height 1.45; 4px spacing grid, regular spacing. Never: square corners; flat matte fills; dark neutral palettes; hairline borders. Dark mode uses background #1a0f16, surfaces #241621, text #fdeef5, accent #ff77aa — the same style, not an inverted one.
The numbers in this prompt are printed from the tokens below, so it cannot drift from what the specimen renders.
What carries the look
- glossy pill controls
- highlight band across the top
- candy colors
- everything looks pressable
What this style refuses
- square corners
- flat matte fills
- dark neutral palettes
- hairline borders
The refusals are the half that keeps generated interfaces from converging — a prompt that only says what to add gets the default look.
Tokens
Palette
RoleLightDark
Background
#fff1f7#1a0f16Surface
#ffffff#241621Border
#f3d3e2#41293aText
#2a1522#fdeef5Muted text
#6b4f5e#c39cb0Accent
#d81b60#ff77aaOn accent
#ffffff#2b0715Shape and type
Radius999 / 999 / 999 px
Bordernone
Shadowinset
DisplayTrebuchet MS
Bodysystem-ui
Monoui-monospace
Type scale11 · 13 · 15 · 17 · 22 · 32 px
Weights500 / 700 / 800
Line height1.45
Tracking0em
Spacing4px grid · regular
Surfacetinted
Accentfilled
Separatornone
Labelssentence case
Blurnone
Measured contrast — body 15.61:1 light, 16.66:1 dark; secondary text 6.6:1 and 7.74:1. Every pair clears WCAG AA in both themes, checked on each build.
Specimen · Specimen.tsx
import type { CSSProperties } from "react";
/**
* Vibary · Candy Gloss
*
* Glossy pill buttons with a highlight across the top, in flavors rather than colors.
*
* One complete product screen, rendered from the token object below —
* the same screen every other Vibary specimen renders, so the style
* is the only variable. Self-contained: React only, no CSS file, no
* assets, no chart library.
*
* `theme` defaults to following the system setting; pass "light" or
* "dark" to pin one.
*/
export const TOKENS = {
"material": "aqua-gel",
"color": {
"light": {
"bg": "#fff1f7",
"surface": "#ffffff",
"border": "#f3d3e2",
"text": "#2a1522",
"muted": "#6b4f5e",
"accent": "#d81b60",
"accentText": "#ffffff"
},
"dark": {
"bg": "#1a0f16",
"surface": "#241621",
"border": "#41293a",
"text": "#fdeef5",
"muted": "#c39cb0",
"accent": "#ff77aa",
"accentText": "#2b0715"
}
},
"radius": {
"sm": 999,
"md": 999,
"lg": 999,
"pill": 999
},
"border": {
"width": 0,
"style": "none"
},
"shadow": {
"level": "inset",
"value": "inset 0 1px 0 rgba(255, 255, 255, 0.5), inset 0 -1px 0 rgba(0, 0, 0, 0.12)"
},
"type": {
"family": {
"display": "\"Trebuchet MS\", \"Segoe UI\", Tahoma, Verdana, sans-serif",
"body": "system-ui, -apple-system, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif",
"mono": "ui-monospace, \"SF Mono\", Menlo, Consolas, \"Liberation Mono\", monospace"
},
"scale": [
11,
13,
15,
17,
22,
32
],
"weight": {
"body": 500,
"strong": 700,
"display": 800
},
"lineHeight": 1.45,
"tracking": 0
},
"space": {
"unit": 4,
"density": "regular"
},
"effects": {
"surface": "tinted",
"accentStyle": "filled",
"separator": "none",
"labelCase": "none",
"blur": 0
}
};
type Palette = typeof TOKENS.color.light;
export type CandyGlossSpecimenProps = {
theme?: "system" | "light" | "dark";
/** Scopes the custom properties; only matters if you render two. */
scope?: string;
};
function vars(palette: Palette): string {
return [
`--sp-bg: ${palette.bg}`,
`--sp-surface: ${palette.surface}`,
`--sp-border: ${palette.border}`,
`--sp-text: ${palette.text}`,
`--sp-muted: ${palette.muted}`,
`--sp-accent: ${palette.accent}`,
`--sp-accent-text: ${palette.accentText}`,
].join("; ");
}
/** Fixed content: identical in every specimen, on purpose. */
const NAV: readonly { label: string; path: string }[] = [
{ label: "Overview", path: "M3 9.5 9 4.5l6 5V15a1 1 0 0 1-1 1h-2.5v-4h-5v4H4a1 1 0 0 1-1-1z" },
{ label: "Orders", path: "M4 5h10l-1 9H5zM7 5V3.5h4V5" },
{ label: "Customers", path: "M9 9a2.6 2.6 0 1 0 0-5.2A2.6 2.6 0 0 0 9 9M3.6 15.4c0-2.4 2.4-3.8 5.4-3.8s5.4 1.4 5.4 3.8" },
{ label: "Reports", path: "M4.5 15V8M9 15V4.5M13.5 15v-4.5" },
{ label: "Settings", path: "M9 11.4A2.4 2.4 0 1 0 9 6.6a2.4 2.4 0 0 0 0 4.8M9 2.6v1.4M9 14v1.4M15.4 9H14M4 9H2.6M13.5 4.5l-1 1M5.5 12.5l-1 1M13.5 13.5l-1-1M5.5 5.5l-1-1" },
];
const STATS: readonly { label: string; value: string; delta: string; up: boolean }[] = [
{ label: "Revenue", value: "$48,290", delta: "+12.4%", up: true },
{ label: "Orders", value: "1,284", delta: "+3.1%", up: true },
{ label: "Refunds", value: "42", delta: "-1.8%", up: false },
];
const BARS: readonly { day: string; value: number }[] = [
{ day: "M", value: 0.42 },
{ day: "T", value: 0.61 },
{ day: "W", value: 0.38 },
{ day: "T", value: 0.74 },
{ day: "F", value: 0.93 },
{ day: "S", value: 0.55 },
{ day: "S", value: 0.29 },
];
const ROWS: readonly { name: string; meta: string; state: string; amount: string }[] = [
{ name: "Kyoto Print Co.", meta: "Invoice 2841", state: "Paid", amount: "420.00" },
{ name: "Aurora Supply", meta: "Invoice 2839", state: "Pending", amount: "186.50" },
{ name: "Northwind Studio", meta: "Invoice 2836", state: "Overdue", amount: "678.00" },
];
const SWITCHES: readonly { label: string; on: boolean }[] = [
{ label: "Auto-pay invoices", on: true },
{ label: "Email receipts", on: false },
];
/**
* The material: how this style paints an element, as opposed to what
* color it paints it. This is the part that makes Aqua gel
* a different design language rather than a different theme —
* Controls look wet: a hard gloss cut across the top half, a bloom returning from the bottom, and a capsule shape throughout.
*/
const MATERIAL = {
"surface": {
"background": "linear-gradient(180deg, color-mix(in srgb, #ffffff 60%, transparent) 0%, color-mix(in srgb, #ffffff 10%, transparent) 48%, transparent 50%), linear-gradient(180deg, var(--sp-surface) 0%, color-mix(in srgb, var(--sp-accent) 10%, var(--sp-surface)) 100%)",
"boxShadow": "inset 0 1px 0 color-mix(in srgb, #ffffff 85%, transparent), 0 3px 8px -3px color-mix(in srgb, #000000 35%, transparent)",
"border": "1px solid color-mix(in srgb, #000000 14%, transparent)"
},
"button": {
"background": "linear-gradient(180deg, color-mix(in srgb, #ffffff 75%, transparent) 0%, color-mix(in srgb, #ffffff 18%, transparent) 47%, transparent 49%), linear-gradient(180deg, color-mix(in srgb, #ffffff 12%, var(--sp-accent)) 0%, color-mix(in srgb, #000000 18%, var(--sp-accent)) 100%)",
"color": "var(--sp-accent-text)",
"boxShadow": "inset 0 1px 0 color-mix(in srgb, #ffffff 90%, transparent), inset 0 -6px 10px -6px color-mix(in srgb, #ffffff 60%, transparent), 0 2px 5px color-mix(in srgb, #000000 30%, transparent)",
"border": "1px solid color-mix(in srgb, #000000 26%, transparent)"
},
"switchOn": {
"background": "linear-gradient(180deg, color-mix(in srgb, #ffffff 50%, transparent) 0%, transparent 50%), var(--sp-accent)",
"boxShadow": "inset 0 1px 0 color-mix(in srgb, #ffffff 70%, transparent), inset 0 -3px 6px -3px color-mix(in srgb, #ffffff 50%, transparent)",
"border": "1px solid color-mix(in srgb, #000000 22%, transparent)"
},
"switchOff": {
"background": "linear-gradient(180deg, color-mix(in srgb, #ffffff 45%, transparent) 0%, transparent 50%), color-mix(in srgb, var(--sp-text) 15%, var(--sp-surface))",
"boxShadow": "inset 0 1px 0 color-mix(in srgb, #ffffff 55%, transparent)",
"border": "1px solid color-mix(in srgb, #000000 18%, transparent)"
},
"knob": {
"background": "radial-gradient(circle at 50% 30%, #ffffff 0%, color-mix(in srgb, #ffffff 70%, transparent) 60%, color-mix(in srgb, #ffffff 35%, transparent) 100%)",
"boxShadow": "0 1px 3px color-mix(in srgb, #000000 40%, transparent)"
},
"navActive": {
"background": "linear-gradient(180deg, color-mix(in srgb, #ffffff 55%, transparent) 0%, transparent 50%), color-mix(in srgb, var(--sp-accent) 30%, var(--sp-surface))",
"boxShadow": "inset 0 1px 0 color-mix(in srgb, #ffffff 70%, transparent), 0 1px 2px color-mix(in srgb, #000000 20%, transparent)"
},
"bar": {
"background": "linear-gradient(180deg, color-mix(in srgb, #ffffff 65%, transparent) 0%, color-mix(in srgb, #ffffff 12%, transparent) 46%, transparent 48%), var(--sp-accent)",
"boxShadow": "inset 0 1px 0 color-mix(in srgb, #ffffff 80%, transparent), 0 1px 3px color-mix(in srgb, #000000 25%, transparent)",
"border": "1px solid color-mix(in srgb, #000000 20%, transparent)"
}
};
const SURFACE_BORDER = "none";
const ROW_SEPARATOR = "none";
const RING = 0.68;
export function CandyGlossSpecimen({ theme = "system", scope = "sp-candy-gloss" }: CandyGlossSpecimenProps) {
const css =
theme === "light"
? `.${scope}{${vars(TOKENS.color.light)}}`
: theme === "dark"
? `.${scope}{${vars(TOKENS.color.dark)}}`
: `.${scope}{${vars(TOKENS.color.light)}}@media(prefers-color-scheme:dark){.${scope}{${vars(TOKENS.color.dark)}}}`;
const label: CSSProperties = {
font: `${TOKENS.type.weight.strong} ${TOKENS.type.scale[0]}px ${TOKENS.type.family.body}`,
letterSpacing: `${TOKENS.type.tracking}em`,
textTransform: "none",
color: "var(--sp-muted)",
};
const meta: CSSProperties = {
font: `${TOKENS.type.weight.body} ${TOKENS.type.scale[0]}px ${TOKENS.type.family.body}`,
color: "var(--sp-muted)",
};
const card: CSSProperties = {
...MATERIAL.surface,
borderRadius: TOKENS.radius.md,
padding: 15,
};
const heading: CSSProperties = {
font: `${TOKENS.type.weight.strong} ${TOKENS.type.scale[2]}px ${TOKENS.type.family.display}`,
textTransform: "none",
letterSpacing: "0",
};
const primary: CSSProperties = { ...MATERIAL.button, borderRadius: TOKENS.radius.sm };
const pill = (active: boolean): CSSProperties => ({
padding: "2px 8px",
borderRadius: TOKENS.radius.pill,
background: active
? "var(--sp-accent)"
: "color-mix(in srgb, var(--sp-text) 10%, transparent)",
color: active ? "var(--sp-accent-text)" : "var(--sp-muted)",
font: `${TOKENS.type.weight.strong} ${TOKENS.type.scale[0]}px ${TOKENS.type.family.body}`,
textTransform: "none",
letterSpacing: "0",
});
return (
<div
className={scope}
style={{
width: 760,
display: "flex",
background: "linear-gradient(180deg, color-mix(in srgb, var(--sp-accent) 8%, var(--sp-bg)) 0%, var(--sp-bg) 46%)",
color: "var(--sp-text)",
font: `${TOKENS.type.weight.body} ${TOKENS.type.scale[1]}px/${TOKENS.type.lineHeight} ${TOKENS.type.family.body}`,
letterSpacing: `${TOKENS.type.tracking}em`,
overflow: "hidden",
position: "relative",
}}
>
<style>{css}</style>
{/* Sidebar */}
<div
style={{
width: 176,
flex: "none",
display: "flex",
flexDirection: "column",
gap: 4,
padding: 18,
borderRight: "1px solid var(--sp-border)",
background: "color-mix(in srgb, var(--sp-surface) 70%, transparent)",
}}
>
<div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 14 }}>
<span
style={{
width: 22,
height: 22,
borderRadius: TOKENS.radius.sm,
background: "var(--sp-accent)",
display: "grid",
placeItems: "center",
color: "var(--sp-accent-text)",
font: `${TOKENS.type.weight.display} ${TOKENS.type.scale[0]}px ${TOKENS.type.family.display}`,
}}
>
N
</span>
<span
style={{
font: `${TOKENS.type.weight.display} ${TOKENS.type.scale[2]}px ${TOKENS.type.family.display}`,
textTransform: "none",
letterSpacing: "0",
}}
>
Northwind
</span>
</div>
{NAV.map((item, index) => (
<span
key={item.label}
style={{
display: "flex",
alignItems: "center",
gap: 9,
height: 34,
padding: "0 9px",
borderRadius: TOKENS.radius.sm,
...(index === 0 ? MATERIAL.navActive : null),
color: index === 0 ? "var(--sp-accent)" : "var(--sp-muted)",
font: `${index === 0 ? TOKENS.type.weight.strong : TOKENS.type.weight.body} ${TOKENS.type.scale[1]}px ${TOKENS.type.family.body}`,
textTransform: "none",
letterSpacing: "0",
}}
>
<svg width="17" height="17" viewBox="0 0 18 18" fill="none" aria-hidden="true">
<path
d={item.path}
stroke="currentColor"
strokeWidth={index === 0 ? 1.7 : 1.3}
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
{item.label}
</span>
))}
<span style={{ flex: 1 }} />
<span
style={{
display: "flex",
alignItems: "center",
gap: 8,
paddingTop: 14,
borderTop: "1px solid var(--sp-border)",
}}
>
<span
style={{
width: 26,
height: 26,
flex: "none",
display: "grid",
placeItems: "center",
borderRadius: TOKENS.radius.pill,
background: "color-mix(in srgb, var(--sp-text) 12%, transparent)",
font: `${TOKENS.type.weight.strong} ${TOKENS.type.scale[0]}px ${TOKENS.type.family.body}`,
}}
>
MK
</span>
<span style={{ minWidth: 0 }}>
<span style={{ display: "block", font: `${TOKENS.type.weight.strong} ${TOKENS.type.scale[0]}px ${TOKENS.type.family.body}` }}>
Mika Ito
</span>
<span style={{ ...meta, display: "block" }}>Finance</span>
</span>
</span>
</div>
{/* Main */}
<div
style={{
flex: 1,
minWidth: 0,
display: "flex",
flexDirection: "column",
gap: 14,
padding: 18,
}}
>
{/* Header */}
<div style={{ display: "flex", alignItems: "center", gap: 10 }}>
<span style={{ flex: 1, minWidth: 0 }}>
<span style={{ ...label, display: "block" }}>March 2026</span>
<span
style={{
display: "block",
font: `${TOKENS.type.weight.display} ${TOKENS.type.scale[4]}px ${TOKENS.type.family.display}`,
textTransform: "none",
letterSpacing: `${TOKENS.type.tracking}em`,
}}
>
Overview
</span>
</span>
<span
style={{
display: "flex",
alignItems: "center",
gap: 7,
padding: "7px 11px",
background: "var(--sp-surface)",
border: "1px solid var(--sp-border)",
borderRadius: TOKENS.radius.sm,
color: "var(--sp-muted)",
font: `${TOKENS.type.weight.body} ${TOKENS.type.scale[0]}px ${TOKENS.type.family.body}`,
}}
>
<svg width="13" height="13" viewBox="0 0 18 18" fill="none" aria-hidden="true">
<circle cx="8" cy="8" r="5.4" stroke="currentColor" strokeWidth="1.5" />
<path d="M12.4 12.4 16 16" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" />
</svg>
Search
</span>
<span
style={{
...primary,
padding: "8px 13px",
font: `${TOKENS.type.weight.strong} ${TOKENS.type.scale[0]}px ${TOKENS.type.family.body}`,
textTransform: "none",
letterSpacing: "0",
}}
>
New report
</span>
</div>
{/* Stats */}
<div style={{ display: "flex", gap: 14 }}>
{STATS.map((stat) => (
<div key={stat.label} style={{ ...card, flex: 1, minWidth: 0 }}>
<span style={{ ...label, display: "block" }}>{stat.label}</span>
<span
style={{
display: "block",
marginTop: 3,
fontVariantNumeric: "tabular-nums",
font: `${TOKENS.type.weight.display} ${TOKENS.type.scale[4]}px ${TOKENS.type.family.display}`,
}}
>
{stat.value}
</span>
<span style={{ display: "inline-flex", marginTop: 6, ...pill(stat.up) }}>
{stat.delta}
</span>
</div>
))}
</div>
{/* Chart + ring */}
<div style={{ display: "flex", gap: 14 }}>
<div style={{ ...card, flex: 1.6, minWidth: 0 }}>
<div style={{ display: "flex", alignItems: "baseline", justifyContent: "space-between" }}>
<span style={heading}>Revenue by day</span>
<span style={meta}>7 days</span>
</div>
<div
style={{
display: "flex",
alignItems: "flex-end",
gap: 7,
height: 92,
marginTop: 10,
}}
>
{BARS.map((bar, index) => (
<span key={index} style={{ flex: 1, display: "flex", flexDirection: "column", alignItems: "center", gap: 5 }}>
<span
style={{
width: "100%",
height: bar.value * 74,
borderRadius: `${TOKENS.radius.sm}px ${TOKENS.radius.sm}px 0 0`,
...(index === 4
? MATERIAL.bar
: {
background: "color-mix(in srgb, var(--sp-accent) 32%, var(--sp-surface))",
border: SURFACE_BORDER,
}),
}}
/>
<span style={meta}>{bar.day}</span>
</span>
))}
</div>
</div>
<div style={{ ...card, flex: 1, minWidth: 0, display: "flex", alignItems: "center", gap: 12 }}>
<span
style={{
width: 74,
height: 74,
flex: "none",
borderRadius: TOKENS.radius.pill,
display: "grid",
placeItems: "center",
background: `conic-gradient(var(--sp-accent) 0turn ${RING}turn, color-mix(in srgb, var(--sp-text) 12%, transparent) ${RING}turn 1turn)`,
}}
>
<span
style={{
width: 52,
height: 52,
borderRadius: TOKENS.radius.pill,
background: "var(--sp-surface)",
display: "grid",
placeItems: "center",
fontVariantNumeric: "tabular-nums",
font: `${TOKENS.type.weight.strong} ${TOKENS.type.scale[2]}px ${TOKENS.type.family.mono}`,
}}
>
68%
</span>
</span>
<span style={{ minWidth: 0 }}>
<span style={{ ...heading, display: "block" }}>Budget</span>
<span style={{ ...meta, display: "block", marginTop: 4 }}>Spent $34,120</span>
<span style={{ ...meta, display: "block" }}>Left $16,170</span>
</span>
</div>
</div>
{/* Table + controls */}
<div style={{ display: "flex", gap: 14 }}>
<div style={{ ...card, flex: 1.6, minWidth: 0, padding: 0, overflow: "hidden" }}>
<div
style={{
display: "flex",
alignItems: "center",
justifyContent: "space-between",
padding: `${15}px ${15}px 8px`,
}}
>
<span style={heading}>Recent orders</span>
<span style={{ color: "var(--sp-accent)", font: `${TOKENS.type.weight.strong} ${TOKENS.type.scale[0]}px ${TOKENS.type.family.body}` }}>
View all
</span>
</div>
{ROWS.map((row, index) => (
<div
key={row.name}
style={{
display: "flex",
alignItems: "center",
gap: 10,
height: 44,
padding: `0 ${15}px`,
borderTop: ROW_SEPARATOR,
}}
>
<span
style={{
width: 24,
height: 24,
flex: "none",
display: "grid",
placeItems: "center",
borderRadius: TOKENS.radius.sm,
background: "color-mix(in srgb, var(--sp-text) 9%, transparent)",
font: `${TOKENS.type.weight.strong} ${TOKENS.type.scale[0]}px ${TOKENS.type.family.mono}`,
}}
>
{row.name.slice(0, 1)}
</span>
<span style={{ flex: 1, minWidth: 0 }}>
<span style={{ display: "block", font: `${TOKENS.type.weight.strong} ${TOKENS.type.scale[1]}px ${TOKENS.type.family.body}` }}>
{row.name}
</span>
<span style={{ ...meta, display: "block" }}>{row.meta}</span>
</span>
<span style={pill(index === 0)}>{row.state}</span>
<span
style={{
width: 66,
textAlign: "right",
fontVariantNumeric: "tabular-nums",
font: `${TOKENS.type.weight.strong} ${TOKENS.type.scale[1]}px ${TOKENS.type.family.mono}`,
}}
>
{row.amount}
</span>
</div>
))}
</div>
<div style={{ ...card, flex: 1, minWidth: 0, display: "flex", flexDirection: "column", gap: 10 }}>
<span style={heading}>Preferences</span>
{SWITCHES.map((item) => (
<span key={item.label} style={{ display: "flex", alignItems: "center", gap: 10 }}>
<span style={{ flex: 1, minWidth: 0, font: `${TOKENS.type.weight.body} ${TOKENS.type.scale[0]}px ${TOKENS.type.family.body}` }}>
{item.label}
</span>
<span
style={{
width: 34,
height: 20,
flex: "none",
position: "relative",
borderRadius: TOKENS.radius.pill,
...(item.on ? MATERIAL.switchOn : MATERIAL.switchOff),
}}
>
<span
style={{
position: "absolute",
top: 3,
left: item.on ? 17 : 3,
width: 14,
height: 14,
borderRadius: TOKENS.radius.pill,
...MATERIAL.knob,
}}
/>
</span>
</span>
))}
<span style={{ marginTop: 2 }}>
<span style={{ display: "flex", justifyContent: "space-between" }}>
<span style={meta}>Alert threshold</span>
<span style={{ ...meta, fontVariantNumeric: "tabular-nums" }}>62%</span>
</span>
<span
style={{
display: "block",
position: "relative",
height: 5,
marginTop: 7,
borderRadius: TOKENS.radius.pill,
background: "color-mix(in srgb, var(--sp-text) 14%, transparent)",
}}
>
<span
style={{
position: "absolute",
inset: "0 38% 0 0",
borderRadius: TOKENS.radius.pill,
background: "var(--sp-accent)",
}}
/>
<span
style={{
position: "absolute",
top: -5,
left: "62%",
width: 15,
height: 15,
marginLeft: -7,
borderRadius: TOKENS.radius.pill,
background: "var(--sp-surface)",
border: `2px solid var(--sp-accent)`,
}}
/>
</span>
</span>
</div>
</div>
</div>
</div>
);
}
export default CandyGlossSpecimen;