Both inline their ramps from CUSTOM_PALETTES so exports stay
self-contained, and double as living tests of the new axes:
per-group button defaults (Cabin) and primary-shade shadows with a
dark-mode primary shade remap (Harbor).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Tokens gains a Primary section: light/dark sliders remapping
--ui-primary along the primary ramp (library defaults 500/400 added
to LIBRARY_TOKEN_DEFAULTS so at-default positions export nothing)
- shadow/border color selects gain 'Primary shade…' — the existing
per-mode shade sliders walk the primary ramp instead of neutral
- default variant select split per component group (Buttons/Cards/
Inputs); the app-wide value from presets/shuffle shows through as
the fallback until a group chooses its own
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- five studio palettes beyond tailwind (sand/sage/ash neutrals,
cocoa/marine primaries) defined in @theme static; exports inline
their ramps since consumer builds can't resolve them
- shuffle now rolls frames, border/shadow colors and app-wide
default variants at tasteful weights
- palette offsets get an effect-strength slider (0-200%) that lerps
between the fitted base and the offset target, extrapolating past
100% for stronger takes
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Color mode moves out of the accordion to UTabs pinned at the top of the
sidebar. Group panels are a single-open UAccordion (one section of the
studio in focus at a time), and the sub-section collapsibles become
ghost buttons with leading rotating chevrons. Shade options in the
color selects read 'Custom…'.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New settings:
- Defaults section: app-wide default variant and size, expanded into
per-component defaultVariants (the runtime channel Nuxt UI already
honors) only where the component supports the value — form fields
have no solid variant and keep their own default.
- Shadow geometry sliders (offset X/Y, blur, spread) driving CSS
variables referenced by one static class shape, plus an opacity
slider folded into the shadow color via color-mix with per-treatment
fallbacks (solid for custom, 25% for soft). 'Hard' renamed 'Custom'.
- Soft shadows now respect the color/shade options — tailwind's stock
shadow color is hardcoded black, and the bare shadow-(--var) form
parses as a shadow SIZE var; shadow-(color:--var) disambiguates.
- Sidebar groups (Colors/Style/Tokens/General) become a UAccordion with
leading chevrons, built-in separators and unpadded panels; the shade
option in both color selects is now labeled 'Custom…'.
Fixes:
- Studio prefs and palette params are restored on load again — the
useState conversion (for popover-reset clearing) lost the client
restore that useLocalStorage had provided; the FOUC plugin now
rehydrates both keys. The persisted style class bundle also
self-heals when the generator changes, so stale expanded classes
can't outlive their source.
- Layout: toolbar returns beside the sidebar atop the preview column
(with the sidebar toggle and Concept badge kept).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Correctness:
- Style class bundles move to their own channel (nuxt-ui-style-ui) and
compose with preset/AI overrides via class-concatenating mergeUi —
restyling can no longer destroy a preset's or the AI's component
overrides, and doc components + style expansion now merge identically
in live apply and exports (spread was dropping one side).
- resetTheme() clears ALL studio state (style prefs, style bundle,
palette params/prev, active preset) so the popover and chat reset
buttons no longer leave orphaned styles that resurrect on the next
click or leak invisible bundles into exports.
- tokenShades are per-mode optional: hydrating a dark-only preset token
no longer invents a light override that leaks into exports untouched.
- currentDoc references palettes by the alias's current value, so a
custom ramp shadowing a default name ('green') still exports.
- applyThemeSettings guards the neutral alias against the SANITIZED
palette set (a rejected palette could previously still be selected,
bricking every neutral token), and takes a track option so slider
drags stop emitting ~16 analytics events per second.
- Removing a custom palette restores the palette that preceded it
instead of the hardcoded default; neutral remaps skip tokens the
shade sliders own (no more two-writer flip-flops on --ui-bg).
- Palette editor: style offset resets to Fitted on reseed, watchIgnorable
scopes seed suppression to its own writes, self-applies no longer
round-trip through the echo watcher; theme-color meta follows the
neutral-50 baseline in light mode.
Perf: shade-only style edits skip the 7-component teardown/re-merge.
Cleanup: shared ThemeStudioShadeSlider component, SHADES/defaults single
sources, shared parseUiColorRef, token-keyed sections, dead exports and
never-shipped legacy paths (bgShade, anchor/vibrance) deleted, FOUC
plugin restores the style bundle with the same merge as the live path.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The Background pattern generalizes into a whitelist-driven tokenShades
map: Inverted, Highlighted, Muted and Dimmed each get their own
collapsible section with per-mode neutral-shade sliders (Background
open by default, the rest collapsed). Presets hydrate all of them via
the same token parser, and the legacy bgShade field folds in for
persisted sessions.
Pastel offset redefined per feedback: compress the lightness range from
both ends (light end down, dark end up) while RAISING chroma — candy
pastels instead of washed-out tints. Vivid/dazzling rebalanced, and the
lightness remap preserves the fitted curve's shape.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Page layout: the toolbar spans full width with the sidebar toggle next
to the title (badge now 'Concept'), and the settings panel sits under
the toolbar row. Every sidebar section collapses via its header.
Fixes the preset regression: setStyle only removes the tokens the
previous style emitted instead of blanket-clearing shared variable
names, so a preset's --ui-bg survives style clicks; and applyDoc now
derives bgShade from preset tokens where they are neutral-ramp refs, so
the background sliders reflect the preset instead of stale defaults.
Also restores the neutral palette editor's lost open binding.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Border color gains the same per-mode neutral-shade slider pair as
shadows, and a new Background section drives --ui-bg per mode the same
way (a token shorthand on the style axis until a full tokens editor
exists). The palette editor's trigger moves into the section header as a
Custom button, and 'Use this palette' is replaced by a style-offset
dropdown (Fitted/Pastel/Muted/Vivid/Dazzling) applying taste transforms
from the fitted base so repeated picks never compound.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replaces the fixed dark/medium gray options (clustered at the dark end)
with a 'Neutral shade' mode: two sliders choose any of the 11 neutral
ramp shades independently for light and dark mode, with live swatches.
Two single sliders rather than one dual-thumb range because the two
values are independent and may cross — a range slider enforces ordering.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Presets grow to nine with Art Deco (gilded amber lines via primary
border color), Marshmallow (pastel pink on mauve), Ghibli (custom moss
ramp on sun-warmed amber paper) and Marvel (comic red/blue with black
frames and hard shadows) — translated from shadcn studio's registry
values into ThemeDoc form, each composing the new style axes rather
than bespoke component hacks.
The sidebar gets compact: primary/neutral collapse into popover swatch
rows with live color dots, radius becomes a slider, everything fits
without scrolling.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Border and shadow colors become first-class settings: Borders gain a
Frame option (outlines solid/soft surfaces too; ghost/link stay flat)
plus a color select (inverted/black/white/primary/neutral), Shadows gain
graded colors (black/dark/medium gray/inverted/primary — pure black
disappears against dark surfaces, which also made the previous defaults
invisible in dark mode). Colors ride two CSS variables so every
combination is a variable swap over static class bundles; all ring
overrides move to extension compoundVariants after discovering card and
input rings live at variant level and silently beat slot overrides.
Studio CSS baselines are now :where()-wrapped — unlayered rules beat the
library's @layer theme but zero specificity lets user theme overrides
win regardless of load order (previously --ui-shadow-color choices and
preset --ui-bg overrides lost the cascade to main.css).
The Neo-brutalist preset adopts the reference palette (#FF3333/#FF6666
custom red ramp, yellow secondary, pure white/black surfaces) and is now
pure configuration. The preview becomes a masonry column layout with five
new tiles: Table, Stats, Chat, Team, Notifications.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Bold now only thickens borders that already exist, keeping each
element's own ring color — ghost/solid/soft variants no longer gain
frames they never had. Hard shadows switch from --ui-border-inverted
(white in dark mode, reading as a glow) to a new --ui-shadow-color
variable: near-black over light surfaces, pure black in dark, defined
in the docs CSS and emitted by generateCSS whenever the hard treatment
is active so exports stand alone. Ghost/link buttons cast no shadow.
The uniform outlined-everything look moves into the Neo-brutalist
preset itself (per-mode border token remaps plus explicit component
frames on solid/outline/subtle/soft, ghost stays flat).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
outline/subtle variants take their rings from theme compoundVariants,
which render after slot-base classes — so the bold bundle's width AND
inverted color were both dropped there (visible as 1px primary/error/
success rings in dark mode). The bundle now also ships extension
compoundVariants for those variants on button/badge/alert, which append
after the theme's and win the merge; inputs keep the slot-level override
that already worked.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adds a style axis to the studio modeled on Shadcn Studio's configurator:
Shadows (none/soft/hard offset) and Borders (thin/bold), expanded into
static per-component class bundles over the app.config ui path — the
stopgap for the missing --ui-shadow/--ui-border-width core tokens. Hard
shadows use --ui-border-inverted so they stay black-on-light and
white-on-dark, with the classic press-down hover on buttons.
Ships a Neo-brutalist preset (hard shadows, bold borders, radius 0,
yellow primary, black borders via token remaps) and teaches shuffle to
occasionally roll style treatments.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The :root baseline rule shared specificity with the library's .dark
override and won on cascade order, painting dark mode with the light 50.
Scope it with :root:not(.dark).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Light-mode --ui-bg now follows the neutral ramp app-wide (main.css +
docs render baseline) instead of hardcoded white, so tinted neutrals show
without editing anything. The engine gains LIBRARY_TOKEN_DEFAULTS — the
stock @nuxt/ui token values — and export diffing compares against those
rather than the docs baseline, so themes that rely on the ramp-following
background still export it for stock installs.
Drag transition matched to the 60ms apply throttle (was 150ms lagging
behind the pointer).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Curve edits now apply on a 60ms throttle (leading + trailing) instead of
a trailing debounce, so the whole page restyles during the drag. A
temporary html class enables short background/color/border transitions
(excluding the curve editor itself) so throttle ticks glide instead of
stepping, and the analytics event is rate-limited to one per burst.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replaces the hex-anchor abstraction: a palette is now three transition
curves (lightness, chroma, hue) edited in a devtools-easing-style square
with draggable endpoint Ys and free handles, one tab per channel. Any
existing palette (tailwind or the docs' CSS-only neutrals) is
reverse-fitted into curves via coordinate-descent so editing always
starts from the real thing — swatch clicks while a custom palette is
active refit to the chosen palette, resetting the scales.
Custom neutrals also re-route the hardcoded white tokens (light --ui-bg /
--ui-text-inverted, dark --ui-text-highlighted) through the ramp so a
tinted neutral finally reaches the app background in light mode; the
remaps are cleaned up on removal.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The base lightness curve was taken from tailwind's gray scale, so color
ramps came out far too dark at the 800-950 end (dL up to -0.17) and the
too-light wings gamut-clamped their chroma away. Rebased the curve on
tailwind's color ramps, widened the chroma bell, gave neutrals their own
deeper dark end, and widened the extreme-anchor guard so near-black
anchors still produce distinct shades.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Opening the editor no longer hijacks the theme (preview only until a user
edit or explicit 'Use this palette'). With a custom palette active, the
standard swatches re-anchor the custom ramp to the chosen palette instead
of being dead ends, and an always-visible ✕ on the trigger row drops the
custom palette entirely. Adds parseCssColor (hex/oklch/rgb) so anchors
can seed from tailwind JS values or the docs' CSS-only palettes.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Dependency-free sRGB<->OKLCH math (gamut clamping, WCAG contrast) and a
parametric ramp generator: anchor hex pinned exactly at shade 500 with
adjustable light/dark endpoints, vibrance, chroma spread and hue drift.
Inline editors under the Primary/Neutral pickers live-apply the generated
ramp through the doc path with a WCAG badge and swatch preview; curve
params persist across reloads and exports stay minimal (unreferenced
palettes are now filtered out of the doc).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Pure theme-engine module (ThemeDoc schema, provenance resolver, minimal
CSS/app.config export generators) with unit tests; useTheme now snapshots
its state as a ThemeDoc and delegates exports to the engine. New
useThemeStudio composable applies docs through the sanitized
applyThemeSettings path, powering a Presets menu (Nuxt UI, Shadcn,
Anthropic, Spotify) and a doc-based shuffle in the studio toolbar.
Also fixes the theme-color computed crashing on custom neutral palettes
(undefined tailwind lookup aborted the whole unhead flush, so injected
palette styles never rendered).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Standalone /theme page in the main header nav: Essentials controls
(primary, neutral, radius, font, icons, color mode) sharing state with
the existing popover via useTheme, a live component bento preview,
seeded-taste shuffle, minimal-diff export panel (main.css + app.config),
and an Open Theme Studio link in the popover.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Plan for the Nuxt UI theme customizer: standalone /theme page in the main
header nav, ThemeDoc + provenance resolver engine, OKLCH palette curve
editor, inheritance drill-down, presets + shuffle, minimal CSS/app.config
exports, bento + template previews, and a phased roadmap with upstream
core-gap PRs.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>