/** * Asset Compatibility System * Defines compatibility rules between music, backgrounds, and avatar contexts */ (function() { 'use strict'; // ============================================================================ // MOOD → BACKGROUND THEME COMPATIBILITY // ============================================================================ var MOOD_BACKGROUND_COMPAT = { Epic: { excellent: ['space', 'fantasy', 'sports', 'sky'], good: ['urban', 'mechanical', 'nature'], neutral: ['retro', 'colorful', 'indoor'], poor: ['abstract'] }, Chill: { excellent: ['nature', 'underwater', 'indoor', 'seasonal'], good: ['sky', 'colorful', 'abstract'], neutral: ['fantasy', 'retro'], poor: ['urban', 'mechanical', 'spooky'] }, Intense: { excellent: ['urban', 'mechanical', 'sports', 'weather'], good: ['space', 'spooky', 'retro'], neutral: ['nature', 'sky'], poor: ['colorful', 'indoor', 'seasonal'] }, Playful: { excellent: ['colorful', 'retro', 'nature', 'indoor'], good: ['underwater', 'seasonal', 'abstract'], neutral: ['fantasy', 'sky'], poor: ['spooky', 'mechanical', 'urban'] }, Mysterious: { excellent: ['spooky', 'fantasy', 'underwater', 'weather'], good: ['nature', 'urban', 'abstract'], neutral: ['space', 'indoor'], poor: ['colorful', 'sports', 'retro'] }, Heroic: { excellent: ['space', 'fantasy', 'urban', 'sky'], good: ['nature', 'sports', 'mechanical'], neutral: ['retro', 'weather'], poor: ['indoor', 'colorful', 'abstract'] }, Quirky: { excellent: ['retro', 'colorful', 'abstract', 'indoor'], good: ['nature', 'mechanical', 'seasonal'], neutral: ['urban', 'fantasy'], poor: ['spooky', 'space', 'sports'] }, Ambient: { excellent: ['nature', 'underwater', 'sky', 'seasonal'], good: ['abstract', 'indoor', 'weather'], neutral: ['space', 'fantasy'], poor: ['urban', 'mechanical', 'sports', 'spooky'] } }; // ============================================================================ // BACKGROUND THEME → AVATAR CONTEXT COMPATIBILITY // ============================================================================ var THEME_CONTEXT_COMPAT = { space: { excellent: ['spaceship-cockpit', 'space-suit', 'mech-suit'], good: ['jetpack', 'platformer-standard', 'adventure-hero'], neutral: ['ninja-outfit', 'superhero-cape', 'wizard-robes'], poor: ['chef-outfit', 'cowboy-gear', 'pirate-outfit', 'race-car', 'submarine', 'hot-air-balloon'] }, fantasy: { excellent: ['knight-armor', 'wizard-robes', 'dragon-rider'], good: ['adventure-hero', 'ninja-outfit', 'fairy-wings'], neutral: ['platformer-standard', 'superhero-cape', 'pirate-outfit'], poor: ['race-car', 'motorcycle', 'submarine', 'spaceship-cockpit', 'space-suit', 'mech-suit'] }, nature: { excellent: ['adventure-hero', 'platformer-standard', 'fairy-wings'], good: ['ninja-outfit', 'cowboy-gear', 'safari-outfit'], neutral: ['wizard-robes', 'pirate-outfit', 'superhero-cape'], poor: ['race-car', 'motorcycle', 'submarine', 'spaceship-cockpit', 'mech-suit', 'skateboard'] }, urban: { excellent: ['skateboard', 'motorcycle', 'superhero-cape', 'parkour-outfit'], good: ['platformer-standard', 'ninja-outfit', 'race-car'], neutral: ['adventure-hero', 'chef-outfit', 'detective-outfit'], poor: ['dragon-rider', 'fairy-wings', 'pirate-outfit', 'submarine', 'space-suit', 'cowboy-gear'] }, underwater: { excellent: ['submarine', 'scuba-gear', 'mermaid-tail'], good: ['pirate-outfit', 'adventure-hero', 'platformer-standard'], neutral: ['ninja-outfit', 'wizard-robes', 'fairy-wings'], poor: ['race-car', 'motorcycle', 'skateboard', 'cowboy-gear', 'knight-armor', 'hot-air-balloon'] }, retro: { excellent: ['platformer-standard', 'arcade-classic', 'superhero-cape'], good: ['adventure-hero', 'ninja-outfit', 'skateboard'], neutral: ['wizard-robes', 'knight-armor', 'pirate-outfit'], poor: ['mech-suit', 'spaceship-cockpit', 'submarine', 'dragon-rider', 'safari-outfit'] }, sports: { excellent: ['race-car', 'motorcycle', 'skateboard', 'sports-uniform'], good: ['platformer-standard', 'adventure-hero', 'superhero-cape'], neutral: ['ninja-outfit', 'parkour-outfit', 'jetpack'], poor: ['wizard-robes', 'knight-armor', 'pirate-outfit', 'submarine', 'fairy-wings', 'mermaid-tail'] }, spooky: { excellent: ['wizard-robes', 'vampire-cloak', 'ghost-costume'], good: ['ninja-outfit', 'adventure-hero', 'detective-outfit'], neutral: ['platformer-standard', 'superhero-cape', 'pirate-outfit'], poor: ['fairy-wings', 'chef-outfit', 'sports-uniform', 'safari-outfit', 'hot-air-balloon', 'race-car'] }, colorful: { excellent: ['platformer-standard', 'superhero-cape', 'fairy-wings', 'arcade-classic'], good: ['adventure-hero', 'skateboard', 'jetpack'], neutral: ['ninja-outfit', 'wizard-robes', 'pirate-outfit'], poor: ['vampire-cloak', 'ghost-costume', 'detective-outfit', 'mech-suit'] }, mechanical: { excellent: ['mech-suit', 'race-car', 'motorcycle', 'jetpack'], good: ['spaceship-cockpit', 'ninja-outfit', 'superhero-cape'], neutral: ['platformer-standard', 'adventure-hero', 'skateboard'], poor: ['fairy-wings', 'wizard-robes', 'pirate-outfit', 'cowboy-gear', 'mermaid-tail', 'safari-outfit'] }, indoor: { excellent: ['platformer-standard', 'chef-outfit', 'detective-outfit', 'arcade-classic'], good: ['adventure-hero', 'ninja-outfit', 'superhero-cape'], neutral: ['wizard-robes', 'skateboard', 'parkour-outfit'], poor: ['submarine', 'race-car', 'motorcycle', 'dragon-rider', 'hot-air-balloon', 'safari-outfit'] }, sky: { excellent: ['jetpack', 'hot-air-balloon', 'dragon-rider', 'fairy-wings'], good: ['superhero-cape', 'spaceship-cockpit', 'platformer-standard'], neutral: ['adventure-hero', 'ninja-outfit', 'wizard-robes'], poor: ['submarine', 'race-car', 'motorcycle', 'skateboard', 'chef-outfit', 'mermaid-tail'] }, seasonal: { excellent: ['platformer-standard', 'adventure-hero', 'fairy-wings'], good: ['superhero-cape', 'wizard-robes', 'chef-outfit'], neutral: ['ninja-outfit', 'skateboard', 'detective-outfit'], poor: ['submarine', 'mech-suit', 'spaceship-cockpit', 'vampire-cloak', 'race-car'] }, weather: { excellent: ['adventure-hero', 'superhero-cape', 'wizard-robes'], good: ['platformer-standard', 'ninja-outfit', 'jetpack'], neutral: ['dragon-rider', 'hot-air-balloon', 'detective-outfit'], poor: ['submarine', 'race-car', 'chef-outfit', 'mermaid-tail', 'arcade-classic'] }, abstract: { excellent: ['platformer-standard', 'arcade-classic', 'superhero-cape'], good: ['adventure-hero', 'ninja-outfit', 'wizard-robes'], neutral: ['fairy-wings', 'jetpack', 'skateboard'], poor: ['cowboy-gear', 'safari-outfit', 'chef-outfit', 'detective-outfit', 'pirate-outfit'] } }; // ============================================================================ // CONTEXT → ANIMATION COMPATIBILITY // ============================================================================ var CONTEXT_ANIMATIONS = { 'spaceship-cockpit': { required: ['idle'], recommended: ['bob', 'hurt', 'celebrate'], incompatible: ['walk', 'run', 'jump', 'swim'] }, 'space-suit': { required: ['idle', 'walk'], recommended: ['jump', 'float', 'hurt', 'celebrate'], incompatible: ['swim'] }, 'mech-suit': { required: ['idle', 'walk'], recommended: ['attack', 'hurt', 'celebrate', 'stomp'], incompatible: ['swim', 'fly'] }, 'race-car': { required: ['idle'], recommended: ['hurt', 'celebrate', 'boost'], incompatible: ['walk', 'run', 'jump', 'fly', 'swim'] }, 'motorcycle': { required: ['idle'], recommended: ['hurt', 'celebrate', 'wheelie'], incompatible: ['walk', 'run', 'fly', 'swim'] }, 'submarine': { required: ['idle'], recommended: ['hurt', 'celebrate', 'dive'], incompatible: ['walk', 'run', 'jump', 'fly'] }, 'platformer-standard': { required: ['idle', 'walk', 'jump'], recommended: ['run', 'fall', 'hurt', 'celebrate', 'crouch'], incompatible: [] }, 'adventure-hero': { required: ['idle', 'walk', 'jump'], recommended: ['run', 'attack', 'hurt', 'celebrate', 'climb'], incompatible: [] }, 'ninja-outfit': { required: ['idle', 'walk', 'jump'], recommended: ['run', 'attack', 'throw', 'hurt', 'celebrate', 'crouch', 'wallslide'], incompatible: [] }, 'knight-armor': { required: ['idle', 'walk'], recommended: ['attack', 'block', 'hurt', 'celebrate'], incompatible: ['fly', 'swim'] }, 'wizard-robes': { required: ['idle', 'walk'], recommended: ['cast', 'float', 'hurt', 'celebrate', 'teleport'], incompatible: [] }, 'dragon-rider': { required: ['idle', 'fly'], recommended: ['attack', 'hurt', 'celebrate', 'dive', 'breathe-fire'], incompatible: ['walk', 'run', 'swim'] }, 'fairy-wings': { required: ['idle', 'fly'], recommended: ['hover', 'hurt', 'celebrate', 'sparkle'], incompatible: ['swim'] }, 'jetpack': { required: ['idle', 'fly'], recommended: ['boost', 'hurt', 'celebrate', 'hover'], incompatible: ['swim'] }, 'hot-air-balloon': { required: ['idle'], recommended: ['float', 'hurt', 'celebrate'], incompatible: ['walk', 'run', 'jump', 'swim', 'attack'] }, 'pirate-outfit': { required: ['idle', 'walk'], recommended: ['attack', 'jump', 'hurt', 'celebrate', 'swim'], incompatible: ['fly'] }, 'cowboy-gear': { required: ['idle', 'walk'], recommended: ['shoot', 'jump', 'hurt', 'celebrate', 'lasso'], incompatible: ['fly', 'swim'] }, 'superhero-cape': { required: ['idle', 'walk', 'fly'], recommended: ['run', 'jump', 'attack', 'hurt', 'celebrate', 'land'], incompatible: [] }, 'skateboard': { required: ['idle'], recommended: ['trick', 'grind', 'hurt', 'celebrate', 'push'], incompatible: ['walk', 'run', 'fly', 'swim'] }, 'scuba-gear': { required: ['idle', 'swim'], recommended: ['dive', 'hurt', 'celebrate'], incompatible: ['walk', 'run', 'jump', 'fly'] }, 'mermaid-tail': { required: ['idle', 'swim'], recommended: ['dive', 'hurt', 'celebrate', 'splash'], incompatible: ['walk', 'run', 'jump', 'fly'] }, 'chef-outfit': { required: ['idle', 'walk'], recommended: ['chop', 'throw', 'hurt', 'celebrate'], incompatible: ['fly', 'swim'] }, 'safari-outfit': { required: ['idle', 'walk'], recommended: ['run', 'jump', 'hurt', 'celebrate', 'crouch'], incompatible: ['fly'] }, 'vampire-cloak': { required: ['idle', 'walk'], recommended: ['attack', 'fly', 'hurt', 'celebrate', 'transform'], incompatible: ['swim'] }, 'ghost-costume': { required: ['idle', 'float'], recommended: ['fly', 'phase', 'hurt', 'celebrate', 'fade'], incompatible: ['walk', 'run', 'swim'] }, 'detective-outfit': { required: ['idle', 'walk'], recommended: ['run', 'crouch', 'hurt', 'celebrate', 'inspect'], incompatible: ['fly', 'swim'] }, 'parkour-outfit': { required: ['idle', 'walk', 'run', 'jump'], recommended: ['wallrun', 'vault', 'roll', 'hurt', 'celebrate', 'climb'], incompatible: ['fly', 'swim'] }, 'arcade-classic': { required: ['idle', 'walk'], recommended: ['jump', 'hurt', 'celebrate'], incompatible: [] }, 'sports-uniform': { required: ['idle', 'walk', 'run'], recommended: ['jump', 'kick', 'throw', 'hurt', 'celebrate'], incompatible: ['fly', 'swim'] } }; // ============================================================================ // COLOR PALETTE HARMONY // ============================================================================ var PALETTE_HARMONY = { 'space-blue': { harmonious: ['fantasy-purple', 'ocean-teal', 'spooky-grey', 'cyber-neon'], neutral: ['nature-green', 'retro-warm', 'neutral-earth'], clash: ['sunset-orange', 'sports-red', 'candy-rainbow'] }, 'fantasy-purple': { harmonious: ['space-blue', 'spooky-grey', 'cyber-neon', 'sunset-orange'], neutral: ['nature-green', 'ocean-teal', 'neutral-earth'], clash: ['sports-red', 'candy-rainbow', 'retro-warm'] }, 'nature-green': { harmonious: ['ocean-teal', 'neutral-earth', 'sunset-orange', 'retro-warm'], neutral: ['space-blue', 'fantasy-purple', 'candy-rainbow'], clash: ['cyber-neon', 'spooky-grey', 'sports-red'] }, 'ocean-teal': { harmonious: ['space-blue', 'nature-green', 'fantasy-purple', 'neutral-earth'], neutral: ['cyber-neon', 'spooky-grey', 'retro-warm'], clash: ['sports-red', 'candy-rainbow', 'sunset-orange'] }, 'sunset-orange': { harmonious: ['fantasy-purple', 'nature-green', 'retro-warm', 'neutral-earth'], neutral: ['spooky-grey', 'candy-rainbow', 'sports-red'], clash: ['space-blue', 'ocean-teal', 'cyber-neon'] }, 'sports-red': { harmonious: ['neutral-earth', 'spooky-grey', 'retro-warm'], neutral: ['sunset-orange', 'candy-rainbow', 'fantasy-purple'], clash: ['space-blue', 'ocean-teal', 'nature-green', 'cyber-neon'] }, 'retro-warm': { harmonious: ['sunset-orange', 'nature-green', 'neutral-earth', 'sports-red'], neutral: ['fantasy-purple', 'candy-rainbow', 'spooky-grey'], clash: ['space-blue', 'ocean-teal', 'cyber-neon'] }, 'spooky-grey': { harmonious: ['space-blue', 'fantasy-purple', 'cyber-neon', 'sports-red'], neutral: ['neutral-earth', 'ocean-teal', 'retro-warm'], clash: ['candy-rainbow', 'nature-green', 'sunset-orange'] }, 'candy-rainbow': { harmonious: ['retro-warm', 'sunset-orange', 'fantasy-purple'], neutral: ['nature-green', 'sports-red', 'neutral-earth'], clash: ['space-blue', 'ocean-teal', 'spooky-grey', 'cyber-neon'] }, 'cyber-neon': { harmonious: ['space-blue', 'fantasy-purple', 'spooky-grey'], neutral: ['ocean-teal', 'neutral-earth', 'candy-rainbow'], clash: ['nature-green', 'sunset-orange', 'retro-warm', 'sports-red'] }, 'neutral-earth': { harmonious: ['nature-green', 'ocean-teal', 'retro-warm', 'sunset-orange'], neutral: ['space-blue', 'fantasy-purple', 'sports-red', 'spooky-grey'], clash: ['candy-rainbow', 'cyber-neon'] } }; // ============================================================================ // ENERGY LEVEL MAPPINGS // ============================================================================ var MOOD_ENERGY = { Epic: 'high', Chill: 'low', Intense: 'high', Playful: 'medium', Mysterious: 'low', Heroic: 'high', Quirky: 'medium', Ambient: 'low' }; var CONTEXT_ENERGY = { 'spaceship-cockpit': 'medium', 'space-suit': 'medium', 'mech-suit': 'high', 'race-car': 'high', 'motorcycle': 'high', 'submarine': 'low', 'platformer-standard': 'medium', 'adventure-hero': 'medium', 'ninja-outfit': 'high', 'knight-armor': 'medium', 'wizard-robes': 'medium', 'dragon-rider': 'high', 'fairy-wings': 'low', 'jetpack': 'high', 'hot-air-balloon': 'low', 'pirate-outfit': 'medium', 'cowboy-gear': 'medium', 'superhero-cape': 'high', 'skateboard': 'high', 'scuba-gear': 'low', 'mermaid-tail': 'low', 'chef-outfit': 'low', 'safari-outfit': 'medium', 'vampire-cloak': 'medium', 'ghost-costume': 'low', 'detective-outfit': 'low', 'parkour-outfit': 'high', 'arcade-classic': 'medium', 'sports-uniform': 'high' }; // ============================================================================ // THEME → DEFAULT PALETTE MAPPING // ============================================================================ var THEME_DEFAULT_PALETTES = { space: ['space-blue', 'cyber-neon', 'spooky-grey'], fantasy: ['fantasy-purple', 'nature-green', 'sunset-orange'], nature: ['nature-green', 'neutral-earth', 'ocean-teal'], urban: ['neutral-earth', 'spooky-grey', 'cyber-neon'], underwater: ['ocean-teal', 'space-blue', 'nature-green'], retro: ['retro-warm', 'candy-rainbow', 'sunset-orange'], sports: ['sports-red', 'neutral-earth', 'cyber-neon'], spooky: ['spooky-grey', 'fantasy-purple', 'cyber-neon'], colorful: ['candy-rainbow', 'sunset-orange', 'fantasy-purple'], mechanical: ['spooky-grey', 'cyber-neon', 'sports-red'], indoor: ['neutral-earth', 'retro-warm', 'sunset-orange'], sky: ['space-blue', 'sunset-orange', 'ocean-teal'], seasonal: ['nature-green', 'sunset-orange', 'neutral-earth'], weather: ['spooky-grey', 'space-blue', 'nature-green'], abstract: ['cyber-neon', 'candy-rainbow', 'fantasy-purple'] }; // ============================================================================ // MECHANICS → CONTEXT MAPPING // ============================================================================ var MECHANICS_CONTEXTS = { flying: ['dragon-rider', 'fairy-wings', 'jetpack', 'superhero-cape', 'hot-air-balloon'], racing: ['race-car', 'motorcycle', 'skateboard'], platforming: ['platformer-standard', 'adventure-hero', 'ninja-outfit', 'parkour-outfit', 'arcade-classic'], swimming: ['submarine', 'scuba-gear', 'mermaid-tail'], combat: ['knight-armor', 'ninja-outfit', 'superhero-cape', 'mech-suit', 'wizard-robes'], exploration: ['adventure-hero', 'safari-outfit', 'detective-outfit', 'pirate-outfit'], puzzle: ['platformer-standard', 'detective-outfit', 'wizard-robes', 'arcade-classic'], stealth: ['ninja-outfit', 'ghost-costume', 'vampire-cloak', 'detective-outfit'], cooking: ['chef-outfit'], sports: ['sports-uniform', 'skateboard'] }; // ============================================================================ // VALIDATION FUNCTIONS // ============================================================================ /** * Get mood-background compatibility level * @param {string} mood - Music mood * @param {string} theme - Background theme * @returns {string} - 'excellent', 'good', 'neutral', or 'poor' */ function getMoodBackgroundCompat(mood, theme) { var compat = MOOD_BACKGROUND_COMPAT[mood]; if (!compat) return 'neutral'; if (compat.excellent && compat.excellent.indexOf(theme) !== -1) return 'excellent'; if (compat.good && compat.good.indexOf(theme) !== -1) return 'good'; if (compat.poor && compat.poor.indexOf(theme) !== -1) return 'poor'; return 'neutral'; } /** * Get theme-context compatibility level * @param {string} theme - Background theme * @param {string} context - Avatar context * @returns {string} - 'excellent', 'good', 'neutral', or 'poor' */ function getThemeContextCompat(theme, context) { var compat = THEME_CONTEXT_COMPAT[theme]; if (!compat) return 'neutral'; if (compat.excellent && compat.excellent.indexOf(context) !== -1) return 'excellent'; if (compat.good && compat.good.indexOf(context) !== -1) return 'good'; if (compat.poor && compat.poor.indexOf(context) !== -1) return 'poor'; return 'neutral'; } /** * Get context-animation compatibility * @param {string} context - Avatar context * @param {string} animation - Animation name * @returns {string} - 'required', 'recommended', 'compatible', or 'incompatible' */ function getContextAnimationCompat(context, animation) { var compat = CONTEXT_ANIMATIONS[context]; if (!compat) return 'compatible'; if (compat.required && compat.required.indexOf(animation) !== -1) return 'required'; if (compat.recommended && compat.recommended.indexOf(animation) !== -1) return 'recommended'; if (compat.incompatible && compat.incompatible.indexOf(animation) !== -1) return 'incompatible'; return 'compatible'; } /** * Get palette harmony level * @param {string} palette1 - First palette * @param {string} palette2 - Second palette * @returns {string} - 'harmonious', 'neutral', or 'clash' */ function getPaletteHarmony(palette1, palette2) { if (palette1 === palette2) return 'harmonious'; var compat = PALETTE_HARMONY[palette1]; if (!compat) return 'neutral'; if (compat.harmonious && compat.harmonious.indexOf(palette2) !== -1) return 'harmonious'; if (compat.clash && compat.clash.indexOf(palette2) !== -1) return 'clash'; return 'neutral'; } /** * Check energy level compatibility * @param {string} moodEnergy - Music energy level * @param {string} contextEnergy - Context energy level * @returns {string} - 'match', 'close', or 'mismatch' */ function getEnergyCompat(moodEnergy, contextEnergy) { if (moodEnergy === contextEnergy) return 'match'; var levels = ['low', 'medium', 'high']; var diff = Math.abs(levels.indexOf(moodEnergy) - levels.indexOf(contextEnergy)); return diff === 1 ? 'close' : 'mismatch'; } /** * Validate a complete asset configuration * @param {Object} config - Configuration object with music, background, avatarContext, palette * @returns {Object} - { valid, score, issues } */ function validate(config) { var issues = []; var score = 100; // Check music/background compatibility if (config.music && config.background) { var mood = config.music.mood || config.music; var theme = config.background.theme || config.background; var compat = getMoodBackgroundCompat(mood, theme); if (compat === 'poor') { issues.push({ type: 'warning', category: 'mood-background', message: 'Music mood "' + mood + '" doesn\'t match background theme "' + theme + '" well' }); score -= 15; } else if (compat === 'neutral') { score -= 5; } else if (compat === 'excellent') { score += 10; } else if (compat === 'good') { score += 5; } } // Check background/context compatibility if (config.background && config.avatarContext) { var theme = config.background.theme || config.background; var context = config.avatarContext.context || config.avatarContext; var compat = getThemeContextCompat(theme, context); if (compat === 'poor') { issues.push({ type: 'warning', category: 'theme-context', message: 'Avatar context "' + context + '" doesn\'t fit background theme "' + theme + '"' }); score -= 20; } else if (compat === 'excellent') { score += 10; } else if (compat === 'good') { score += 5; } } // Check energy level appropriateness if (config.music && config.avatarContext) { var mood = config.music.mood || config.music; var context = config.avatarContext.context || config.avatarContext; var moodEnergy = MOOD_ENERGY[mood]; var contextEnergy = CONTEXT_ENERGY[context]; if (moodEnergy && contextEnergy) { var energyCompat = getEnergyCompat(moodEnergy, contextEnergy); if (energyCompat === 'mismatch') { issues.push({ type: 'info', category: 'energy', message: 'Music energy (' + moodEnergy + ') doesn\'t match avatar context energy (' + contextEnergy + ')' }); score -= 10; } else if (energyCompat === 'match') { score += 5; } } } // Check palette harmony with theme if (config.palette && config.background) { var theme = config.background.theme || config.background; var palette = config.palette.name || config.palette; var themePalettes = THEME_DEFAULT_PALETTES[theme]; if (themePalettes) { if (themePalettes.indexOf(palette) === -1) { // Check if it's harmonious with any default palette var hasHarmony = false; for (var i = 0; i < themePalettes.length; i++) { if (getPaletteHarmony(palette, themePalettes[i]) === 'harmonious') { hasHarmony = true; break; } } if (!hasHarmony) { var clashes = false; for (var i = 0; i < themePalettes.length; i++) { if (getPaletteHarmony(palette, themePalettes[i]) === 'clash') { clashes = true; break; } } if (clashes) { issues.push({ type: 'info', category: 'palette', message: 'Color palette "' + palette + '" may clash with theme "' + theme + '"' }); score -= 5; } } } else { score += 5; } } } // Check animation compatibility with context if (config.avatarContext && config.animations) { var context = config.avatarContext.context || config.avatarContext; var contextAnims = CONTEXT_ANIMATIONS[context]; if (contextAnims) { // Check for missing required animations var animations = Array.isArray(config.animations) ? config.animations : [config.animations]; if (contextAnims.required) { for (var i = 0; i < contextAnims.required.length; i++) { var required = contextAnims.required[i]; if (animations.indexOf(required) === -1) { issues.push({ type: 'error', category: 'animation', message: 'Context "' + context + '" requires animation "' + required + '"' }); score -= 25; } } } // Check for incompatible animations if (contextAnims.incompatible) { for (var i = 0; i < animations.length; i++) { if (contextAnims.incompatible.indexOf(animations[i]) !== -1) { issues.push({ type: 'warning', category: 'animation', message: 'Animation "' + animations[i] + '" is incompatible with context "' + context + '"' }); score -= 10; } } } } } return { valid: issues.filter(function(i) { return i.type === 'error'; }).length === 0, score: Math.max(0, Math.min(100, score)), issues: issues }; } // ============================================================================ // SUGGESTION FUNCTIONS // ============================================================================ /** * Get compatible music moods for a background theme * @param {string} theme - Background theme * @returns {Array} - Sorted array of { mood, compatibility } */ function getMusicForTheme(theme) { var results = []; var moods = Object.keys(MOOD_BACKGROUND_COMPAT); for (var i = 0; i < moods.length; i++) { var mood = moods[i]; var compat = getMoodBackgroundCompat(mood, theme); results.push({ mood: mood, compatibility: compat }); } // Sort by compatibility var order = { excellent: 0, good: 1, neutral: 2, poor: 3 }; results.sort(function(a, b) { return order[a.compatibility] - order[b.compatibility]; }); return results; } /** * Get compatible background themes for a music mood * @param {string} mood - Music mood * @returns {Array} - Sorted array of { theme, compatibility } */ function getBackgroundsForMood(mood) { var compat = MOOD_BACKGROUND_COMPAT[mood]; if (!compat) return []; var results = []; var allThemes = Object.keys(THEME_CONTEXT_COMPAT); for (var i = 0; i < allThemes.length; i++) { var theme = allThemes[i]; var level = getMoodBackgroundCompat(mood, theme); results.push({ theme: theme, compatibility: level }); } var order = { excellent: 0, good: 1, neutral: 2, poor: 3 }; results.sort(function(a, b) { return order[a.compatibility] - order[b.compatibility]; }); return results; } /** * Get compatible contexts for game mechanics * @param {Array|string} mechanics - Game mechanics * @returns {Array} - Array of context names with relevance scores */ function getContextsForMechanics(mechanics) { var mechs = Array.isArray(mechanics) ? mechanics : [mechanics]; var contextScores = {}; for (var i = 0; i < mechs.length; i++) { var mech = mechs[i]; var contexts = MECHANICS_CONTEXTS[mech]; if (contexts) { for (var j = 0; j < contexts.length; j++) { var ctx = contexts[j]; contextScores[ctx] = (contextScores[ctx] || 0) + 1; } } } var results = []; var ctxNames = Object.keys(contextScores); for (var i = 0; i < ctxNames.length; i++) { results.push({ context: ctxNames[i], relevance: contextScores[ctxNames[i]] / mechs.length }); } results.sort(function(a, b) { return b.relevance - a.relevance; }); return results; } /** * Get compatible contexts for a background theme * @param {string} theme - Background theme * @returns {Array} - Sorted array of { context, compatibility } */ function getContextsForTheme(theme) { var compat = THEME_CONTEXT_COMPAT[theme]; if (!compat) return []; var results = []; var allContexts = Object.keys(CONTEXT_ANIMATIONS); for (var i = 0; i < allContexts.length; i++) { var context = allContexts[i]; var level = getThemeContextCompat(theme, context); results.push({ context: context, compatibility: level }); } var order = { excellent: 0, good: 1, neutral: 2, poor: 3 }; results.sort(function(a, b) { return order[a.compatibility] - order[b.compatibility]; }); return results; } /** * Get compatible palettes for a background theme * @param {string} theme - Background theme * @returns {Array} - Array of palette names with compatibility */ function getPalettesForTheme(theme) { var defaultPalettes = THEME_DEFAULT_PALETTES[theme] || []; var results = []; var allPalettes = Object.keys(PALETTE_HARMONY); for (var i = 0; i < allPalettes.length; i++) { var palette = allPalettes[i]; var isDefault = defaultPalettes.indexOf(palette) !== -1; // Check harmony with default palettes var harmony = 'neutral'; if (isDefault) { harmony = 'excellent'; } else { for (var j = 0; j < defaultPalettes.length; j++) { var h = getPaletteHarmony(palette, defaultPalettes[j]); if (h === 'harmonious') { harmony = 'good'; break; } else if (h === 'clash') { harmony = 'poor'; } } } results.push({ palette: palette, compatibility: harmony }); } var order = { excellent: 0, good: 1, neutral: 2, poor: 3 }; results.sort(function(a, b) { return order[a.compatibility] - order[b.compatibility]; }); return results; } /** * Suggest improvements for a configuration * @param {Object} config - Current configuration * @returns {Array} - Array of suggestion objects */ function suggestImprovements(config) { var suggestions = []; var validation = validate(config); if (validation.score >= 90) { return suggestions; } // Analyze each issue and suggest fixes for (var i = 0; i < validation.issues.length; i++) { var issue = validation.issues[i]; if (issue.category === 'mood-background') { var theme = config.background.theme || config.background; var betterMoods = getMusicForTheme(theme) .filter(function(m) { return m.compatibility === 'excellent' || m.compatibility === 'good'; }) .slice(0, 3); if (betterMoods.length > 0) { suggestions.push({ type: 'music', message: 'Consider using music with mood: ' + betterMoods.map(function(m) { return m.mood; }).join(', '), options: betterMoods }); } } if (issue.category === 'theme-context') { var context = config.avatarContext.context || config.avatarContext; // Find better themes for this context var betterThemes = []; var themes = Object.keys(THEME_CONTEXT_COMPAT); for (var j = 0; j < themes.length; j++) { var compat = getThemeContextCompat(themes[j], context); if (compat === 'excellent' || compat === 'good') { betterThemes.push({ theme: themes[j], compatibility: compat }); } } if (betterThemes.length > 0) { suggestions.push({ type: 'background', message: 'Consider using background theme: ' + betterThemes.slice(0, 3).map(function(t) { return t.theme; }).join(', '), options: betterThemes.slice(0, 5) }); } // Also suggest better contexts for current theme var theme = config.background.theme || config.background; var betterContexts = getContextsForTheme(theme) .filter(function(c) { return c.compatibility === 'excellent' || c.compatibility === 'good'; }) .slice(0, 5); if (betterContexts.length > 0) { suggestions.push({ type: 'context', message: 'Or consider avatar context: ' + betterContexts.slice(0, 3).map(function(c) { return c.context; }).join(', '), options: betterContexts }); } } if (issue.category === 'energy') { var mood = config.music.mood || config.music; var moodEnergy = MOOD_ENERGY[mood]; // Find contexts with matching energy var matchingContexts = []; var contexts = Object.keys(CONTEXT_ENERGY); for (var j = 0; j < contexts.length; j++) { if (CONTEXT_ENERGY[contexts[j]] === moodEnergy) { matchingContexts.push(contexts[j]); } } if (matchingContexts.length > 0) { suggestions.push({ type: 'context', message: 'For ' + moodEnergy + ' energy music, consider: ' + matchingContexts.slice(0, 4).join(', '), options: matchingContexts.slice(0, 6).map(function(c) { return { context: c, energy: moodEnergy }; }) }); } } if (issue.category === 'animation' && issue.type === 'error') { var context = config.avatarContext.context || config.avatarContext; var contextAnims = CONTEXT_ANIMATIONS[context]; if (contextAnims && contextAnims.required) { suggestions.push({ type: 'animation', message: 'Required animations for "' + context + '": ' + contextAnims.required.join(', '), options: contextAnims.required }); } } if (issue.category === 'palette') { var theme = config.background.theme || config.background; var betterPalettes = getPalettesForTheme(theme) .filter(function(p) { return p.compatibility === 'excellent' || p.compatibility === 'good'; }) .slice(0, 5); if (betterPalettes.length > 0) { suggestions.push({ type: 'palette', message: 'Better palettes for "' + theme + '": ' + betterPalettes.map(function(p) { return p.palette; }).join(', '), options: betterPalettes }); } } } return suggestions; } // ============================================================================ // CONVENIENCE FUNCTIONS // ============================================================================ /** * Get backgrounds compatible with a music mood * @param {string} mood - Music mood * @returns {Array} - Array of theme names (excellent and good only) */ function getCompatibleBackgrounds(mood) { return getBackgroundsForMood(mood) .filter(function(b) { return b.compatibility === 'excellent' || b.compatibility === 'good'; }) .map(function(b) { return b.theme; }); } /** * Get contexts compatible with a background theme * @param {string} theme - Background theme * @returns {Array} - Array of context names (excellent and good only) */ function getCompatibleContexts(theme) { return getContextsForTheme(theme) .filter(function(c) { return c.compatibility === 'excellent' || c.compatibility === 'good'; }) .map(function(c) { return c.context; }); } /** * Get palettes compatible with a background theme * @param {string} theme - Background theme * @returns {Array} - Array of palette names (excellent and good only) */ function getCompatiblePalettes(theme) { return getPalettesForTheme(theme) .filter(function(p) { return p.compatibility === 'excellent' || p.compatibility === 'good'; }) .map(function(p) { return p.palette; }); } /** * Get required animations for a context * @param {string} context - Avatar context * @returns {Array} - Array of required animation names */ function getRequiredAnimations(context) { var anims = CONTEXT_ANIMATIONS[context]; return anims ? (anims.required || []) : []; } /** * Get recommended animations for a context * @param {string} context - Avatar context * @returns {Array} - Array of recommended animation names */ function getRecommendedAnimations(context) { var anims = CONTEXT_ANIMATIONS[context]; return anims ? (anims.recommended || []) : []; } /** * Get all valid animations for a context * @param {string} context - Avatar context * @returns {Object} - { required, recommended, compatible } */ function getValidAnimations(context) { var anims = CONTEXT_ANIMATIONS[context]; if (!anims) { return { required: [], recommended: [], incompatible: [] }; } return { required: anims.required || [], recommended: anims.recommended || [], incompatible: anims.incompatible || [] }; } /** * Check if a complete asset set is compatible * @param {string} mood - Music mood * @param {string} theme - Background theme * @param {string} context - Avatar context * @returns {Object} - { compatible, score, issues } */ function checkFullCompatibility(mood, theme, context) { return validate({ music: { mood: mood }, background: { theme: theme }, avatarContext: { context: context } }); } // ============================================================================ // PUBLIC API // ============================================================================ window.AssetCompatibility = { // Validation validate: validate, checkFullCompatibility: checkFullCompatibility, // Compatibility checks getMoodBackgroundCompat: getMoodBackgroundCompat, getThemeContextCompat: getThemeContextCompat, getContextAnimationCompat: getContextAnimationCompat, getPaletteHarmony: getPaletteHarmony, // Suggestions getMusicForTheme: getMusicForTheme, getBackgroundsForMood: getBackgroundsForMood, getContextsForTheme: getContextsForTheme, getContextsForMechanics: getContextsForMechanics, getPalettesForTheme: getPalettesForTheme, suggestImprovements: suggestImprovements, // Get compatible options (convenience methods) getCompatibleBackgrounds: getCompatibleBackgrounds, getCompatibleContexts: getCompatibleContexts, getCompatiblePalettes: getCompatiblePalettes, // Animation helpers getRequiredAnimations: getRequiredAnimations, getRecommendedAnimations: getRecommendedAnimations, getValidAnimations: getValidAnimations, // Raw data MOOD_BACKGROUND_COMPAT: MOOD_BACKGROUND_COMPAT, THEME_CONTEXT_COMPAT: THEME_CONTEXT_COMPAT, CONTEXT_ANIMATIONS: CONTEXT_ANIMATIONS, PALETTE_HARMONY: PALETTE_HARMONY, MOOD_ENERGY: MOOD_ENERGY, CONTEXT_ENERGY: CONTEXT_ENERGY, THEME_DEFAULT_PALETTES: THEME_DEFAULT_PALETTES, MECHANICS_CONTEXTS: MECHANICS_CONTEXTS }; })();