Expressive AI mascots for modern interfaces
Real-time character animation engine with Canvas 2D and WebGL 3D rendering.
|
|
Shared across both modes:
- 15 emotional states with smooth transitions
- 40+ expressive gestures
- Natural language
feel()API for LLM integration - TypeScript definitions
- Unified API
![]() Crystal Soul Subsurface scattering shader |
![]() Moon Phases 8 phases with tidal lock |
![]() Solar Eclipse Corona and diamond ring |
![]() Blood Moon Eclipse Rayleigh scattering simulation |
||
![]() Hello World Minimal setup |
![]() Basic Usage Emotions and gestures |
![]() Breathing App Guided breathing |
![]() Event Handling Real-time monitoring |
![]() Rhythm Sync Beat detection |
![]() LLM Integration Claude sentiment analysis |
npm install @joshtol/emotive-engineOr via CDN:
<!-- 2D Engine -->
<script src="https://unpkg.com/@joshtol/emotive-engine/dist/emotive-mascot.umd.js"></script>
<!-- 3D Engine (includes Three.js) -->
<script src="https://unpkg.com/@joshtol/emotive-engine/dist/emotive-mascot-3d.umd.js"></script>import { EmotiveMascot3D } from '@joshtol/emotive-engine/3d';
const mascot = new EmotiveMascot3D({
coreGeometry: 'crystal', // crystal, moon, sun, heart, sphere
enableParticles: true,
enablePostProcessing: true,
});
mascot.init(document.getElementById('container'));
mascot.start();
// Control emotions and gestures
mascot.setEmotion('joy');
mascot.express('bounce');
mascot.morphTo('heart');import { EmotiveMascot } from '@joshtol/emotive-engine';
const mascot = new EmotiveMascot({
canvasId: 'mascot',
defaultEmotion: 'neutral',
});
await mascot.init(document.getElementById('container'));
mascot.start();
// Same API as 3D
mascot.setEmotion('joy');
mascot.express('bounce');The feel() method lets LLMs control the mascot using natural language:
// Simple emotion
mascot.feel('happy')
// Emotion with gesture
mascot.feel('curious, leaning in')
// With undertone modifier
mascot.feel('happy but nervous')
// With shape morph
mascot.feel('loving, heart shape, sparkle')
// With intensity
mascot.feel('very angry, shaking')The engine parses ~1400 synonyms to understand natural expressions. For full documentation, see LLM Integration Guide.
After each response, output: FEEL: <emotion>, <gesture>
Examples:
- Greeting: FEEL: happy, wave
- Thinking: FEEL: focused, leaning in
- Celebrating: FEEL: euphoric, star shape, sparkle
15 built-in emotional states with unique visual characteristics:
| Emotion | Description | Emotion | Description |
|---|---|---|---|
neutral |
Default calm | joy |
Happy, upbeat |
calm |
Peaceful | love |
Affectionate |
excited |
High energy | euphoria |
Peak happiness |
sadness |
Melancholy | anger |
Frustrated |
fear |
Anxious | surprise |
Startled |
disgust |
Repulsed | focused |
Concentrated |
suspicion |
Wary | resting |
Idle/sleep |
glitch |
Digital artifact |
mascot.setEmotion('joy');
mascot.setEmotion('calm', 'peaceful'); // with undertone40+ expressive gestures in three categories:
Motion: bounce, pulse, shake, nod, sway, float, wiggle, lean
Transform: spin, jump, morph, stretch, tilt, orbital, twist
Effects: wave, flicker, burst, flash, glow, breathe, expand
mascot.express('bounce');
mascot.chain('bounce > spin > pulse'); // sequential
mascot.chain('sway+breathe+float'); // simultaneous| Geometry | Description | Shader |
|---|---|---|
crystal |
Faceted hexagonal crystal | Subsurface scattering |
moon |
Realistic lunar surface | Custom phase shader |
sun |
Solar sphere with corona | Emissive + corona layers |
heart |
Heart-shaped crystal | Subsurface scattering |
sphere |
Smooth sphere | Standard PBR |
mascot.morphTo('heart'); // Runtime geometry morphingimport { setMoonPhase, MOON_PHASES } from '@joshtol/emotive-engine/3d';
setMoonPhase(mascot.core3D, MOON_PHASES.FULL);
setMoonPhase(mascot.core3D, MOON_PHASES.CRESCENT_WAXING);
// All phases: NEW, CRESCENT_WAXING, FIRST_QUARTER, GIBBOUS_WAXING,
// FULL, GIBBOUS_WANING, LAST_QUARTER, CRESCENT_WANING// Solar eclipse with corona
mascot.core3D.setSolarEclipse(0.8); // 0-1 coverage
// Lunar eclipse (blood moon)
mascot.core3D.setLunarEclipse(1.0); // Full umbranew EmotiveMascot3D({
// Geometry
coreGeometry: 'crystal',
// Rendering
enableParticles: true,
enablePostProcessing: true, // Bloom effects
enableShadows: false,
// Camera
enableControls: true, // Orbit controls
autoRotate: true,
cameraDistance: 3,
// Animation
enableBlinking: true,
enableBreathing: true,
targetFPS: 60,
});new EmotiveMascot({
canvasId: 'mascot',
targetFPS: 60,
enableParticles: true,
maxParticles: 300,
adaptive: true, // Auto quality adjustment
});// Lifecycle
mascot.init(container);
mascot.start();
mascot.stop();
mascot.destroy();
// Natural language control (LLM-friendly)
mascot.feel('happy, bouncing');
mascot.feel('curious, leaning in');
// Emotions
mascot.setEmotion(name);
mascot.setEmotion(name, undertone);
// Gestures
mascot.express(gesture);
mascot.chain('gesture1 > gesture2');
// Shapes
mascot.morphTo(shape);// Toggle features
mascot.enableParticles();
mascot.disableParticles();
mascot.enableAutoRotate();
mascot.disableAutoRotate();
// Camera
mascot.setCameraPreset('front'); // front, side, top, anglegit clone https://github.com/joshtol/emotive-engine.git
cd emotive-engine
npm install
npm run build
npm run local
# Open http://localhost:3001Or view the live demo gallery.
| Browser | Version |
|---|---|
| Chrome/Edge | 90+ |
| Firefox | 88+ |
| Safari | 14+ |
| iOS Safari | 14+ |
| Chrome Android | 90+ |
3D mode requires WebGL 2.0 support.
- Disable post-processing on mobile for 60fps
- Use
enableShadows: falseunless needed - Lower
maxParticleson constrained devices - 2D mode is lighter weight for simple use cases
MIT License - see LICENSE.md
Created by Joshua Tollette









