@backbay/glia-agent 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/emotion/constants.ts","../src/emotion/mapping.ts","../src/emotion/transitions.ts","../src/emotion/micro-expressions.ts","../src/emotion/controller.ts","../src/emotion/hooks/useEmotion.ts"],"sourcesContent":["// packages/bb-ui/src/emotion/constants.ts\n\nimport type { AVO, AnchorState, MicroExpressionConfig, LegacyGlyphState } from './types.js';\n\n/**\n * Validate AVO dimensions are in valid range\n */\nexport function isValidAVO(avo: AVO): boolean {\n return (\n avo.arousal >= 0 && avo.arousal <= 1 &&\n avo.valence >= 0 && avo.valence <= 1 &&\n avo.openness >= 0 && avo.openness <= 1\n );\n}\n\n/**\n * Clamp AVO dimensions to valid range\n */\nexport function clampAVO(avo: Partial<AVO>): AVO {\n return {\n arousal: Math.max(0, Math.min(1, avo.arousal ?? 0.25)),\n valence: Math.max(0, Math.min(1, avo.valence ?? 0.6)),\n openness: Math.max(0, Math.min(1, avo.openness ?? 0.35)),\n };\n}\n\n/**\n * Named anchor states with AVO coordinates\n */\nexport const ANCHOR_STATES: Record<AnchorState, AVO> = {\n // Rest states\n dormant: { arousal: 0.05, valence: 0.55, openness: 0.30 },\n idle: { arousal: 0.25, valence: 0.60, openness: 0.35 },\n\n // Receptive states\n attentive: { arousal: 0.40, valence: 0.70, openness: 0.20 },\n curious: { arousal: 0.50, valence: 0.75, openness: 0.10 },\n listening: { arousal: 0.45, valence: 0.70, openness: 0.05 },\n\n // Processing states\n thinking: { arousal: 0.60, valence: 0.60, openness: 0.40 },\n contemplating: { arousal: 0.55, valence: 0.65, openness: 0.45 },\n focused: { arousal: 0.70, valence: 0.70, openness: 0.50 },\n\n // Expressive states\n responding: { arousal: 0.60, valence: 0.75, openness: 0.80 },\n explaining: { arousal: 0.55, valence: 0.80, openness: 0.85 },\n enthusiastic: { arousal: 0.80, valence: 0.90, openness: 0.75 },\n\n // Completion states\n satisfied: { arousal: 0.30, valence: 0.90, openness: 0.50 },\n proud: { arousal: 0.45, valence: 0.95, openness: 0.60 },\n\n // Negative states\n uncertain: { arousal: 0.45, valence: 0.40, openness: 0.35 },\n concerned: { arousal: 0.55, valence: 0.30, openness: 0.30 },\n struggling: { arousal: 0.70, valence: 0.35, openness: 0.45 },\n alarmed: { arousal: 0.80, valence: 0.20, openness: 0.40 },\n error: { arousal: 0.75, valence: 0.10, openness: 0.35 },\n\n // Recovery states\n recovering: { arousal: 0.40, valence: 0.45, openness: 0.40 },\n relieved: { arousal: 0.35, valence: 0.75, openness: 0.45 },\n};\n\n/**\n * Map legacy GlyphState to anchor states\n */\nexport const LEGACY_STATE_MAP: Record<LegacyGlyphState, AnchorState> = {\n idle: 'idle',\n listening: 'listening',\n thinking: 'thinking',\n responding: 'responding',\n success: 'satisfied',\n error: 'error',\n sleep: 'dormant',\n};\n\n/**\n * Default micro-expression configuration\n */\nexport const DEFAULT_MICRO_CONFIG: MicroExpressionConfig = {\n enabled: true,\n arousalNoise: 0.02,\n valenceNoise: 0.015,\n opennessNoise: 0.01,\n frequency: 0.3,\n};\n\n/**\n * Default transition durations by type (ms)\n */\nexport const DEFAULT_TRANSITION_DURATIONS = {\n micro: 150,\n standard: 400,\n mood: 800,\n major: 1200,\n} as const;\n\n/**\n * Default AVO state (idle equivalent)\n */\nexport const DEFAULT_AVO: AVO = ANCHOR_STATES.idle;\n","// packages/bb-ui/src/emotion/mapping.ts\n\nimport type { AVO, LegacyGlyphState, VisualState } from './types.js';\nimport { ANCHOR_STATES, LEGACY_STATE_MAP } from './constants.js';\n\n/**\n * Linear interpolation\n */\nexport function lerp(a: number, b: number, t: number): number {\n return a + (b - a) * t;\n}\n\n/**\n * Map Arousal (0-1) to temporal visual properties\n */\nexport function mapArousal(a: number) {\n return {\n breathingRate: 0.3 + Math.pow(a, 1.5) * 1.7, // 0.3 - 2.0 Hz\n breathingAmplitude: 0.01 + a * 0.05, // 1% - 6%\n ringRotationSpeed: 0.1 + Math.pow(a, 1.3) * 1.9, // 0.1 - 2.0 rad/s\n particleVelocity: 0.02 + a * 0.18, // 0.02 - 0.20\n particleCount: Math.floor(20 + a * 80), // 20 - 100\n glowPulseRate: 0.2 + Math.pow(a, 1.4) * 1.3, // 0.2 - 1.5 Hz\n };\n}\n\n/**\n * Map Valence (0-1) to qualitative visual properties\n */\nexport function mapValence(v: number) {\n // Sigmoid for sharper color transition in middle range\n const colorT = 1 / (1 + Math.exp(-8 * (v - 0.4)));\n\n return {\n coreHue: lerp(220, 35, colorT), // Blue(220) → Gold(35)\n coreSaturation: 0.4 + v * 0.45, // 40% - 85%\n motionNoise: 0.15 * Math.pow(1 - v, 2), // High noise when low\n scaleFactor: 0.92 + v * 0.16, // 0.92x - 1.08x\n emissiveIntensity: 0.2 + Math.pow(v, 1.5) * 0.7, // 0.2 - 0.9\n };\n}\n\n/**\n * Map Openness (0-1) to spatial visual properties\n */\nexport function mapOpenness(o: number) {\n return {\n particleFlowDirection: lerp(-1, 1, o), // -1 (in) to +1 (out)\n particleSpreadAngle: lerp(30, 120, o), // 30° - 120°\n breathingPhaseBias: lerp(-0.3, 0.3, o), // Inhale vs exhale bias\n ringTilt: lerp(-15, 15, o), // -15° to +15°\n auraExpansion: lerp(0.95, 1.1, o), // 0.95x - 1.1x\n };\n}\n\n/**\n * Compute complete visual state from AVO dimensions\n */\nexport function computeVisualState(avo: AVO): VisualState {\n const arousalMap = mapArousal(avo.arousal);\n const valenceMap = mapValence(avo.valence);\n const opennessMap = mapOpenness(avo.openness);\n\n // Cross-dimensional: overall intensity combines A and V\n const overallIntensity = 0.3 + (avo.arousal * 0.4) + (avo.valence * 0.3);\n\n return {\n ...arousalMap,\n ...valenceMap,\n ...opennessMap,\n overallIntensity,\n };\n}\n\n/**\n * Compute Euclidean distance between two AVO states\n */\nexport function avoDistance(a: AVO, b: AVO): number {\n return Math.sqrt(\n Math.pow(a.arousal - b.arousal, 2) +\n Math.pow(a.valence - b.valence, 2) +\n Math.pow(a.openness - b.openness, 2)\n );\n}\n\n/**\n * Blend between two AVO states\n */\nexport function blendAVO(from: AVO, to: AVO, t: number): AVO {\n return {\n arousal: lerp(from.arousal, to.arousal, t),\n valence: lerp(from.valence, to.valence, t),\n openness: lerp(from.openness, to.openness, t),\n };\n}\n\n/**\n * Calculate animation weights for all legacy states based on distance to current AVO.\n * Uses inverse distance weighting with falloff - states closer in AVO space get higher weights.\n * Weights are normalized to sum to 1.0 (or all zero if no state is close enough).\n */\nexport function getAnimationWeights(\n currentAVO: AVO\n): Record<LegacyGlyphState, number> {\n const weights: Record<LegacyGlyphState, number> = {\n idle: 0,\n listening: 0,\n thinking: 0,\n responding: 0,\n success: 0,\n error: 0,\n sleep: 0,\n };\n\n // Calculate distance to each legacy state's AVO coordinates\n for (const [state, anchor] of Object.entries(LEGACY_STATE_MAP)) {\n const targetAVO = ANCHOR_STATES[anchor as keyof typeof ANCHOR_STATES];\n const distance = avoDistance(currentAVO, targetAVO);\n // Inverse distance weighting with falloff\n // Distance of 0 -> weight 1, distance >= 0.5 -> weight 0\n weights[state as LegacyGlyphState] = Math.max(0, 1 - distance * 2);\n }\n\n // Normalize weights to sum to 1.0\n const total = Object.values(weights).reduce((a, b) => a + b, 0);\n if (total > 0) {\n for (const key of Object.keys(weights)) {\n weights[key as LegacyGlyphState] /= total;\n }\n } else {\n // Fallback: if all weights are zero (current AVO is far from all states),\n // default to idle with full weight\n weights.idle = 1;\n }\n\n return weights;\n}\n","// packages/bb-ui/src/emotion/transitions.ts\n\nimport type { AVO, EasingFunction, TransitionOptions } from './types.js';\nimport { avoDistance } from './mapping.js';\n\n/**\n * Easing functions\n */\nexport const EASING_FUNCTIONS: Record<EasingFunction, (t: number) => number> = {\n linear: (t) => t,\n easeIn: (t) => t * t,\n easeOut: (t) => 1 - Math.pow(1 - t, 2),\n easeInOut: (t) => t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2,\n spring: (t) => {\n const c4 = (2 * Math.PI) / 3;\n return t === 0 ? 0 : t === 1 ? 1 :\n Math.pow(2, -10 * t) * Math.sin((t * 10 - 0.75) * c4) + 1;\n },\n};\n\n/**\n * Apply easing function to progress value (clamped 0-1)\n */\nexport function ease(fn: EasingFunction, t: number): number {\n return EASING_FUNCTIONS[fn](Math.max(0, Math.min(1, t)));\n}\n\n/**\n * Calculate appropriate transition duration based on AVO change\n * Returns duration in milliseconds\n * - Urgent (200ms) for sudden negative changes (e.g., error states)\n * - Recovery uses longer duration with distance factor\n * - Default: proportional to AVO distance\n */\nexport function getTransitionDuration(from: AVO, to: AVO): number {\n const distance = avoDistance(from, to);\n const valenceDrop = from.valence - to.valence;\n const arousalSpike = to.arousal - from.arousal;\n\n // Urgent: sudden negative change (error state)\n if (valenceDrop > 0.3 && arousalSpike > 0.2) {\n return 200;\n }\n\n // Recovery: returning to positive\n if (to.valence > from.valence && to.valence > 0.6) {\n return 600 + distance * 400;\n }\n\n // Default: proportional to distance\n return Math.floor(200 + distance * 800);\n}\n\n/**\n * Get recommended easing for a transition based on emotional context\n * - Urgent negative: fast out (easeOut)\n * - Recovery: springy for natural bounce-back\n * - Default: smooth in-out\n */\nexport function getTransitionEasing(from: AVO, to: AVO): EasingFunction {\n const valenceDrop = from.valence - to.valence;\n const arousalSpike = to.arousal - from.arousal;\n\n // Urgent negative: fast out\n if (valenceDrop > 0.3 && arousalSpike > 0.2) {\n return 'easeOut';\n }\n\n // Recovery: springy\n if (to.valence > from.valence && to.valence > 0.7) {\n return 'spring';\n }\n\n // Default\n return 'easeInOut';\n}\n\n/**\n * Get complete transition config with duration, easing, and onComplete callback\n */\nexport function getTransitionConfig(from: AVO, to: AVO): Required<TransitionOptions> {\n return {\n duration: getTransitionDuration(from, to),\n easing: getTransitionEasing(from, to),\n onComplete: () => {},\n };\n}\n","// packages/bb-ui/src/emotion/micro-expressions.ts\n\nimport type { AVO, MicroExpressionConfig } from './types.js';\n\n/**\n * Simple seeded pseudo-random number generator\n */\nfunction seededRandom(seed: number): () => number {\n let state = seed;\n return () => {\n state = (state * 1103515245 + 12345) & 0x7fffffff;\n return state / 0x7fffffff;\n };\n}\n\n/**\n * Create a smooth noise generator (Perlin-like)\n * Returns values between -1 and 1\n */\nexport function createNoiseGenerator(seed: number = 42) {\n const rand = seededRandom(seed);\n\n // Pre-generate gradient table\n const gradients: number[] = [];\n for (let i = 0; i < 256; i++) {\n gradients.push(rand() * 2 - 1);\n }\n\n // Smoothstep interpolation\n const smoothstep = (t: number) => t * t * (3 - 2 * t);\n\n return (t: number): number => {\n const i0 = Math.floor(t) & 255;\n const i1 = (i0 + 1) & 255;\n const frac = t - Math.floor(t);\n\n const g0 = gradients[i0];\n const g1 = gradients[i1];\n\n const d0 = g0 * frac;\n const d1 = g1 * (frac - 1);\n\n return smoothstep(frac) * (d1 - d0) + d0;\n };\n}\n\n// Global noise generators for each dimension (different seeds)\nconst arousalNoise = createNoiseGenerator(42);\nconst valenceNoise = createNoiseGenerator(137);\nconst opennessNoise = createNoiseGenerator(256);\n\n/**\n * Apply micro-expression variations to base AVO state\n */\nexport function applyMicroExpression(\n base: AVO,\n config: MicroExpressionConfig,\n time: number\n): AVO {\n if (!config.enabled) {\n return base;\n }\n\n const t = time * config.frequency;\n\n // Apply noise scaled by config amplitude\n const noiseA = arousalNoise(t) * config.arousalNoise;\n const noiseV = valenceNoise(t + 100) * config.valenceNoise;\n const noiseO = opennessNoise(t + 200) * config.opennessNoise;\n\n // Clamp to valid 0-1 range\n return {\n arousal: Math.max(0, Math.min(1, base.arousal + noiseA)),\n valence: Math.max(0, Math.min(1, base.valence + noiseV)),\n openness: Math.max(0, Math.min(1, base.openness + noiseO)),\n };\n}\n\n/**\n * Create a micro-expression animator that tracks time internally\n */\nexport function createMicroExpressionAnimator(config: MicroExpressionConfig) {\n let time = 0;\n\n return {\n tick(deltaMs: number) {\n time += deltaMs / 1000;\n },\n apply(base: AVO): AVO {\n return applyMicroExpression(base, config, time);\n },\n reset() {\n time = 0;\n },\n };\n}\n","// packages/bb-ui/src/emotion/controller.ts\n\nimport type {\n AVO,\n AnchorState,\n TransitionOptions,\n EasingFunction,\n EmotionEvent,\n MicroExpressionConfig,\n VisualState,\n} from './types.js';\nimport { ANCHOR_STATES, DEFAULT_AVO, DEFAULT_MICRO_CONFIG, clampAVO } from './constants.js';\nimport { blendAVO, computeVisualState } from './mapping.js';\nimport { ease, getTransitionConfig } from './transitions.js';\nimport { applyMicroExpression } from './micro-expressions.js';\n\ntype EventHandler<T> = (data: T) => void;\n\ninterface EmotionControllerEvents {\n change: AVO;\n transitionStart: { from: AVO; to: AVO };\n transitionEnd: AVO;\n anchorReached: AnchorState;\n}\n\nexport interface EmotionControllerOptions {\n initial?: Partial<AVO>;\n initialAnchor?: AnchorState;\n microExpressions?: boolean | MicroExpressionConfig;\n}\n\ninterface TransitionState {\n from: AVO;\n to: AVO;\n duration: number;\n easing: EasingFunction;\n elapsed: number;\n onComplete?: () => void;\n}\n\n/**\n * EmotionController manages the emotional state lifecycle for the Glyph character.\n *\n * It handles:\n * - AVO dimension state (Arousal, Valence, Openness)\n * - Smooth transitions between states with configurable easing\n * - Micro-expression overlays for natural movement\n * - Event-driven state changes from agent behaviors\n * - Visual state computation for rendering\n */\nexport class EmotionController {\n private _dimensions: AVO;\n private _transition: TransitionState | null = null;\n private _microConfig: MicroExpressionConfig;\n private _time: number = 0;\n private _listeners: Map<keyof EmotionControllerEvents, Set<EventHandler<unknown>>> = new Map();\n private _disposed: boolean = false;\n\n constructor(options: EmotionControllerOptions = {}) {\n // Initialize dimensions from anchor, custom values, or default\n if (options.initialAnchor) {\n this._dimensions = { ...ANCHOR_STATES[options.initialAnchor] };\n } else if (options.initial) {\n this._dimensions = clampAVO(options.initial);\n } else {\n this._dimensions = { ...DEFAULT_AVO };\n }\n\n // Initialize micro-expression config\n if (options.microExpressions === false) {\n this._microConfig = { ...DEFAULT_MICRO_CONFIG, enabled: false };\n } else if (typeof options.microExpressions === 'object') {\n this._microConfig = { ...DEFAULT_MICRO_CONFIG, ...options.microExpressions };\n } else {\n this._microConfig = { ...DEFAULT_MICRO_CONFIG };\n }\n }\n\n /**\n * Get current base dimensions (without micro-expressions)\n */\n getDimensions(): AVO {\n return { ...this._dimensions };\n }\n\n /**\n * Get current dimensions with micro-expressions applied\n */\n getAnimatedDimensions(): AVO {\n return applyMicroExpression(this._dimensions, this._microConfig, this._time);\n }\n\n /**\n * Get computed visual state for rendering\n */\n getVisualState(): VisualState {\n return computeVisualState(this.getAnimatedDimensions());\n }\n\n /**\n * Set dimensions immediately (no transition)\n * Values are clamped to valid 0-1 range\n */\n setDimensions(dims: Partial<AVO>): void {\n this._dimensions = clampAVO({ ...this._dimensions, ...dims });\n this._transition = null;\n this._emit('change', this._dimensions);\n }\n\n /**\n * Transition to target dimensions over time\n * Auto-calculates duration and easing if not specified\n */\n transitionTo(target: Partial<AVO>, options: TransitionOptions = {}): void {\n const from = { ...this._dimensions };\n const to = clampAVO({ ...this._dimensions, ...target });\n\n const autoConfig = getTransitionConfig(from, to);\n\n this._transition = {\n from,\n to,\n duration: options.duration ?? autoConfig.duration,\n easing: options.easing ?? autoConfig.easing,\n elapsed: 0,\n onComplete: options.onComplete,\n };\n\n this._emit('transitionStart', { from, to });\n }\n\n /**\n * Transition to a named anchor state\n * Emits anchorReached when transition completes\n */\n transitionToAnchor(anchor: AnchorState, options: TransitionOptions = {}): void {\n this.transitionTo(ANCHOR_STATES[anchor], {\n ...options,\n onComplete: () => {\n this._emit('anchorReached', anchor);\n options.onComplete?.();\n },\n });\n }\n\n /**\n * Handle emotion events from agent behaviors\n * Maps event types to appropriate anchor transitions\n */\n handleEvent(event: EmotionEvent): void {\n const intensity = event.intensity ?? 0.5;\n\n switch (event.type) {\n case 'input_received':\n this.transitionToAnchor('listening');\n break;\n case 'processing_start':\n this.transitionToAnchor('thinking');\n break;\n case 'processing_complete':\n this.transitionToAnchor('responding');\n break;\n case 'error_occurred':\n this.transitionToAnchor(intensity > 0.7 ? 'error' : 'concerned');\n break;\n case 'success':\n this.transitionToAnchor(intensity > 0.7 ? 'proud' : 'satisfied');\n break;\n case 'user_idle':\n this.transitionToAnchor('idle', { duration: 2000 });\n break;\n case 'interrupt':\n this.setDimensions({ arousal: Math.min(this._dimensions.arousal + 0.2, 1) });\n break;\n }\n }\n\n /**\n * Blend toward target dimensions by a factor (0-1)\n * Useful for continuous input-driven changes\n */\n blendToward(target: Partial<AVO>, factor: number): void {\n const to = clampAVO({ ...this._dimensions, ...target });\n this._dimensions = blendAVO(this._dimensions, to, factor);\n this._emit('change', this._dimensions);\n }\n\n /**\n * Check if currently transitioning\n */\n isTransitioning(): boolean {\n return this._transition !== null;\n }\n\n /**\n * Cancel current transition, keeping current position\n */\n cancelTransition(): void {\n this._transition = null;\n }\n\n /**\n * Subscribe to controller events\n * Returns unsubscribe function\n */\n on<K extends keyof EmotionControllerEvents>(\n event: K,\n handler: EventHandler<EmotionControllerEvents[K]>\n ): () => void {\n if (!this._listeners.has(event)) {\n this._listeners.set(event, new Set());\n }\n this._listeners.get(event)!.add(handler as EventHandler<unknown>);\n\n return () => {\n this._listeners.get(event)?.delete(handler as EventHandler<unknown>);\n };\n }\n\n /**\n * Update tick - call each frame with delta time in milliseconds\n * Advances transitions and micro-expression time\n */\n tick(deltaMs: number): void {\n if (this._disposed) return;\n\n this._time += deltaMs / 1000;\n\n if (this._transition) {\n this._transition.elapsed += deltaMs;\n // Handle duration 0 as immediate transition\n const progress = this._transition.duration <= 0\n ? 1\n : Math.min(this._transition.elapsed / this._transition.duration, 1);\n const easedProgress = ease(this._transition.easing, progress);\n\n this._dimensions = blendAVO(this._transition.from, this._transition.to, easedProgress);\n this._emit('change', this._dimensions);\n\n if (progress >= 1) {\n const onComplete = this._transition.onComplete;\n this._transition = null;\n this._emit('transitionEnd', this._dimensions);\n onComplete?.();\n }\n }\n }\n\n /**\n * Dispose controller and clean up resources\n */\n dispose(): void {\n this._disposed = true;\n this._listeners.clear();\n this._transition = null;\n }\n\n private _emit<K extends keyof EmotionControllerEvents>(\n event: K,\n data: EmotionControllerEvents[K]\n ): void {\n this._listeners.get(event)?.forEach((handler) => handler(data));\n }\n}\n","'use client';\n\nimport { useState, useEffect, useCallback, useRef } from 'react';\nimport type {\n AVO,\n AnchorState,\n TransitionOptions,\n EmotionEvent,\n VisualState,\n MicroExpressionConfig,\n} from '../types.js';\nimport { EmotionController } from '../controller.js';\n\nexport interface UseEmotionOptions {\n /** Initial dimensions */\n initial?: Partial<AVO>;\n /** Initial anchor state (overrides initial) */\n initialAnchor?: AnchorState;\n /** Enable micro-expressions (boolean or config object) */\n microExpressions?: boolean | MicroExpressionConfig;\n /** Callback on dimension change */\n onChange?: (dimensions: AVO) => void;\n /** Auto-tick with requestAnimationFrame (default: true) */\n autoTick?: boolean;\n}\n\nexport interface UseEmotionResult {\n /** Current dimensions (with micro-expressions if enabled) */\n dimensions: AVO;\n /** Base dimensions (without micro-expressions) */\n baseDimensions: AVO;\n /** Computed visual properties */\n visualState: VisualState;\n /** Set dimensions instantly */\n set: (dimensions: Partial<AVO>) => void;\n /** Transition to dimensions */\n transition: (dimensions: Partial<AVO>, options?: TransitionOptions) => void;\n /** Transition to anchor state */\n goTo: (anchor: AnchorState, options?: TransitionOptions) => void;\n /** Handle emotion event */\n emit: (event: EmotionEvent) => void;\n /** Currently transitioning */\n isTransitioning: boolean;\n /** Manual tick (if autoTick disabled) */\n tick: (deltaMs: number) => void;\n}\n\n/**\n * React hook for managing Glyph emotion state.\n *\n * Creates an EmotionController and provides reactive state updates.\n * Automatically handles RAF-based animation when autoTick is true (default).\n *\n * @example\n * ```tsx\n * const { dimensions, visualState, goTo, emit } = useEmotion({\n * initialAnchor: 'idle',\n * onChange: (dims) => console.log('Emotion changed:', dims),\n * });\n *\n * // Transition to a named state\n * goTo('thinking');\n *\n * // Handle agent events\n * emit({ type: 'processing_complete' });\n *\n * // Apply visual state to rendering\n * <mesh scale={visualState.scaleFactor}>\n * <meshStandardMaterial color={`hsl(${visualState.coreHue}, 80%, 50%)`} />\n * </mesh>\n * ```\n */\nexport function useEmotion(options: UseEmotionOptions = {}): UseEmotionResult {\n const {\n initial,\n initialAnchor,\n microExpressions = true,\n onChange,\n autoTick = true,\n } = options;\n\n // Create controller ref (stable across renders)\n const controllerRef = useRef<EmotionController | null>(null);\n\n if (!controllerRef.current) {\n controllerRef.current = new EmotionController({\n initial,\n initialAnchor,\n microExpressions,\n });\n }\n\n const controller = controllerRef.current;\n\n // State for React reactivity\n const [dimensions, setDimensions] = useState<AVO>(controller.getAnimatedDimensions());\n const [baseDimensions, setBaseDimensions] = useState<AVO>(controller.getDimensions());\n const [visualState, setVisualState] = useState<VisualState>(controller.getVisualState());\n const [isTransitioning, setIsTransitioning] = useState(false);\n\n // Store onChange in ref to avoid effect dependency changes\n const onChangeRef = useRef(onChange);\n onChangeRef.current = onChange;\n\n // Subscribe to controller events\n useEffect(() => {\n const unsub = controller.on('change', (dims) => {\n setBaseDimensions({ ...dims });\n setDimensions(controller.getAnimatedDimensions());\n setVisualState(controller.getVisualState());\n onChangeRef.current?.(dims);\n });\n\n const unsubStart = controller.on('transitionStart', () => {\n setIsTransitioning(true);\n });\n\n const unsubEnd = controller.on('transitionEnd', () => {\n setIsTransitioning(false);\n });\n\n return () => {\n unsub();\n unsubStart();\n unsubEnd();\n };\n }, [controller]);\n\n // Auto-tick with RAF\n useEffect(() => {\n if (!autoTick) return;\n\n let lastTime = performance.now();\n let rafId: number;\n\n const tick = (time: number) => {\n const delta = time - lastTime;\n lastTime = time;\n\n controller.tick(delta);\n setDimensions(controller.getAnimatedDimensions());\n setVisualState(controller.getVisualState());\n\n rafId = requestAnimationFrame(tick);\n };\n\n rafId = requestAnimationFrame(tick);\n\n return () => {\n cancelAnimationFrame(rafId);\n };\n }, [controller, autoTick]);\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n controller.dispose();\n };\n }, [controller]);\n\n // Stable callbacks\n const set = useCallback(\n (dims: Partial<AVO>) => {\n controller.setDimensions(dims);\n },\n [controller]\n );\n\n const transition = useCallback(\n (dims: Partial<AVO>, opts?: TransitionOptions) => {\n controller.transitionTo(dims, opts);\n },\n [controller]\n );\n\n const goTo = useCallback(\n (anchor: AnchorState, opts?: TransitionOptions) => {\n controller.transitionToAnchor(anchor, opts);\n },\n [controller]\n );\n\n const emit = useCallback(\n (event: EmotionEvent) => {\n controller.handleEvent(event);\n },\n [controller]\n );\n\n const tick = useCallback(\n (deltaMs: number) => {\n controller.tick(deltaMs);\n },\n [controller]\n );\n\n return {\n dimensions,\n baseDimensions,\n visualState,\n set,\n transition,\n goTo,\n emit,\n isTransitioning,\n tick,\n };\n}\n"],"mappings":"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","names":["tick"]}