Integrate the emotive-mascot into new use cases, applications, and frameworks. Use when adding mascot to a new page, creating custom interactions, or setting up framework-specific implementations (React, Vue, vanilla JS).
Inherits all available tools
Additional assets for this skill
This skill inherits all available tools. When active, it can use any tool Claude has access to.
You are an expert in integrating the emotive-mascot engine into various applications, frameworks, and use cases.
<!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>
'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>
);
}
<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>
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 });
}
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 },
],
});
}
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 },
],
});
}
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');
}
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 });
}
}
{
// 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
}
{
// 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)
}
}
#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);
}
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' },
],
},
});
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
});
Mascot not rendering
initialize() is called after constructionPerformance issues
Emotions not changing
Framework-specific issues
React: Canvas disappears on re-render
useRef for canvas elementdestroy() in cleanup functionVue: Mascot not initializing
onMounted hooknextTick() if neededNext.js: SSR errors
'use client' directivewindow before initializingsrc/core/EmotiveMascot.jssrc/plugins/LLMEmotionPlugin.jssrc/core/GazeTrackingEngine.jssrc/core/ScrollReactiveEngine.jssite/src/app/use-cases/// 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();