Theme generator
Paste a tweakcn/shadcn theme and copy a working Flutter theme.dart for flutterwindcss — colors, radius, shadows, and fonts, with nothing dropped.
The theme generator turns any tweakcn / shadcn theme into a
ready-to-use theme.dart for flutterwindcss. Paste the CSS you export from tweakcn and
copy a theme.dart — two const FwTokens (light + dark) you own and drop into your project,
shadcn-style. No other Flutter UI library does this — it's the headline feature.
How to use it
- On tweakcn, design or pick a theme and export it as CSS. Choose the Tailwind v4 format (the default) — see Limitations.
- Open the generator and paste the entire CSS export into the box
(the full file —
@import,@theme inline,@layerand all; only the:rootand.darkblocks are read). - The preview updates live: a swatch grid of all 32 colors, the four radius samples, and the seven shadow samples, shown in both light and dark.
- Copy the generated
theme.dart(the "Copy" button above the source) and paste it into your app.
You don't pick the input format — each color value is auto-detected, so oklch(), hsl(),
rgb(), and hex can even be mixed within one theme.
Wiring the output into your app
The generated file exports two const FwTokens — lightTheme and darkTheme. Hand the right
one to FwAnimatedTheme (or FwTheme) for the current brightness; every context.fw-styled
widget reskins from that single swap:
import 'package:flutter/widgets.dart';
import 'package:flutterwindcss/flutterwindcss.dart';
import 'theme.dart'; // the theme.dart you copied in
class App extends StatelessWidget {
const App({super.key, required this.isDark});
final bool isDark;
@override
Widget build(BuildContext context) {
return WidgetsApp(
color: const Color(0xFF000000),
home: FwAnimatedTheme(
tokens: isDark ? darkTheme : lightTheme,
child: const HomeScreen(),
),
);
}
}It also works inside a MaterialApp — context.fw resolves the Material-free FwTheme first
and falls back to the FwThemeExtension bridge, so the same components theme in either host.
What gets converted
Everything a shadcn theme carries, not just color:
- Colors — all 32. The 19 core roles plus
chart-1…5and the 8sidebar-*tokens, mapped straight ontoFwColors. Nothing is dropped; a partial theme can't even compile, so the generator won't produce atheme.dartuntil all 32 are present (see below). - Radius. Derived from
--radiususing shadcn's additive steps (sm = r−4,md = r−2,lg = r,xl = r+4, clamped at ≥ 0). - Shadows — 7 named levels.
--shadow-2xs … --shadow-2xlbecomeFwShadows, including colored and hard-offset shadows (the composed CSS strings are read verbatim). - Typography. The first concrete family from each
--font-*stack (sans/serif/mono) plus--tracking-normal(letter-spacing, normalized to em).
Color accuracy
OKLCH colors are converted to match Tailwind/shadcn's published hex (a gamut-clip), so a
pasted shadcn theme is the shadcn colors — and the generated theme stays coherent with the
baked Tailwind palette flutterwindcss ships. For the realistic, in-gamut shadcn range this is
exact. (A perceptual gamut-map for vivid, genuinely out-of-gamut OKLCH exists in the library API
but isn't a UI option — real tweakcn exports are already in-gamut.)
Reporting — nothing is silent
Whenever the generator defaults or drops a token, it tells you: the UI shows a notice and
the emitted theme.dart carries header comments. Omitted fonts fall back to the platform family,
an omitted shadow scale falls back to the engine default, a missing --sidebar-ring falls back to
--ring, and any unrecognized --var is listed as dropped.
Limitations
Tailwind v4 exports only
tweakcn can also export Tailwind v3 CSS (bare H S% L% colors under @layer base with
@tailwind directives). That format is not supported — the generator detects it and asks
you to re-export as Tailwind v4 rather than silently misparsing it.
All 32 colors are required
FwColors has no defaults, so a theme.dart missing any color wouldn't compile — and a web
user has no compiler. If a pasted theme is missing one of the 32, the generator shows an error
listing the missing tokens and produces no output. (Non-color tokens — fonts, shadows, radius,
tracking — default gracefully and are reported.)
Fonts are named, not bundled
flutterwindcss ships no fonts. The generator emits the family name (so it round-trips) plus
a clearly-commented google_fonts wiring stub. Until you
wire the font, Flutter falls back to the platform family — it never pretends a font is present.
A few smaller, deliberate notes:
--spacingis dropped (with a comment) when it isn't the default0.25rem. flutterwindcss uses a fixed spacing scale of1 unit = 4px, context-free by design.--tracking-normalround-trips and interpolates as a token, but applying it to rendered text on the engine's default text path is a separate, not-yet-wired enhancement.- The unprefixed
--shadow(Tailwind's DEFAULT level) is dropped —FwShadowshas seven named slots and no DEFAULT level. It is not the same value as--shadow-md.
How it works
The generator is a small, pure TypeScript pipeline (parse → color → emit) that runs entirely in
your browser — nothing is uploaded. The color math is a hand-rolled, vector-tested
OKLCH → OKLab → linear sRGB → sRGB conversion, and the whole pipeline is checked end-to-end
against a real tweakcn theme exported in all four color formats, so the four converge on the same
result.