Implement and test custom color schemes, themes, and visual variants for the emotive-mascot website and demos. Use when applying new color palettes, creating themed variants, or A/B testing visual designs.
Implements CSS variable-based color themes for the emotive-mascot website. Used when applying new color palettes, creating themed variants, or A/B testing visual designs with the provided warm, cool, and premium schemes.
/plugin marketplace add joshtol/emotive-engine/plugin install joshtol-emotive-mascot-skills@joshtol/emotive-engineThis skill inherits all available tools. When active, it can use any tool Claude has access to.
You are an expert in implementing and testing visual themes for the emotive-mascot platform.
From the theme-factory skill, we have 3 ready-to-use variants:
Use for: E-commerce, retail, food & beverage, entertainment Primary: #FF8C42 (Vibrant Orange) Accent: #FF6B35 (Coral)
Use for: Healthcare, finance, technology, corporate Primary: #06B6D4 (Cyan) Accent: #0891B2 (Darker Cyan)
Use for: Luxury, premium products, high-end services Primary: #D4AF37 (Gold) Accent: #B8960F (Rich Gold)
Create theme variants using CSS custom properties:
/* site/src/app/globals.css */
:root {
/* Default theme (Purple/Blue) */
--color-primary: #667eea;
--color-primary-light: #a5b4fc;
--color-primary-dark: #4c51bf;
--color-accent: #764ba2;
--color-accent-light: #9d7cbf;
}
/* Warm theme */
[data-theme='warm'] {
--color-primary: #ff8c42;
--color-primary-light: #ffb088;
--color-primary-dark: #e67a2e;
--color-accent: #ff6b35;
--color-accent-light: #ff9270;
}
/* Cool theme */
[data-theme='cool'] {
--color-primary: #06b6d4;
--color-primary-light: #67e8f9;
--color-primary-dark: #0891b2;
--color-accent: #0e7490;
--color-accent-light: #22d3ee;
}
/* Premium theme */
[data-theme='premium'] {
--color-primary: #d4af37;
--color-primary-light: #f4d03f;
--color-primary-dark: #b8960f;
--color-accent: #8b7500;
--color-accent-light: #e6c200;
}
Replace hardcoded colors with CSS variables:
// Before (hardcoded)
<div style={{
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
border: '1px solid rgba(102, 126, 234, 0.3)'
}}>
...
</div>
// After (themeable)
<div style={{
background: 'linear-gradient(135deg, var(--color-primary) 0%, var(--color-accent) 100%)',
border: '1px solid rgba(var(--color-primary-rgb), 0.3)'
}}>
...
</div>
// site/src/components/ThemeSwitcher.tsx
'use client';
import { useState, useEffect } from 'react';
type Theme = 'default' | 'warm' | 'cool' | 'premium';
export default function ThemeSwitcher() {
const [theme, setTheme] = useState<Theme>('default');
useEffect(() => {
// Load theme from localStorage
const savedTheme =
(localStorage.getItem('theme') as Theme) || 'default';
setTheme(savedTheme);
document.documentElement.setAttribute('data-theme', savedTheme);
}, []);
const handleThemeChange = (newTheme: Theme) => {
setTheme(newTheme);
document.documentElement.setAttribute('data-theme', newTheme);
localStorage.setItem('theme', newTheme);
};
return (
<div
style={{
position: 'fixed',
top: '20px',
right: '20px',
zIndex: 9999,
display: 'flex',
gap: '0.5rem',
padding: '0.75rem',
background: 'rgba(0, 0, 0, 0.8)',
borderRadius: '12px',
backdropFilter: 'blur(10px)',
}}
>
<button
onClick={() => handleThemeChange('default')}
style={{
width: '40px',
height: '40px',
borderRadius: '8px',
background:
'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
border: theme === 'default' ? '2px solid white' : 'none',
cursor: 'pointer',
}}
title="Default (Purple)"
/>
<button
onClick={() => handleThemeChange('warm')}
style={{
width: '40px',
height: '40px',
borderRadius: '8px',
background:
'linear-gradient(135deg, #FF8C42 0%, #FF6B35 100%)',
border: theme === 'warm' ? '2px solid white' : 'none',
cursor: 'pointer',
}}
title="Warm (Orange)"
/>
<button
onClick={() => handleThemeChange('cool')}
style={{
width: '40px',
height: '40px',
borderRadius: '8px',
background:
'linear-gradient(135deg, #06B6D4 0%, #0891B2 100%)',
border: theme === 'cool' ? '2px solid white' : 'none',
cursor: 'pointer',
}}
title="Cool (Cyan)"
/>
<button
onClick={() => handleThemeChange('premium')}
style={{
width: '40px',
height: '40px',
borderRadius: '8px',
background:
'linear-gradient(135deg, #D4AF37 0%, #B8960F 100%)',
border: theme === 'premium' ? '2px solid white' : 'none',
cursor: 'pointer',
}}
title="Premium (Gold)"
/>
</div>
);
}
Sync mascot emotion colors with theme:
// Create theme-aware emotion configs
const getThemedEmotions = (theme = 'default') => {
const themeColors = {
default: {
joy: '#FFD700',
calm: '#667eea',
excitement: '#FF6B9D',
},
warm: {
joy: '#FF8C42',
calm: '#FFB088',
excitement: '#FF6B35',
},
cool: {
joy: '#67E8F9',
calm: '#06B6D4',
excitement: '#22D3EE',
},
premium: {
joy: '#F4D03F',
calm: '#D4AF37',
excitement: '#E6C200',
},
};
return {
joy: {
...baseEmotions.joy,
color: themeColors[theme].joy,
},
calm: {
...baseEmotions.calm,
color: themeColors[theme].calm,
},
excitement: {
...baseEmotions.excitement,
color: themeColors[theme].excitement,
},
};
};
// Usage in component
const mascot = new EmotiveMascot({
containerId: 'mascot',
emotions: getThemedEmotions(currentTheme),
});
File: site/src/app/globals.css
Add CSS variable definitions for all themes
File: site/src/app/page.tsx
Replace hardcoded colors:
Update these components to use CSS variables:
FeaturesShowcase.tsx:
// Update feature card borders and backgrounds
border: `1px solid var(--color-primary-light)`,
background: `linear-gradient(135deg, rgba(var(--color-primary-rgb), 0.15) 0%, rgba(var(--color-primary-rgb), 0.05) 100%)`
PremiumAIAssistant.tsx:
// Update panel styling
background: 'linear-gradient(135deg, var(--color-primary) 0%, var(--color-accent) 100%)';
Use Case Pages:
site/src/app/use-cases/retail/page.tsxsite/src/app/use-cases/smart-home/page.tsxsite/src/app/use-cases/healthcare/page.tsxsite/src/app/use-cases/education/page.tsxFile: src/config/emotions.js
Create theme-aware emotion color mappings
// site/src/components/ThemeAnalytics.tsx
'use client';
import { useEffect } from 'react';
export function trackThemeImpression(theme: string) {
// Google Analytics
if (typeof window !== 'undefined' && window.gtag) {
window.gtag('event', 'theme_impression', {
theme_variant: theme,
timestamp: Date.now(),
});
}
// Or custom analytics
fetch('/api/analytics/theme-impression', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ theme, timestamp: Date.now() }),
});
}
export function trackThemeConversion(theme: string, action: string) {
if (typeof window !== 'undefined' && window.gtag) {
window.gtag('event', 'theme_conversion', {
theme_variant: theme,
conversion_action: action,
timestamp: Date.now(),
});
}
}
// site/src/app/layout.tsx
'use client';
import { useEffect, useState } from 'react';
export default function RootLayout({ children }) {
const [theme, setTheme] = useState<string>('default');
useEffect(() => {
// Check if user already has a theme assigned
let assignedTheme = localStorage.getItem('ab-theme');
if (!assignedTheme) {
// Randomly assign theme for A/B test
const themes = ['default', 'warm', 'cool', 'premium'];
assignedTheme = themes[Math.floor(Math.random() * themes.length)];
localStorage.setItem('ab-theme', assignedTheme);
}
setTheme(assignedTheme);
document.documentElement.setAttribute('data-theme', assignedTheme);
// Track impression
trackThemeImpression(assignedTheme);
}, []);
return (
<html lang="en" data-theme={theme}>
<body>{children}</body>
</html>
);
}
// In waitlist form
const handleSubmit = async (email: string) => {
// Submit form
await submitWaitlist(email);
// Track conversion with current theme
const theme = document.documentElement.getAttribute('data-theme');
trackThemeConversion(theme, 'waitlist_signup');
};
// In demo interactions
const handleDemoStart = () => {
const theme = document.documentElement.getAttribute('data-theme');
trackThemeConversion(theme, 'demo_started');
};
For rgba() usage, add RGB values to CSS:
:root {
--color-primary: #667eea;
--color-primary-rgb: 102, 126, 234; /* For rgba() */
}
[data-theme='warm'] {
--color-primary: #ff8c42;
--color-primary-rgb: 255, 140, 66;
}
Or use JavaScript:
function hexToRgb(hex) {
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result
? {
r: parseInt(result[1], 16),
g: parseInt(result[2], 16),
b: parseInt(result[3], 16),
}
: null;
}
// Usage
const rgb = hexToRgb('#667eea');
const rgba = `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.3)`;
Ensure sufficient contrast for all themes:
// Check contrast ratio (WCAG AA requires 4.5:1 for normal text)
function getContrastRatio(color1, color2) {
const l1 = getLuminance(color1);
const l2 = getLuminance(color2);
const lighter = Math.max(l1, l2);
const darker = Math.min(l1, l2);
return (lighter + 0.05) / (darker + 0.05);
}
function getLuminance(hex) {
const rgb = hexToRgb(hex);
const [r, g, b] = [rgb.r, rgb.g, rgb.b].map(val => {
val = val / 255;
return val <= 0.03928
? val / 12.92
: Math.pow((val + 0.055) / 1.055, 2.4);
});
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
}
// Test all themes
const themes = {
default: { bg: '#0a0a0a', text: '#ffffff' },
warm: { bg: '#0a0a0a', text: '#FF8C42' },
cool: { bg: '#0a0a0a', text: '#06B6D4' },
premium: { bg: '#0a0a0a', text: '#D4AF37' },
};
Object.entries(themes).forEach(([name, colors]) => {
const ratio = getContrastRatio(colors.bg, colors.text);
console.log(
`${name} theme contrast: ${ratio.toFixed(2)}:1 ${ratio >= 4.5 ? '✓' : '✗'}`
);
});
Use this command to quickly apply a theme across the codebase:
# Find all hardcoded color references
grep -r "#667eea" site/src --include="*.tsx" --include="*.ts" --include="*.css"
# Replace with CSS variable (manual verification recommended)
find site/src -type f \( -name "*.tsx" -o -name "*.ts" -o -name "*.css" \) -exec sed -i 's/#667eea/var(--color-primary)/g' {} +
site/src/app/globals.csssite/src/components/ThemeSwitcher.tsxsite/src/components/ThemeAnalytics.tsxsrc/config/emotions-themed.jssite/src/app/page.tsxsite/src/app/use-cases/*/page.tsxThis skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.