Flutter Integration
The design system generates a Dart file at build/flutter/naluma_tokens.dart containing type-safe color constants. This file is the bridge between the token JSON and the Flutter app’s ThemeData.
Build Pipeline
Section titled “Build Pipeline”The Style Dictionary config (config/style-dictionary.config.mjs) includes a flutter platform that transforms primitive color tokens into a Dart class:
tokens/primitive/color.json | Style Dictionary (flutter transformGroup) | build/flutter/naluma_tokens.dartRun from the repository root:
npm run tokensThis regenerates all platform outputs, including the Dart file.
Generated File Structure
Section titled “Generated File Structure”The generated naluma_tokens.dart exports an abstract final class with static Color constants:
// DO NOT EDIT — generated by Style Dictionaryimport 'package:flutter/material.dart';
abstract final class NalumaColors { /// Primary light background static const primitiveColorWarmWhite = Color(0xFFFBFAF1); /// Secondary background, soft accent areas static const primitiveColorPaleWheat = Color(0xFFF9DFAE); /// Borders, dividers, accent highlights static const primitiveColorWarmGold = Color(0xFFF2C087); // ... all primitive colors}The class is abstract final to prevent instantiation — it serves as a namespace for color constants.
Using NalumaColors in ThemeData
Section titled “Using NalumaColors in ThemeData”Import the generated file and wire the colors into your app’s ThemeData:
import 'package:naluma_app/generated/naluma_tokens.dart';
ThemeData nalumaLightTheme() { return ThemeData( scaffoldBackgroundColor: NalumaColors.primitiveColorWarmWhite, colorScheme: ColorScheme.light( primary: NalumaColors.primitiveColorBurntSiennaDeep, onPrimary: NalumaColors.primitiveColorWhite, secondary: NalumaColors.primitiveColorDarkBurgundy, surface: NalumaColors.primitiveColorWhite, onSurface: NalumaColors.primitiveColorWarmDark, error: const Color(0xFFDC2626), ), appBarTheme: AppBarTheme( backgroundColor: NalumaColors.primitiveColorPaleWheat, foregroundColor: NalumaColors.primitiveColorWarmDark, ), elevatedButtonTheme: ElevatedButtonThemeData( style: ElevatedButton.styleFrom( backgroundColor: NalumaColors.primitiveColorBurntSiennaDeep, foregroundColor: NalumaColors.primitiveColorWhite, minimumSize: const Size.fromHeight(44), // Accessibility min touch target shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), // primitive.radius.md ), ), ), );}Dark Theme
Section titled “Dark Theme”ThemeData nalumaDarkTheme() { return ThemeData.dark().copyWith( scaffoldBackgroundColor: NalumaColors.primitiveColorWarmCharcoal, colorScheme: ColorScheme.dark( primary: NalumaColors.primitiveColorBurntSiennaDeep, onPrimary: NalumaColors.primitiveColorWhite, secondary: NalumaColors.primitiveColorPaleWheat, // Flipped for dark mode surface: NalumaColors.primitiveColorDarkSurface, onSurface: NalumaColors.primitiveColorWarmWhite, error: const Color(0xFFDC2626), ), );}Font Bundling
Section titled “Font Bundling”The app uses two Google Fonts families. Bundle them as assets rather than fetching at runtime to avoid a flash of unstyled text.
1. Download font files
Section titled “1. Download font files”Download variable-weight .ttf files for:
- Literata (headings) — weights 300—800
- Plus Jakarta Sans (body) — weights 300—800
2. Add to pubspec.yaml
Section titled “2. Add to pubspec.yaml”flutter: fonts: - family: Literata fonts: - asset: assets/fonts/Literata-VariableFont.ttf - family: PlusJakartaSans fonts: - asset: assets/fonts/PlusJakartaSans-VariableFont.ttf3. Reference in TextTheme
Section titled “3. Reference in TextTheme”TextTheme nalumaTextTheme() { return TextTheme( displayLarge: const TextStyle( fontFamily: 'Literata', fontSize: 48, fontWeight: FontWeight.w600, height: 1.15, // line-height.snug letterSpacing: -0.01 * 48, // tight-1 in px ), headlineLarge: const TextStyle( fontFamily: 'Literata', fontSize: 36, fontWeight: FontWeight.w600, height: 1.2, letterSpacing: -0.005 * 36, ), bodyLarge: const TextStyle( fontFamily: 'PlusJakartaSans', fontSize: 18, fontWeight: FontWeight.w400, height: 1.7, ), bodyMedium: const TextStyle( fontFamily: 'PlusJakartaSans', fontSize: 16, fontWeight: FontWeight.w400, height: 1.7, ), bodySmall: const TextStyle( fontFamily: 'PlusJakartaSans', fontSize: 14, fontWeight: FontWeight.w400, height: 1.65, ), labelLarge: const TextStyle( fontFamily: 'PlusJakartaSans', fontSize: 16, fontWeight: FontWeight.w600, letterSpacing: 0.01 * 16, // button-lg ), );}Motion Constants
Section titled “Motion Constants”The settle easing curve maps to Flutter’s Cubic:
class NalumaMotion { static const settleCurve = Cubic(0.16, 1, 0.3, 1); static const settleDuration = Duration(milliseconds: 600);
static const defaultCurve = Cubic(0.4, 0, 0.2, 1); static const fastDuration = Duration(milliseconds: 150); static const normalDuration = Duration(milliseconds: 250); static const slowDuration = Duration(milliseconds: 400);}Keeping Tokens in Sync
Section titled “Keeping Tokens in Sync”The generated Dart file should be committed to the Flutter app repository (not the design system repo). The recommended workflow:
- Edit token JSON in
naluma-design-system/tokens/ - Run
npm run tokensto regenerate all outputs - Copy
build/flutter/naluma_tokens.dartinto the Flutter app’slib/generated/directory - Review the diff for any breaking changes before committing
A future CI step could automate step 3 by opening a PR against the Flutter app repo whenever tokens change.