Apply Theme Skill
Reads assets/config/theme_config.json generated by /brand-theme and applies it to the Flutter app's theme system.
When to Use
- •After running
/brand-themeto generate a config - •User asks to "apply the theme", "update theme from config", or "implement the brand colors"
- •User invokes
/apply-themedirectly
Prerequisites
- •
assets/config/theme_config.jsonmust exist (generated by/brand-theme) - •If it doesn't exist, instruct user to run
/brand-themefirst
Process Overview
- •Read and validate
theme_config.json - •Update color definitions in
lib/core/theme/app_colors.dart - •Update gradients in
lib/core/theme/gradients.dart - •Update logo paths
- •Update app name, caption, and welcome message in
lib/core/constants/app_constants.dart - •Implement animation effects based on style preset
- •Verify the app builds successfully
Step 1: Read Configuration
Read assets/config/theme_config.json and validate structure:
{
"brand": {
"name": "...",
"appName": { "light": "...", "dark": "..." },
"caption": { "light": "...", "dark": "..." },
"welcomeMessage": "...",
"logo": { "light": "...", "dark": "..." }
},
"colors": { "primary": "#...", "secondary": "#...", "accent": "#..." },
"animation": { "style": "neon|cosmic|minimal|professional|playful" },
"modes": { "default": "dark|light|system" }
}
Validation checks:
- •Primary color is valid hex
- •Logo paths are provided
- •Animation style is one of the valid presets
- •App name and caption are provided (or default to brand.name)
Step 2: Update app_colors.dart
File: lib/core/theme/app_colors.dart
Color Mapping
Map config colors to the app's color system. Generate both light and dark variants.
From config primary color, derive:
For dark mode (if primary is the accent color):
- •
_darkPrimary= config primary - •
_darkPrimaryForeground= contrasting color (white or dark based on luminance) - •
_darkSecondary= config secondary (or derive complementary) - •
_darkAccent= config accent (or derive triadic) - •
_darkBackground= deep dark version of primary (10% lightness) - •
_darkCard= slightly lighter than background (15% lightness) - •
_darkMuted= desaturated primary at 20% lightness - •
_darkMessageBubbleOwn= primary at 30% lightness
For light mode:
- •
_lightPrimary= config primary - •
_lightPrimaryForeground= white (or dark if primary is light) - •
_lightBackground= white or very light tint of primary - •
_lightCard= off-white or very light gray - •
_lightMessageBubbleOwn= config primary
Logo Paths
Update lines 97-98 in app_colors.dart:
static const String lightLogo = '[CONFIG_LIGHT_LOGO]'; static const String darkLogo = '[CONFIG_DARK_LOGO]';
Logo Sizing Note:
- •The welcome screen (
lib/features/chat/presentation/widgets/welcome_hero_screen.dart) displays the logo atheight: 120 - •Prefer emblem/icon-only logos - full logos with text appear oversized at this height
- •If logo appears too large, verify an emblem-only asset is being used
Color Generation Algorithm
Given primary hex color: 1. Convert to HSL 2. For dark mode derived colors: - Background: H same, S * 0.3, L = 5% - Card: H same, S * 0.3, L = 8% - Muted: H same, S * 0.2, L = 15% - Border: H same, S * 0.2, L = 12% 3. For light mode derived colors: - Background: white (#FFFFFF) - Card: H same, S * 0.05, L = 98% - Muted: H same, S * 0.1, L = 96% 4. For foreground/text colors: - If primary luminance > 0.5: use dark text - If primary luminance <= 0.5: use light text
Step 3: Update gradients.dart
File: lib/core/theme/gradients.dart
Generate gradient variations from the config colors:
// Primary gradient - 3 stops from lighter to darker
static const darkPrimaryGradient = LinearGradient(
colors: [
Color(0xFF[LIGHTER_PRIMARY]), // +10% lightness
Color(0xFF[PRIMARY]), // config primary
Color(0xFF[DARKER_PRIMARY]), // -10% lightness
],
stops: [0.0, 0.5, 1.0],
);
Apply same pattern to:
- •
darkPrimaryGradient/lightPrimaryGradient - •
darkSecondaryGradient/lightSecondaryGradient - •
darkAccentGradient - •
primaryButtonGradient - •
secondaryButtonGradient
Step 4: Update App Constants
File: lib/core/constants/app_constants.dart
Update the app name, caption, and related strings from the config:
// App Information static const String appName = '[CONFIG_APPNAME_LIGHT]'; // Light theme name static const String appNameDark = "[CONFIG_APPNAME_DARK]"; // Dark theme name static const String appCaption = '[CONFIG_CAPTION_LIGHT]'; // Light theme caption static const String appCaptionDark = '[CONFIG_CAPTION_DARK]'; // Dark theme caption
Mapping from config:
- •
appName=brand.appName.light(orbrand.nameif not specified) - •
appNameDark=brand.appName.dark(orbrand.nameif not specified) - •
appCaption=brand.caption.light(or "Powered by AI" if not specified) - •
appCaptionDark=brand.caption.dark(or same as light if not specified)
Note: The welcome message (brand.welcomeMessage) is used in chat_home_page.dart via the app name constants. Updating appName and appNameDark will automatically update the welcome message format: "Welcome to {appName}!"
Step 5: Implement Animation Effects
Based on animation.style from config, create or update animation widgets.
CRITICAL: Follow Existing Codebase Patterns
All effects MUST follow these patterns from the existing codebase:
Pattern 1: Theme Brightness Detection
final isDark = Theme.of(context).brightness == Brightness.dark;
Pattern 2: AppColors Extension Access
final appColors = Theme.of(context).extension<AppColorsExtension>()!; final colorScheme = Theme.of(context).colorScheme;
Pattern 3: Dynamic Color Selection (from speech_to_text_widget.dart)
List<Color> _buildGlowColors() {
final isDark = Theme.of(context).brightness == Brightness.dark;
final appColors = context.appColors;
if (isDark) {
return isActive
? [
colorScheme.primary.withOpacity(0.8),
colorScheme.secondary.withOpacity(0.6),
appColors.accent.withOpacity(0.4),
]
: [
appColors.mutedForeground.withOpacity(0.3),
appColors.mutedForeground.withOpacity(0.2),
];
}
// Light theme with reduced intensity...
}
Pattern 4: Use AppConstants for Animation Values
Reference: lib/core/constants/app_constants.dart
static const Duration glowAnimationDuration = Duration(milliseconds: 2000); static const double glowBorderSize = 2.0; static const double speechGlowSizeListening = 12.0; static const double speechGlowSizeIdle = 6.0;
Pattern 5: Existing Packages to Use
- •glowy_borders -
AnimatedGradientBorderfor neon glow effects - •flutter_animate -
.animate().fadeIn().scale().shimmer()chains - •CustomPainter - For particle/starfield effects (see
particles_widget.dart) - •AnimationController + AnimatedBuilder - For wave/pulse effects
Pattern 6: Particles Widget Reference
See lib/shared/widgets/particles_widget.dart for starfield implementation:
ParticlesWidget( quantity: 50, color: appColors.primary, // Theme-aware staticity: 50, size: 0.4, )
Effect Implementation Patterns
Reference: https://github.com/flutterfx/flutterfx_widgets
cosmic style
Create lib/shared/widgets/effects/cosmic_background.dart:
- •Animated starfield using CustomPainter
- •Subtle parallax on mouse/touch movement
- •Use
flutter_animatefor particle fade effects
neon style
Create lib/shared/widgets/effects/border_beams.dart:
- •Animated gradient border using
glowy_borderspackage - •Pulsing glow effect synced with primary color
- •Use config primary color for the beam color
minimal style
- •No new widgets needed
- •Ensure existing
BlurFadetransitions are subtle (duration: 200ms, blur: 2.0)
professional style
Create lib/shared/widgets/effects/fancy_card.dart:
- •Elevated card with subtle shadow animation
- •Hover state with slight scale and shadow increase
- •Clean, understated motion
playful style
Create lib/shared/widgets/effects/particle_burst.dart:
- •Confetti/particle effect on interactions
- •Use chart colors from config for particle variety
- •Bouncy spring animations
Effect File Structure
lib/shared/widgets/effects/ ├── cosmic_background.dart # For cosmic style ├── border_beams.dart # For neon style ├── fancy_card.dart # For professional style ├── particle_burst.dart # For playful style └── effects_provider.dart # Exports based on active style
effects_provider.dart Template
import 'package:flutter/material.dart';
enum AnimationStyle { cosmic, neon, minimal, professional, playful }
// Current active style from config
const AnimationStyle activeStyle = AnimationStyle.[CONFIG_STYLE];
class EffectsProvider {
static Widget wrapWithBackground(Widget child) {
switch (activeStyle) {
case AnimationStyle.cosmic:
return CosmicBackground(child: child);
case AnimationStyle.neon:
return BorderBeamsBackground(child: child);
case AnimationStyle.professional:
return FancyCardBackground(child: child);
case AnimationStyle.playful:
return FlickeringGridBackground(child: child);
case AnimationStyle.minimal:
default:
return child;
}
}
static Widget wrapWithLoadingEffect(Widget child) {
// Similar switch for loading indicators
}
}
Step 6: Verify Build
After making all changes:
- •Run
flutter analyzeto check for errors - •Run
flutter build web --wasmto verify build succeeds - •Report any issues found
IMPORTANT: If testing via the backend server (http://localhost:8000):
- •The server serves static files from
build/web - •After rebuilding, restart the server to serve the new build
- •Kill existing server:
lsof -ti :8000 | xargs kill -9 - •Start fresh:
cd backend && uv run python app.py
Output Summary
After applying theme, display:
Theme applied successfully! Updated files: - lib/core/theme/app_colors.dart (colors + logos) - lib/core/theme/gradients.dart (gradient variations) - lib/core/constants/app_constants.dart (app name + caption) - lib/shared/widgets/effects/ (animation widgets) Brand applied: - App Name: [NAME] - Caption: [CAPTION] - Welcome: [WELCOME_MESSAGE] Colors applied: - Primary: [HEX] - Secondary: [HEX] - Accent: [HEX] Animation style: [STYLE] Next steps: - Run `flutter build web --wasm` to rebuild - Restart the backend server to serve the new build - Test the app at http://localhost:8000
Rollback
If issues occur, the skill should:
- •Keep original files backed up (git handles this)
- •Provide instructions to revert:
git checkout -- lib/core/theme/
File Modification Checklist
Before completing, verify these files were updated:
- •
lib/core/theme/app_colors.dart- Color constants and logo paths - •
lib/core/theme/gradients.dart- Gradient definitions - •
lib/core/constants/app_constants.dart- App name, caption, welcome message - •
lib/shared/widgets/effects/- Animation effect widgets (if style != minimal) - • Verify
flutter analyzepasses - • Commit changes with descriptive message
Error Handling
Config file not found:
theme_config.json not found at assets/config/theme_config.json Run /brand-theme first to generate the configuration.
Invalid color format:
Invalid color "[value]" in config. Expected hex format like #FF5F46. Please fix the config file or run /brand-theme again.
Build fails after changes:
Build failed after applying theme. Errors: [error details] You can revert changes with: git checkout -- lib/core/theme/ Then review the config and try again.