Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 1 to 2. - [Release notes](https://github.com/softprops/action-gh-release/releases) - [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md) - [Commits](https://github.com/softprops/action-gh-release/compare/v1...v2) --- updated-dependencies: - dependency-name: softprops/action-gh-release dependency-version: '2' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com>
Owen Animation System
A comprehensive Three.js animation system for character state management with clean architecture principles, dependency injection, and factory patterns.
🎯 Overview
The Owen Animation System is a sophisticated character animation framework built for Three.js that manages complex state machines, emotional responses, and animation transitions. It's designed with clean architecture principles to be maintainable, extensible, and testable.
✨ Key Features
- 🤖 State Machine Implementation - Complete state management system with
Wait,React,Type, andSleepstates - 😊 Emotional Response System - Analyzes user input to determine appropriate emotional animations
- 🔄 Animation Transition Management - Smooth transitions between states with fade in/out support
- 📝 Multi-Scheme Animation Naming - Supports legacy, artist-friendly, hierarchical, and semantic naming schemes
- 🎨 Artist-Friendly Workflow - Blender-compatible naming for 3D artists (
Owen_WaitIdle,Owen_ReactHappy) - 👨💻 Developer Experience - Type-safe constants and semantic naming (
OwenWaitIdleLoop,OwenReactAngryTransition) - 🏗️ Clean Architecture - Uses dependency injection, factory patterns, and separation of concerns
- ⚡ Performance Optimized - Efficient animation caching and resource management
- 🧩 Extensible Design - Easy to add new states, emotions, and animation types
- 🔄 Backward Compatibility - Legacy naming scheme continues to work alongside new schemes
🚀 Installation
Prerequisites
- Node.js 16.0.0 or higher
- Three.js compatible 3D model with animations (GLTF/GLB format recommended)
Install Dependencies
# Clone the repository
git clone https://gitea.kajkowalski.nl/kjanat/Owen.git
cd Owen
# Install dependencies
npm install
# Install dev dependencies
npm install --include dev
📖 Usage
Basic Usage
import * as THREE from "three";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
import { OwenSystemFactory } from "owen";
// Load your 3D model
const loader = new GLTFLoader();
const gltf = await loader.loadAsync("path/to/your-model.gltf");
// Create a Three.js scene
const scene = new THREE.Scene();
scene.add(gltf.scene);
// Create the Owen animation system
const owenSystem = await OwenSystemFactory.createOwenSystem(gltf, scene);
// Handle user messages
await owenSystem.handleUserMessage("Hello Owen!");
// Update in your render loop
function animate() {
const deltaTime = clock.getDelta() * 1000; // Convert to milliseconds
owenSystem.update(deltaTime);
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
Note
Replace
path/to/your-model.gltfwith the actual path to your 3D character model. The system is designed to work with any GLTF model that follows the animation naming convention.
Advanced Usage
import { OwenSystemFactory, States, Emotions, StateHandler } from "owen";
// Create custom state handler
class CustomStateHandler extends StateHandler {
async enter(fromState, emotion) {
console.log(`Entering custom state from ${fromState}`);
// Your custom logic here
}
async exit(toState, emotion) {
console.log(`Exiting custom state to ${toState}`);
// Your custom logic here
}
}
// Register custom states
const customStates = new Map();
customStates.set("custom", CustomStateHandler);
// Create system with custom states
const owenSystem = await OwenSystemFactory.createCustomOwenSystem(gltfModel, scene, customStates);
// Manual state transitions
await owenSystem.transitionTo(States.REACTING, Emotions.HAPPY);
🎨 Multi-Scheme Animation Naming
Owen supports four different animation naming schemes to accommodate different workflows and preferences:
Naming Schemes
| Scheme | Format | Example | Use Case |
|---|---|---|---|
| Legacy | {state}_{emotion}_{type} |
wait_idle_L |
Backward compatibility |
| Artist | Owen_{Action} |
Owen_WaitIdle |
Blender-friendly for 3D artists |
| Hierarchical | owen.{category}.{state}... |
owen.state.wait.idle.loop |
Structured projects |
| Semantic | Owen{StateAction}{Type} |
OwenWaitIdleLoop |
Developer-friendly |
Usage Examples
// All of these refer to the same animation:
const clip1 = owenSystem.getClip('wait_idle_L'); // Legacy
const clip2 = owenSystem.getClip('Owen_WaitIdle'); // Artist
const clip3 = owenSystem.getClip('owen.state.wait.idle.loop'); // Hierarchical
const clip4 = owenSystem.getClip('OwenWaitIdleLoop'); // Semantic
// Convert between schemes
import { convertAnimationName, SemanticAnimations } from 'owen';
const artistName = convertAnimationName('wait_idle_L', 'artist');
// Returns: 'Owen_WaitIdle'
// Use type-safe constants
const animation = SemanticAnimations.WAIT_IDLE_LOOP; // 'OwenWaitIdleLoop'
For 3D Artists (Blender Workflow)
// Use artist-friendly names in Blender:
// Owen_WaitIdle, Owen_ReactHappy, Owen_TypeFast, etc.
// System automatically handles conversion!
const clip = owenSystem.getClip('Owen_ReactAngry'); // Just works!
Tip
See the Multi-Scheme Guide for complete documentation and examples.
🎮 Animation Naming Convention (Legacy)
The system maintains backward compatibility with the original naming convention:
The system expects animations to follow this naming convention:
[state]_[action]_[type]
[state]_[action]2[toState]_[emotion]_T
Examples
wait_idle_L- Wait state idle loopwait_quirk1_Q- Wait state quirk animationreact_angry2type_an_T- Transition from react to type with angry emotiontype_happy_L- Type state with happy emotion loopsleep_wakeup_T- Sleep wake up transition
Animation Types
L- Loop animationQ- Quirk animationT- Transition animationNL- Nested loopNQ- Nested quirk
Emotions
an- Angrysh- Shockedha- Happysa- Sad
🏗️ Architecture
Dependency Injection
OwenAnimationContextreceives dependencies through constructor injection- State handlers are injected with required context
- Animation loaders are injected into factories
Factory Patterns
AnimationClipFactory- Creates animation clips with metadata parsingStateFactory- Creates state handlers dynamicallyOwenSystemFactory- Main factory that assembles the complete system
State Machine
- Each state has its own handler class with entry/exit logic
- States manage their own transitions and behaviors
- Emotional transitions are handled with proper animation sequencing
📁 Project Structure
Owen/
├── src/
│ ├── constants.js # Animation types, states, emotions
│ ├── index.js # Main entry point
│ ├── animation/
│ │ └── AnimationClip.js # Core animation classes
│ ├── core/
│ │ └── OwenAnimationContext.js # Main system controller
│ ├── factories/
│ │ └── OwenSystemFactory.js # System factory
│ ├── loaders/
│ │ └── AnimationLoader.js # Animation loading interfaces
│ └── states/
│ ├── StateHandler.js # Base state handler
│ ├── StateFactory.js # State factory
│ ├── WaitStateHandler.js # Wait state implementation
│ ├── ReactStateHandler.js # React state implementation
│ ├── TypeStateHandler.js # Type state implementation
│ └── SleepStateHandler.js # Sleep state implementation
├── examples/
│ ├── index.html # Demo HTML page
│ └── basic-demo.js # Basic usage example
├── package.json
├── vite.config.js
├── jsdoc.config.json
└── README.md
🛠️ Development
Running the Development Server
# Start the development server
npm run dev
This will start a Vite development server and open the basic demo at http://localhost:3000.
Building for Production
# Build the project
npm run build
Linting
# Run ESLint
npm run lint
# Fix linting issues automatically
npm run lint:fix
Generating Documentation
# Generate JSDoc documentation
npm run docs
Documentation will be generated in the docs/ directory.
Project Scripts
npm run dev- Start development servernpm run build- Build for productionnpm run preview- Preview production buildnpm run lint- Run StandardJS lintingnpm run lint:fix- Fix StandardJS issuesnpm run docs- Generate JSDoc documentationnpm run format- Format code with Prettier
🎮 Demo Controls
The basic demo includes these keyboard controls:
- 1 - Transition to Wait state
- 2 - Transition to React state
- 3 - Transition to Type state
- 4 - Transition to Sleep state
- Space - Send random test message
- Click - Register user activity
🔧 Configuration
Customizing Emotions
You can extend the emotion system by modifying the message analysis:
import { ReactStateHandler } from "owen";
class CustomReactHandler extends ReactStateHandler {
analyzeMessageEmotion(message) {
// Your custom emotion analysis logic
if (message.includes("excited")) {
return Emotions.HAPPY;
}
return super.analyzeMessageEmotion(message);
}
}
Adjusting Timing
Configure timing values in your application:
import { Config } from "owen";
// Modify default values
Config.QUIRK_INTERVAL = 8000; // 8 seconds between quirks
Config.INACTIVITY_TIMEOUT = 120000; // 2 minutes until sleep
🐛 Troubleshooting
Common Issues
- "Animation not found" errors
- Ensure your 3D model contains animations with the correct naming convention
- Check that animations are properly exported in your GLTF file
- State transitions not working
- Verify that transition animations exist in your model
- Check console for error messages about missing clips
- Performance issues
- Ensure you're calling
owenSystem.update()in your render loop - Check that unused animations are properly disposed
Debug Mode
Enable debug logging by opening browser console. The system logs state transitions and important events.
🤝 Contributing
- Fork the repository
- Create a feature branch:
git checkout -b feature/new-feature - Commit your changes:
git commit -am 'Add new feature' - Push to the branch:
git push origin feature/new-feature - Submit a pull request
Code Style
- Follow the existing ESLint configuration
- Add JSDoc comments for all public methods
- Write unit tests for new features
- Maintain the existing architecture patterns
📄 License
This project is dual-licensed under your choice of:
- Open Source/Non-Commercial Use: AGPL-3.0 - see the LICENSE.AGPL file for details.
- Commercial/Enterprise Use: Commercial License - see the LICENSE.COMMERCIAL file for details. Requires a paid commercial license. Please contact us at [email] for pricing and terms.
Quick Guide
- ✅ Personal/educational use → Use under AGPL-3.0
- ✅ Open source projects → Use under AGPL-3.0
- ✅ Commercial/proprietary use → Purchase commercial license
- ❌ SaaS without source disclosure → Purchase commercial license
🙏 Acknowledgments
- Built with Three.js
- Inspired by modern character animation systems
- Uses clean architecture principles from Robert C. Martin