git clone https://github.com/majiayu000/claude-skill-registry-data
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry-data "$T" && mkdir -p ~/.claude/skills && cp -r "$T/data/mascot-integrator" ~/.claude/skills/majiayu000-claude-skill-registry-data-mascot-integrator && rm -rf "$T"
data/mascot-integrator/SKILL.mdMascot Integrator
You are an expert in integrating the emotive-mascot engine into various applications, frameworks, and use cases.
When to Use This Skill
- Adding mascot to a new use case or page
- Setting up mascot in different frameworks (React, Vue, Svelte, vanilla JS)
- Creating custom interaction patterns
- Configuring mascot for specific contexts
- Implementing LLM-driven emotion responses
- Troubleshooting integration issues
Quick Start Patterns
Vanilla JavaScript
<!DOCTYPE html> <html> <head> <script src="https://unpkg.com/@joshtol/emotive-engine@latest"></script> </head> <body> <canvas id="mascot-canvas"></canvas> <script> const mascot = new EmotiveMascot({ containerId: 'mascot-canvas', width: 400, height: 400, initialEmotion: 'calm' }) await mascot.initialize() await mascot.transitionTo('joy') </script> </body> </html>
React (Next.js App Router)
'use client'; import { useEffect, useRef, useState } from 'react'; export default function MascotDemo() { const canvasRef = useRef<HTMLCanvasElement>(null); const mascotRef = useRef<any>(null); const [isClient, setIsClient] = useState(false); useEffect(() => { setIsClient(true); }, []); useEffect(() => { if (!isClient || !canvasRef.current) return; const initMascot = async () => { const { EmotiveMascot } = await import('@joshtol/emotive-engine'); mascotRef.current = new EmotiveMascot({ canvas: canvasRef.current, width: 400, height: 400, initialEmotion: 'calm', enableGazeTracking: true, }); await mascotRef.current.initialize(); }; initMascot(); return () => { mascotRef.current?.destroy(); }; }, [isClient]); const handleEmotionChange = async (emotion: string) => { await mascotRef.current?.transitionTo(emotion, { duration: 1000 }); }; if (!isClient) return null; return ( <div> <canvas ref={canvasRef} /> <button onClick={() => handleEmotionChange('joy')}>Joy</button> <button onClick={() => handleEmotionChange('excitement')}> Excitement </button> </div> ); }
Vue 3
<template> <div> <canvas ref="mascotCanvas"></canvas> <button @click="changeEmotion('joy')">Joy</button> </div> </template> <script setup> import { ref, onMounted, onUnmounted } from 'vue'; const mascotCanvas = ref(null); let mascot = null; onMounted(async () => { const { EmotiveMascot } = await import('@joshtol/emotive-engine'); mascot = new EmotiveMascot({ canvas: mascotCanvas.value, width: 400, height: 400, initialEmotion: 'calm', }); await mascot.initialize(); }); onUnmounted(() => { mascot?.destroy(); }); const changeEmotion = async emotion => { await mascot?.transitionTo(emotion); }; </script>
Use Case Patterns
1. Retail Checkout Assistant
Context: Shopping cart, payment processing, item scanning Emotions: calm → anticipation (scanning) → joy (success) → concern (error)
const mascot = new EmotiveMascot({ containerId: 'checkout-mascot', initialEmotion: 'calm', enableGazeTracking: true, scrollReactive: false, // Fixed position at checkout }); // Item scanned successfully async function onItemScanned() { await mascot.playPerformance('itemScanned', { steps: [ { emotion: 'anticipation', duration: 300 }, { emotion: 'joy', duration: 800, gesture: 'bounce' }, ], }); } // Payment processing async function onPaymentProcessing() { await mascot.transitionTo('anticipation', { duration: 500 }); // Show loading state } // Payment success async function onPaymentSuccess() { await mascot.playPerformance('celebration'); } // Error occurred async function onError(errorType) { await mascot.transitionTo('concern', { duration: 800 }); }
2. Smart Home Dashboard
Context: Device control, status monitoring, voice commands Emotions: calm → focus (listening) → joy (command success)
const mascot = new EmotiveMascot({ containerId: 'smarthome-mascot', initialEmotion: 'calm', enableGazeTracking: true, scrollReactive: true, audioEnabled: true, // Enable audio feedback }); // Voice command started async function onVoiceStart() { await mascot.transitionTo('focus', { duration: 400 }); } // Command recognized async function onCommandRecognized(command) { await mascot.transitionTo('anticipation', { duration: 300 }); } // Device controlled successfully async function onDeviceControlled(device) { await mascot.playPerformance('success', { steps: [ { emotion: 'joy', duration: 600, gesture: 'pulse' }, { emotion: 'calm', duration: 800 }, ], }); }
3. Healthcare Patient Intake
Context: Form filling, health questions, appointment scheduling Emotions: calm → empathy → reassurance
const mascot = new EmotiveMascot({ containerId: 'patient-mascot', initialEmotion: 'calm', enableGazeTracking: true, scrollReactive: false, }); // Sensitive question async function onSensitiveQuestion() { await mascot.transitionTo('empathy', { duration: 1000 }); } // Form validation error async function onValidationError() { await mascot.transitionTo('concern', { duration: 600 }); } // Form submitted async function onFormSubmitted() { await mascot.playPerformance('reassurance', { steps: [ { emotion: 'gratitude', duration: 800 }, { emotion: 'calm', duration: 600 }, ], }); }
4. Education / Learning Platform
Context: Quiz, lessons, progress tracking Emotions: calm → encouragement → celebration (correct) → empathy (incorrect)
const mascot = new EmotiveMascot({ containerId: 'learning-mascot', initialEmotion: 'calm', enableGazeTracking: true, }); // Correct answer async function onCorrectAnswer() { await mascot.playPerformance('celebration', { steps: [ { emotion: 'joy', duration: 600, gesture: 'bounce' }, { emotion: 'pride', duration: 800, gesture: 'shimmer' }, ], }); } // Incorrect answer async function onIncorrectAnswer() { await mascot.playPerformance('encouragement', { steps: [ { emotion: 'empathy', duration: 600 }, { emotion: 'encouragement', duration: 800 }, ], }); } // Lesson completed async function onLessonComplete() { await mascot.playPerformance('achievement'); }
LLM Integration Pattern
Connect mascot to Claude, GPT, or other LLMs for sentiment-driven emotions:
import { LLMEmotionPlugin } from '@joshtol/emotive-engine'; const mascot = new EmotiveMascot({ containerId: 'ai-mascot', initialEmotion: 'calm', plugins: [ new LLMEmotionPlugin({ provider: 'anthropic', // or 'openai' apiKey: process.env.ANTHROPIC_API_KEY, autoDetect: true, // Automatically detect sentiment }), ], }); // Handle LLM response async function onLLMResponse(message) { // Plugin automatically detects sentiment and transitions emotion await mascot.handleLLMMessage(message); } // Manual sentiment override async function onUserMessage(message) { if (message.includes('error') || message.includes('problem')) { await mascot.transitionTo('concern', { duration: 800 }); } else if (message.includes('thank') || message.includes('great')) { await mascot.transitionTo('gratitude', { duration: 600 }); } }
Configuration Options
Essential Options
{ // Container (choose one) containerId: 'my-canvas', // ID of canvas element canvas: canvasElement, // Direct canvas reference // Dimensions width: 400, // Canvas width height: 400, // Canvas height // Initial state initialEmotion: 'calm', // Starting emotion // Interactivity enableGazeTracking: true, // Follow mouse/touch scrollReactive: true, // React to page scroll clickReactive: true, // React to clicks // Performance targetFPS: 60, // Target frame rate pixelRatio: window.devicePixelRatio, // Display quality // Features audioEnabled: false, // Audio synthesis plugins: [] // Additional plugins }
Advanced Options
{ // Accessibility ariaLabel: 'Interactive mascot', reducedMotion: false, // Respect prefers-reduced-motion // Debug debug: false, // Show FPS and debug info // Custom behaviors onEmotionChange: (emotion) => { console.log('Emotion changed to:', emotion) }, onGestureComplete: (gesture) => { console.log('Gesture completed:', gesture) }, onPerformanceComplete: (performance) => { console.log('Performance completed:', performance) } }
Common Integration Patterns
Fixed Position Mascot
#mascot-canvas { position: fixed; bottom: 20px; right: 20px; z-index: 1000; border-radius: 50%; box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3); }
Scroll-Reactive Hero Section
const mascot = new EmotiveMascot({ containerId: 'hero-mascot', scrollReactive: true, scrollConfig: { minScroll: 0, maxScroll: 1000, emotionSequence: [ { scrollY: 0, emotion: 'calm' }, { scrollY: 300, emotion: 'curiosity' }, { scrollY: 600, emotion: 'excitement' }, { scrollY: 1000, emotion: 'joy' }, ], }, });
Mobile Responsive
const isMobile = window.innerWidth < 768; const mascot = new EmotiveMascot({ containerId: 'mascot', width: isMobile ? 300 : 500, height: isMobile ? 300 : 500, targetFPS: isMobile ? 30 : 60, // Lower FPS on mobile enableGazeTracking: !isMobile, // Disable on mobile for performance });
Troubleshooting
Mascot not rendering
- Verify canvas element exists in DOM
- Check canvas has width/height (not 0x0)
- Ensure
is called after constructioninitialize() - Check browser console for errors
Performance issues
- Reduce particle count in emotion configs
- Lower targetFPS to 30
- Disable gaze tracking on mobile
- Check for other animation conflicts
Emotions not changing
- Verify emotion name exists in emotion config
- Check transition is awaited (async)
- Ensure previous transition completed
- Check for JavaScript errors blocking execution
Framework-specific issues
React: Canvas disappears on re-render
- Use
for canvas elementuseRef - Don't recreate mascot on every render
- Clean up with
in cleanup functiondestroy()
Vue: Mascot not initializing
- Use
hookonMounted - Check canvas ref is properly bound
- Use
if needednextTick()
Next.js: SSR errors
- Use
directive'use client' - Check for
before initializingwindow - Use dynamic imports for mascot library
Key Files
- Core Engine:
src/core/EmotiveMascot.js - LLM Plugin:
src/plugins/LLMEmotionPlugin.js - Gaze Tracking:
src/core/GazeTrackingEngine.js - Scroll Reactive:
src/core/ScrollReactiveEngine.js - Example Use Cases:
site/src/app/use-cases/
Testing Integration
// Test basic initialization const mascot = new EmotiveMascot({ containerId: 'test-canvas' }); await mascot.initialize(); console.assert(mascot.isInitialized, 'Mascot should be initialized'); // Test emotion transition await mascot.transitionTo('joy'); console.assert(mascot.currentEmotion === 'joy', 'Should transition to joy'); // Test gesture await mascot.playGesture('wave'); console.assert(mascot.isGesturePlaying, 'Gesture should be playing'); // Clean up mascot.destroy();