Code Examples & Integration Patterns
Explore practical examples of using the Owen Animation System in different frameworks and scenarios.
Framework Integration
Multi-Scheme Usage
Advanced Features
React Integration Example
import React, { useEffect, useRef, useState } from 'react'
import { OwenAnimationContext } from '@kjanat/owen'
export function AnimatedCharacter({ characterModel, namingScheme = 'semantic' }) {
const containerRef = useRef()
const [animationContext, setAnimationContext] = useState(null)
const [currentAnimation, setCurrentAnimation] = useState('idle')
const [isPlaying, setIsPlaying] = useState(false)
useEffect(() => {
// Initialize Owen Animation Context
const context = new OwenAnimationContext({
namingScheme,
autoConvert: true,
container: containerRef.current
})
context.loadModel(characterModel).then(() => {
setAnimationContext(context)
})
return () => context?.dispose()
}, [characterModel, namingScheme])
const playAnimation = async (animationName) => {
if (!animationContext) return
try {
await animationContext.playAnimation(animationName)
setCurrentAnimation(animationName)
setIsPlaying(true)
} catch (error) {
console.error('Failed to play animation:', error)
}
}
const stopAnimation = () => {
animationContext?.stopAnimation()
setIsPlaying(false)
}
return (
<div className="animated-character">
<div ref={containerRef} className="character-viewport" />
<div className="animation-controls">
<button onClick={() => playAnimation('walk_forward')}>
Walk
</button>
<button onClick={() => playAnimation('character_run')}>
Run
</button>
<button onClick={() => playAnimation('jump_high')}>
Jump
</button>
<button onClick={stopAnimation}>
Stop
</button>
</div>
<div className="animation-info">
<p>Current: {currentAnimation}</p>
<p>Status: {isPlaying ? 'Playing' : 'Stopped'}</p>
<p>Scheme: {namingScheme}</p>
</div>
</div>
)
}
Animation Name Conversion
import { AnimationNameMapper } from '@kjanat/owen'
// Initialize the mapper
const mapper = new AnimationNameMapper()
// Single animation conversion
function convertAnimation(animationName, fromScheme, toScheme) {
try {
const converted = mapper.convert(animationName, toScheme, fromScheme)
console.log(`${fromScheme}: ${animationName} → ${toScheme}: ${converted}`)
return converted
} catch (error) {
console.error('Conversion failed:', error.message)
return null
}
}
// Batch conversion with validation
function convertAnimationBatch(animations, fromScheme, toScheme) {
const results = {
successful: [],
failed: [],
conflicts: []
}
animations.forEach(anim => {
try {
const converted = mapper.convert(anim, toScheme, fromScheme)
// Check for conflicts
if (results.successful.includes(converted)) {
results.conflicts.push({
original: anim,
converted,
conflict: 'Duplicate target name'
})
} else {
results.successful.push({
original: anim,
converted,
schemes: { from: fromScheme, to: toScheme }
})
}
} catch (error) {
results.failed.push({
original: anim,
error: error.message,
suggestions: mapper.suggestCorrections(anim, fromScheme)
})
}
})
return results
}
// Example usage
const legacyAnimations = [
'walk_forward', 'run_fast', 'jump_high',
'attack_sword', 'defend_shield', 'idle_breathing'
]
const conversionResults = convertAnimationBatch(
legacyAnimations,
'legacy',
'semantic'
)
console.log('Conversion Results:', conversionResults)
Batch Processing Pipeline
import { AnimationProcessor } from '@kjanat/owen'
import fs from 'fs/promises'
import path from 'path'
class AnimationBatchProcessor {
constructor(options = {}) {
this.processor = new AnimationProcessor(options)
this.inputDir = options.inputDir || './assets/raw'
this.outputDir = options.outputDir || './assets/processed'
this.targetScheme = options.targetScheme || 'semantic'
}
async processDirectory() {
console.log('Starting batch animation processing...')
try {
// Scan input directory
const files = await this.scanAnimationFiles()
console.log(`Found ${files.length} animation files`)
// Process each file
const results = await Promise.allSettled(
files.map(file => this.processFile(file))
)
// Generate summary report
const summary = this.generateSummary(results)
await this.saveReport(summary)
return summary
} catch (error) {
console.error('Batch processing failed:', error)
throw error
}
}
async scanAnimationFiles() {
const files = []
const entries = await fs.readdir(this.inputDir, { withFileTypes: true })
for (const entry of entries) {
if (entry.isFile() && /\.(gltf|glb|fbx)$/i.test(entry.name)) {
files.push(path.join(this.inputDir, entry.name))
}
}
return files
}
async processFile(inputFile) {
const filename = path.basename(inputFile)
console.log(`Processing: ${filename}`)
try {
// Load and analyze animation
const animation = await this.processor.loadAnimation(inputFile)
// Convert naming scheme
const convertedName = this.processor.convertName(
animation.name,
this.targetScheme
)
// Apply optimizations
const optimized = await this.processor.optimize(animation)
// Save processed animation
const outputFile = path.join(this.outputDir, `${convertedName}.gltf`)
await this.processor.saveAnimation(optimized, outputFile)
return {
status: 'success',
inputFile,
outputFile,
originalName: animation.name,
convertedName,
size: optimized.size,
duration: optimized.duration
}
} catch (error) {
return {
status: 'error',
inputFile,
error: error.message
}
}
}
generateSummary(results) {
const successful = results.filter(r => r.value?.status === 'success')
const failed = results.filter(r => r.status === 'rejected' || r.value?.status === 'error')
return {
timestamp: new Date().toISOString(),
total: results.length,
successful: successful.length,
failed: failed.length,
successRate: (successful.length / results.length * 100).toFixed(2),
details: {
successful: successful.map(r => r.value),
failed: failed.map(r => ({
file: r.value?.inputFile || 'unknown',
error: r.value?.error || r.reason
}))
}
}
}
async saveReport(summary) {
const reportPath = path.join(this.outputDir, 'processing-report.json')
await fs.mkdir(path.dirname(reportPath), { recursive: true })
await fs.writeFile(reportPath, JSON.stringify(summary, null, 2))
console.log(`Report saved: ${reportPath}`)
}
}
// Usage
const processor = new AnimationBatchProcessor({
inputDir: './assets/blender-exports',
outputDir: './assets/animations',
targetScheme: 'semantic'
})
processor.processDirectory().then(summary => {
console.log('Processing complete:', summary)
}).catch(error => {
console.error('Processing failed:', error)
process.exit(1)
})