/** * @fileoverview Basic example of using the Owen Animation System * @author Owen Animation System */ import * as THREE from 'three' import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js' import { OwenSystemFactory, States } from '../src/index.js' /** * Basic Owen Animation System demo * @class */ class OwenDemo { /** * Create the demo */ constructor () { /** * The Three.js scene * @type {THREE.Scene} */ this.scene = new THREE.Scene() /** * The Three.js camera * @type {THREE.PerspectiveCamera} */ this.camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000) /** * The Three.js renderer * @type {THREE.WebGLRenderer} */ this.renderer = new THREE.WebGLRenderer({ antialias: true }) /** * The Owen animation system * @type {OwenAnimationContext|null} */ this.owenSystem = null /** * Clock for tracking time * @type {THREE.Clock} */ this.clock = new THREE.Clock() } /** * Initialize the demo * @returns {Promise} */ async init () { // Setup renderer this.renderer.setSize(window.innerWidth, window.innerHeight) this.renderer.setClearColor(0x1a1a1a) this.renderer.shadowMap.enabled = true this.renderer.shadowMap.type = THREE.PCFSoftShadowMap document.body.appendChild(this.renderer.domElement) // Setup camera this.camera.position.set(0, 1.6, 3) this.camera.lookAt(0, 1, 0) // Add lighting this.setupLighting() // Load Owen model (replace with your model path) await this.loadOwenModel() // Setup event listeners this.setupEventListeners() // Start render loop this.animate() console.log('Owen Demo initialized') } /** * Setup scene lighting * @private * @returns {void} */ setupLighting () { // Ambient light const ambientLight = new THREE.AmbientLight(0x404040, 0.4) this.scene.add(ambientLight) // Directional light const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8) directionalLight.position.set(5, 10, 5) directionalLight.castShadow = true directionalLight.shadow.mapSize.width = 2048 directionalLight.shadow.mapSize.height = 2048 this.scene.add(directionalLight) // Fill light const fillLight = new THREE.DirectionalLight(0x8bb7f0, 0.3) fillLight.position.set(-5, 5, -5) this.scene.add(fillLight) } /** * Load the Owen character model * @private * @returns {Promise} */ async loadOwenModel () { try { const loader = new GLTFLoader() // Replace 'path/to/owen.gltf' with your actual model path const gltf = await new Promise((resolve, reject) => { loader.load( 'path/to/owen.gltf', // Update this path resolve, (progress) => console.log('Loading progress:', progress.loaded / progress.total * 100 + '%'), reject ) }) const model = gltf.scene model.position.set(0, 0, 0) model.scale.setScalar(1) // Enable shadows model.traverse((child) => { if (child.isMesh) { child.castShadow = true child.receiveShadow = true } }) this.scene.add(model) // Create Owen animation system this.owenSystem = await OwenSystemFactory.createOwenSystem(gltf, this.scene) console.log('Owen model loaded and animation system created') this.logSystemInfo() } catch (error) { console.error('Error loading Owen model:', error) // Create a placeholder cube for demo purposes this.createPlaceholderModel() } } /** * Create a placeholder model for demo purposes * @private * @returns {void} */ createPlaceholderModel () { const geometry = new THREE.BoxGeometry(1, 2, 1) const material = new THREE.MeshPhongMaterial({ color: 0x6699ff }) const cube = new THREE.Mesh(geometry, material) cube.position.set(0, 1, 0) cube.castShadow = true cube.receiveShadow = true this.scene.add(cube) console.log('Created placeholder model (cube)') } /** * Setup event listeners for user interaction * @private * @returns {void} */ setupEventListeners () { // Keyboard controls document.addEventListener('keydown', (event) => { if (!this.owenSystem) return switch (event.key) { case '1': this.owenSystem.transitionTo(States.WAIT) break case '2': this.owenSystem.transitionTo(States.REACT) break case '3': this.owenSystem.transitionTo(States.TYPE) break case '4': this.owenSystem.transitionTo(States.SLEEP) break case ' ': this.sendTestMessage() break } }) // Mouse interaction document.addEventListener('click', () => { if (this.owenSystem) { this.owenSystem.onUserActivity() } }) // Window resize window.addEventListener('resize', () => { this.camera.aspect = window.innerWidth / window.innerHeight this.camera.updateProjectionMatrix() this.renderer.setSize(window.innerWidth, window.innerHeight) }) // Add instructions to the page this.addInstructions() } /** * Add on-screen instructions * @private * @returns {void} */ addInstructions () { const instructions = document.createElement('div') instructions.innerHTML = `

Owen Animation System Demo

Controls:

1 - Wait State

2 - React State

3 - Type State

4 - Sleep State

Space - Send Test Message

Click - User Activity


Current State: -

Available Transitions: -

` document.body.appendChild(instructions) } /** * Send a test message to Owen * @private * @returns {void} */ sendTestMessage () { if (!this.owenSystem) return const testMessages = [ 'Hello Owen!', 'How are you doing?', 'This is urgent!', 'Great work!', 'Error in the system!', 'I\'m feeling sad today' ] const randomMessage = testMessages[Math.floor(Math.random() * testMessages.length)] console.log(`Sending message: "${randomMessage}"`) this.owenSystem.handleUserMessage(randomMessage) } /** * Log system information * @private * @returns {void} */ logSystemInfo () { if (!this.owenSystem) return console.log('=== Owen System Info ===') console.log('Available States:', this.owenSystem.getAvailableStates()) console.log('Available Clips:', this.owenSystem.getAvailableClips()) console.log('Current State:', this.owenSystem.getCurrentState()) console.log('========================') } /** * Update UI with current system state * @private * @returns {void} */ updateUI () { if (!this.owenSystem) return const currentStateElement = document.getElementById('current-state') const transitionsElement = document.getElementById('transitions') if (currentStateElement) { currentStateElement.textContent = this.owenSystem.getCurrentState() } if (transitionsElement) { transitionsElement.textContent = this.owenSystem.getAvailableTransitions().join(', ') } } /** * Main animation loop * @private * @returns {void} */ animate () { requestAnimationFrame(() => this.animate()) const deltaTime = this.clock.getDelta() * 1000 // Convert to milliseconds // Update Owen system if (this.owenSystem) { this.owenSystem.update(deltaTime) } // Update UI this.updateUI() // Render scene this.renderer.render(this.scene, this.camera) } } // Initialize the demo when the page loads window.addEventListener('load', async () => { const demo = new OwenDemo() try { await demo.init() } catch (error) { console.error('Failed to initialize Owen demo:', error) } }) export default OwenDemo