Home

Owen Animation System

A comprehensive Three.js animation system for character state management with clean architecture principles, dependency injection, and factory patterns.

Gitea Issues Gitea Pull Requests Gitea Release

🎯 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, and Sleep states
  • 😊 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.gltf with 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 loop
  • wait_quirk1_Q - Wait state quirk animation
  • react_angry2type_an_T - Transition from react to type with angry emotion
  • type_happy_L - Type state with happy emotion loop
  • sleep_wakeup_T - Sleep wake up transition

Animation Types

  • L - Loop animation
  • Q - Quirk animation
  • T - Transition animation
  • NL - Nested loop
  • NQ - Nested quirk

Emotions

  • an - Angry
  • sh - Shocked
  • ha - Happy
  • sa - Sad

🏗️ Architecture

Dependency Injection

  • OwenAnimationContext receives 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 parsing
  • StateFactory - Creates state handlers dynamically
  • OwenSystemFactory - 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 server
  • npm run build - Build for production
  • npm run preview - Preview production build
  • npm run lint - Run StandardJS linting
  • npm run lint:fix - Fix StandardJS issues
  • npm run docs - Generate JSDoc documentation
  • npm 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

  1. "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
  1. State transitions not working
  • Verify that transition animations exist in your model
  • Check console for error messages about missing clips
  1. 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

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/new-feature
  3. Commit your changes: git commit -am 'Add new feature'
  4. Push to the branch: git push origin feature/new-feature
  5. 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