VisorVisor
Flutter

Theming

Customize Visor's Flutter output by editing .visor.yaml — change palettes, swap fonts, and re-generate your packages/ui/ with visor theme apply.

Visor's theming system for Flutter is driven by .visor.yaml — a single config file that describes your active theme, color overrides, typography, and more. Running visor theme apply --target flutter re-generates your packages/ui/ directory from this config.

How it Works

.visor.yaml  →  visor theme apply --target flutter  →  packages/ui/

The generated packages/ui/ contains strongly-typed Dart token classes that your app's widgets reference at runtime via BuildContext extensions provided by visor_core.

.visor.yaml Structure

A minimal Flutter-targeted config:

theme: visor-default
target: flutter
output: packages/ui

colors:
  primary: "#6366f1"
  primaryForeground: "#ffffff"

typography:
  fontFamily: "Inter"
  scale: 1.0

theme

The base theme to build on. Built-in options:

ValueDescription
visor-defaultLight mode, neutral palette
visor-darkDark mode, neutral palette
visor-spaceDark mode, deep space palette

target

Set to flutter to generate Dart output. The same .visor.yaml can target css (React) and flutter simultaneously via separate runs or a batch command.

output

Path to the generated package directory relative to project root. Defaults to packages/ui.

colors

Override individual semantic color tokens. Keys map directly to VisorColorsData fields:

colors:
  interactivePrimaryBg: "#6366f1"
  interactivePrimaryBgHover: "#4f46e5"
  interactivePrimaryText: "#ffffff"
  surfaceDefault: "#ffffff"
  surfaceCard: "#f8fafc"
  textPrimary: "#111827"
  textSecondary: "#4b5563"

typography

Control the font family and scale factor:

typography:
  fontFamily: "Inter"
  scale: 1.0

Re-generating after Changes

After editing .visor.yaml:

npx visor theme apply --target flutter

Verify the output compiles:

npx visor theme verify --target flutter packages/ui

Theming Multiple Flavors

For apps with separate light/dark or brand-specific builds, use separate .visor.yaml files and pass the config path explicitly:

npx visor theme apply --target flutter --config .visor.light.yaml
npx visor theme apply --target flutter --config .visor.dark.yaml

Consuming Tokens at Runtime

The generated packages/ui/ registers all tokens as InheritedWidget data via visor_core's BuildContext extensions. Access any token in any widget:

@override
Widget build(BuildContext context) {
  final colors = context.visorColors;
  final textStyles = context.visorTextStyles;
  final spacing = context.visorSpacing;

  return Container(
    color: colors.surfaceCard,
    padding: EdgeInsets.all(spacing.md),
    child: Text(
      'Hello',
      style: textStyles.bodyMedium.copyWith(color: colors.textPrimary),
    ),
  );
}

All theme changes flow through VisorTheme — no setState, no Provider boilerplate required.

Validating your Config

Before applying, validate the YAML against Visor's schema:

npx visor theme validate .visor.yaml

This catches unknown keys, type mismatches, and missing required fields before any code is generated.

See Also