tweakcn theming

why

a theme tool produces a coherent palette in seconds — exactly why its output must not become authority by paste. values that skip role review arrive without an owner; later theming work cannot tell which token serves canvas, surface, or state. routing candidates through owned semantic roles keeps exploration fast with one accountable token system.

rule

use tweakcn to explore and establish an intentional semantic token system, never to paste a theme in without ownership review.

workflow

  1. choose the visual role each token serves: canvas, surface, text, action, border, destructive state, data state.
  2. apply the values in the shared theme source.
  3. verify contrast, focus, dark mode if supported, real component states.
  4. remove obsolete token aliases once the system is accepted.

exploration is not authority

a theme tool compares candidate systems quickly. it does not decide product roles, contrast requirements, component variants, or refine-vs-replace. accept values only after mapping them to owned semantic roles in source, then remove the exploration artifact from the decision path.

values pasted without mapping have no documented meaning. a later designer cannot tell "refinement" (same identity, better contrast) from "redesign" (new visual world). adoption splits: some components use the new palette, others the old one — the product looks fragmented. map each value to a semantic role (canvas, surface, action, text, border, destructive, data), remove tweakcn's output, update components to the owned roles.

questionrequired answer before adoption
refinement or redesign?refinement preserves the existing visual world; redesign explicitly replaces it.
what does each candidate token mean?canvas, surface, text, action, border, destructive, or data role—not a palette label.
where is it consumed?shared theme source and named component variants.
what changes with theme mode?explicit paired values and checked contrast, focus, disabled, and error states.
what becomes obsolete?aliases and raw values removed in the same forward-only change.

verification

render real component states, not a token swatch alone: default, hover/focus, disabled, error, loading, empty, dense data surfaces where they exist. compare against the declared refinement/redesign decision so a theme update cannot silently change unrelated product identity.

do not

  • treat generated theme values as product truth.
  • use tweakcn output as a substitute for a component or accessibility review.

good and bad

bad

/* theme.css — values copied from tweakcn without mapping */
:root {
--slate-50: #f8fafc;
--slate-900: #0f172a;
--primary: #6750a4;
--secondary: #625b71;
}
/* Button.tsx — no consistency rule */
<button className="bg-primary text-slate-50">Submit</button>
/* StatusBadge.tsx — uses old palette */
<span className="bg-slate-900 text-slate-50">Active</span>
/* Card.tsx — uses wrong token */
<div className="bg-secondary">Content</div>

tweakcn provided values but not meaning. each component guesses a token. a later update to --primary (actions only) still hits the card; new components match inconsistently or reach for raw palette values.

good

/* theme.css — values mapped to semantic roles before adoption */
:root {
/* visual roles */
--action: #6750a4; /* buttons, links, interactive elements */
--surface: #fffbfe; /* background layers and containers */
--text: #0f172a; /* primary and secondary text */
--border: #e2e8f0; /* dividers and outlines */
--error: #dc2626; /* destructive and error states */
}
/* Button.tsx — owns its CVA variants, consumes roles */
const button = cva("", {
variants: {
tone: {
primary: "bg-action text-surface",
secondary: "bg-surface text-action border border-action",
},
},
});
<button className={button({ tone: "primary" })}>Submit</button>
/* StatusBadge.tsx — consistent semantic usage */
<span className="bg-surface text-text border border-border">Active</span>
/* Card.tsx — components never use undocumented tokens */
<div className="bg-surface text-text">Content</div>

values become owned semantic roles; components consume them through variants. updating --action propagates to all buttons; identity stays coherent.

search pages

go to any page