@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.
- package/dist/audio.d.ts +163 -0
- package/dist/audio.js +39 -0
- package/dist/audio.js.map +1 -0
- package/dist/chunk-LLOGBVQT.js +445 -0
- package/dist/chunk-LLOGBVQT.js.map +1 -0
- package/dist/chunk-VU2XK2NI.js +583 -0
- package/dist/chunk-VU2XK2NI.js.map +1 -0
- package/dist/chunk-XE2IVCKJ.js +743 -0
- package/dist/chunk-XE2IVCKJ.js.map +1 -0
- package/dist/cognition.d.ts +742 -0
- package/dist/cognition.js +25 -0
- package/dist/cognition.js.map +1 -0
- package/dist/emotion.d.ts +288 -0
- package/dist/emotion.js +53 -0
- package/dist/emotion.js.map +1 -0
- package/dist/httpSpeechSynthesisProvider-CIR7L2Zr.d.ts +1698 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +93 -0
- package/dist/index.js.map +1 -0
- package/dist/types-B0jyNVTH.d.ts +85 -0
- package/dist/types-CRp9rbx0.d.ts +125 -0
- package/package.json +54 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cognition/types.ts","../src/cognition/schema.ts","../src/cognition/reducers.ts","../src/cognition/controller.ts","../src/cognition/hooks/useCognition.ts"],"sourcesContent":["import type { AVO } from '../emotion/types.js';\n\n// =============================================================================\n// Cognitive Mode\n// =============================================================================\n\nexport type CognitiveMode =\n | 'idle'\n | 'listening'\n | 'deliberating'\n | 'acting'\n | 'explaining'\n | 'recovering'\n | 'blocked';\n\nexport type CognitiveSubmode =\n | 'reading'\n | 'searching'\n | 'verifying'\n | 'waiting'\n | 'writing'\n | 'tool_call';\n\n// =============================================================================\n// Continuous Signals (all normalized 0..1)\n// =============================================================================\n\nexport interface CognitionSignals {\n attention: number;\n workload: number;\n timePressure: number;\n planDrift: number;\n costPressure: number;\n risk: number;\n uncertainty: number;\n confidence: number;\n errorStress: number;\n}\n\n// =============================================================================\n// Persona Signals\n// =============================================================================\n\nexport interface PersonaSignals {\n personaAnchor: number;\n personaDriftRisk: number;\n personaStyle?: string[];\n}\n\n// =============================================================================\n// Dynamics (kernel integration)\n// =============================================================================\n\nexport interface TrapWarning {\n stateId: string;\n reason: string;\n recommendation: string;\n severity?: 'info' | 'warning' | 'danger';\n}\n\nexport interface DetailedBalance {\n chi2PerNdf: number;\n passed: boolean;\n threshold: number;\n}\n\nexport interface DynamicsState {\n potentialV?: number;\n actionRate?: number;\n detailedBalance?: DetailedBalance;\n traps?: TrapWarning[];\n}\n\n// =============================================================================\n// Personality + Policy (cockpit integration)\n// =============================================================================\n\nexport interface PersonalityConfig {\n style: 'professional' | 'casual' | 'terse' | 'verbose';\n riskTolerance: 'conservative' | 'moderate' | 'aggressive';\n autonomy: 'low' | 'medium' | 'high' | 'full';\n}\n\nexport interface PolicyConfig {\n safetyMode: boolean;\n trustTier?: string;\n}\n\n// =============================================================================\n// Evidence (verification-first)\n// =============================================================================\n\nexport type EvidenceRef =\n | { type: 'run'; runId: string }\n | { type: 'run_receipt'; receiptHash: string }\n | { type: 'artifact'; path: string; digest?: string }\n | { type: 'ui'; componentId: string; note?: string };\n\n// =============================================================================\n// Full Cognition State\n// =============================================================================\n\nexport interface CognitionState extends CognitionSignals, PersonaSignals {\n mode: CognitiveMode;\n submode?: CognitiveSubmode;\n focusRunId?: string;\n\n dynamics?: DynamicsState;\n personality?: PersonalityConfig;\n policy?: PolicyConfig;\n\n moodAVO: AVO;\n emotionAVO: AVO;\n}\n\n// =============================================================================\n// Cognition Events\n// =============================================================================\n\nexport type CognitionEvent =\n | { type: 'ui.input_received'; intensity?: number }\n | { type: 'ui.user_idle' }\n | { type: 'ui.interrupt'; intensity?: number }\n | { type: 'run.event'; runId: string; status: string; progress?: number }\n | { type: 'run.started'; runId: string }\n | { type: 'run.completed'; runId: string; success: boolean }\n | { type: 'intensity.update'; values: Partial<CognitionSignals> }\n | { type: 'signals.update'; signals: Partial<CognitionSignals> }\n | { type: 'dynamics.update'; dynamics: DynamicsState }\n | { type: 'policy.update'; policy?: PolicyConfig; personality?: PersonalityConfig }\n | { type: 'text.user_message'; text: string; categories?: string[] }\n | { type: 'tick'; deltaMs: number };\n\n// =============================================================================\n// Cognition Snapshot (serialization)\n// =============================================================================\n\nexport interface CognitionSnapshot {\n version: '1.0';\n timestamp: number;\n state: CognitionState;\n recentEvents?: Array<{ t: number; event: CognitionEvent }>;\n}\n\n// =============================================================================\n// Helpers\n// =============================================================================\n\nexport function clamp01(value: number): number {\n return Math.max(0, Math.min(1, value));\n}\n\nconst DEFAULT_AVO: AVO = { arousal: 0.25, valence: 0.6, openness: 0.35 };\n\nexport function createInitialCognitionState(\n overrides?: Partial<CognitionState>\n): CognitionState {\n return {\n mode: 'idle',\n attention: 0.3,\n workload: 0,\n timePressure: 0,\n planDrift: 0,\n costPressure: 0,\n risk: 0,\n uncertainty: 0.2,\n confidence: 0.8,\n errorStress: 0,\n personaAnchor: 1,\n personaDriftRisk: 0,\n moodAVO: { ...DEFAULT_AVO },\n emotionAVO: { ...DEFAULT_AVO },\n ...overrides,\n };\n}\n","import { z } from 'zod';\n\n// =============================================================================\n// Primitives\n// =============================================================================\n\nconst Signal01 = z.number().min(0).max(1);\n\nconst CognitiveModeSchema = z.enum([\n 'idle',\n 'listening',\n 'deliberating',\n 'acting',\n 'explaining',\n 'recovering',\n 'blocked',\n]);\n\nconst CognitiveSubmodeSchema = z.enum([\n 'reading',\n 'searching',\n 'verifying',\n 'waiting',\n 'writing',\n 'tool_call',\n]);\n\nconst AVOSchema = z.object({\n arousal: Signal01,\n valence: Signal01,\n openness: Signal01,\n});\n\n// =============================================================================\n// Sub-objects\n// =============================================================================\n\nconst TrapWarningSchema = z.object({\n stateId: z.string(),\n reason: z.string(),\n recommendation: z.string(),\n severity: z.enum(['info', 'warning', 'danger']).optional(),\n});\n\nconst DetailedBalanceSchema = z.object({\n chi2PerNdf: z.number(),\n passed: z.boolean(),\n threshold: z.number(),\n});\n\nconst DynamicsStateSchema = z.object({\n potentialV: z.number().optional(),\n actionRate: Signal01.optional(),\n detailedBalance: DetailedBalanceSchema.optional(),\n traps: z.array(TrapWarningSchema).optional(),\n});\n\nconst PersonalityConfigSchema = z.object({\n style: z.enum(['professional', 'casual', 'terse', 'verbose']),\n riskTolerance: z.enum(['conservative', 'moderate', 'aggressive']),\n autonomy: z.enum(['low', 'medium', 'high', 'full']),\n});\n\nconst PolicyConfigSchema = z.object({\n safetyMode: z.boolean(),\n trustTier: z.string().optional(),\n});\n\n// =============================================================================\n// CognitionState\n// =============================================================================\n\nexport const CognitionStateSchema = z.object({\n mode: CognitiveModeSchema,\n submode: CognitiveSubmodeSchema.optional(),\n focusRunId: z.string().optional(),\n\n attention: Signal01,\n workload: Signal01,\n timePressure: Signal01,\n planDrift: Signal01,\n costPressure: Signal01,\n risk: Signal01,\n uncertainty: Signal01,\n confidence: Signal01,\n errorStress: Signal01,\n\n personaAnchor: Signal01,\n personaDriftRisk: Signal01,\n personaStyle: z.array(z.string()).optional(),\n\n dynamics: DynamicsStateSchema.optional(),\n personality: PersonalityConfigSchema.optional(),\n policy: PolicyConfigSchema.optional(),\n\n moodAVO: AVOSchema,\n emotionAVO: AVOSchema,\n});\n\n// =============================================================================\n// CognitionSnapshot\n// =============================================================================\n\nexport const CognitionSnapshotSchema = z.object({\n version: z.literal('1.0'),\n timestamp: z.number(),\n state: CognitionStateSchema,\n recentEvents: z\n .array(\n z.object({\n t: z.number(),\n event: z.record(z.unknown()),\n })\n )\n .optional(),\n});\n\n// =============================================================================\n// Validation helpers\n// =============================================================================\n\nexport type CognitionSnapshotInput = z.input<typeof CognitionSnapshotSchema>;\nexport type CognitionSnapshotOutput = z.output<typeof CognitionSnapshotSchema>;\n\nexport interface CognitionSnapshotValidationResult {\n success: boolean;\n data?: CognitionSnapshotOutput;\n error?: z.ZodError;\n}\n\nexport function validateCognitionSnapshot(\n input: unknown\n): CognitionSnapshotValidationResult {\n const result = CognitionSnapshotSchema.safeParse(input);\n if (result.success) {\n return { success: true, data: result.data };\n }\n return { success: false, error: result.error };\n}\n","// packages/bb-ui/src/cognition/reducers.ts\n\n/**\n * Cognition State Reducers\n *\n * Pure functions for updating cognition state based on events and time decay.\n */\n\nimport type {\n CognitionState,\n CognitionEvent,\n CognitiveMode,\n CognitionSignals,\n DynamicsState,\n PolicyConfig,\n PersonalityConfig,\n} from './types.js';\nimport { clamp01 } from './types.js';\n\n/**\n * Trigger types that cause mode transitions\n */\nexport type CognitionTrigger =\n | 'ui.input_received'\n | 'ui.user_idle'\n | 'ui.interrupt'\n | 'run.started'\n | 'run.completed'\n | 'run.event';\n\n/**\n * Maps trigger events to resulting cognitive modes\n */\nexport const MODE_TRANSITION_MAP: Record<CognitionTrigger, CognitiveMode> = {\n 'ui.input_received': 'listening',\n 'ui.user_idle': 'idle',\n 'ui.interrupt': 'listening',\n 'run.started': 'deliberating',\n 'run.completed': 'idle',\n 'run.event': 'deliberating',\n};\n\n/**\n * Decay rates per second for various signals\n */\nexport const DECAY_RATES: Record<'errorStress' | 'timePressure' | 'planDrift', number> = {\n errorStress: 0.1, // Decays 10% per second\n timePressure: 0.05, // Decays 5% per second\n planDrift: 0.08, // Decays 8% per second\n};\n\n/**\n * Reduce signals from a signals.update event\n */\nfunction reduceSignals(\n state: CognitionState,\n signals: Partial<CognitionSignals>\n): CognitionState {\n return {\n ...state,\n attention: signals.attention !== undefined ? clamp01(signals.attention) : state.attention,\n workload: signals.workload !== undefined ? clamp01(signals.workload) : state.workload,\n risk: signals.risk !== undefined ? clamp01(signals.risk) : state.risk,\n timePressure: signals.timePressure !== undefined ? clamp01(signals.timePressure) : state.timePressure,\n errorStress: signals.errorStress !== undefined ? clamp01(signals.errorStress) : state.errorStress,\n planDrift: signals.planDrift !== undefined ? clamp01(signals.planDrift) : state.planDrift,\n costPressure: signals.costPressure !== undefined ? clamp01(signals.costPressure) : state.costPressure,\n uncertainty: signals.uncertainty !== undefined ? clamp01(signals.uncertainty) : state.uncertainty,\n confidence: signals.confidence !== undefined ? clamp01(signals.confidence) : state.confidence,\n };\n}\n\n/**\n * Reduce dynamics state update\n */\nfunction reduceDynamicsUpdate(\n state: CognitionState,\n dynamics: DynamicsState\n): CognitionState {\n return {\n ...state,\n dynamics,\n };\n}\n\n/**\n * Reduce policy/personality update\n */\nfunction reducePolicyUpdate(\n state: CognitionState,\n policy?: PolicyConfig,\n personality?: PersonalityConfig\n): CognitionState {\n return {\n ...state,\n policy: policy ?? state.policy,\n personality: personality ?? state.personality,\n };\n}\n\n/**\n * Reduce mode transitions based on events\n */\nfunction reduceModeTransition(\n state: CognitionState,\n event: CognitionEvent\n): CognitionState {\n const trigger = event.type as CognitionTrigger;\n const newMode = MODE_TRANSITION_MAP[trigger];\n\n if (!newMode) {\n return state;\n }\n\n let focusRunId = state.focusRunId;\n let errorStress = state.errorStress;\n let mode = newMode;\n\n // Handle run-related events\n if (event.type === 'run.started') {\n focusRunId = event.runId;\n } else if (event.type === 'run.completed') {\n focusRunId = undefined;\n if (!event.success) {\n errorStress = clamp01(state.errorStress + 0.2);\n mode = 'recovering';\n }\n } else if (event.type === 'run.event') {\n focusRunId = event.runId;\n }\n\n return {\n ...state,\n mode,\n focusRunId,\n errorStress,\n };\n}\n\n/**\n * Apply exponential decay to time-based signals\n */\nexport function reduceDecay(\n state: CognitionState,\n deltaMs: number\n): CognitionState {\n const deltaSec = deltaMs / 1000;\n\n // Exponential decay: value * e^(-rate * time)\n const errorStress = clamp01(\n state.errorStress * Math.exp(-DECAY_RATES.errorStress * deltaSec)\n );\n const timePressure = clamp01(\n state.timePressure * Math.exp(-DECAY_RATES.timePressure * deltaSec)\n );\n const planDrift = clamp01(\n state.planDrift * Math.exp(-DECAY_RATES.planDrift * deltaSec)\n );\n\n return {\n ...state,\n errorStress,\n timePressure,\n planDrift,\n };\n}\n\n/**\n * Main event reducer - handles all cognition events\n */\nexport function reduceEvent(\n state: CognitionState,\n event: CognitionEvent\n): CognitionState {\n switch (event.type) {\n case 'signals.update':\n return reduceSignals(state, event.signals);\n\n case 'intensity.update':\n return reduceSignals(state, event.values);\n\n case 'dynamics.update':\n return reduceDynamicsUpdate(state, event.dynamics);\n\n case 'policy.update':\n return reducePolicyUpdate(state, event.policy, event.personality);\n\n case 'tick':\n return reduceDecay(state, event.deltaMs);\n\n case 'ui.input_received':\n case 'ui.user_idle':\n case 'ui.interrupt':\n case 'run.started':\n case 'run.completed':\n case 'run.event':\n return reduceModeTransition(state, event);\n\n case 'text.user_message': {\n // Text messages transition to listening mode and update persona drift risk\n // based on message categories per spec section 7.5\n const categories = event.categories ?? [];\n const driftRisk = categories.includes('meta_reflection')\n ? 0.3\n : categories.includes('vulnerable_disclosure')\n ? 0.4\n : 0;\n\n // Exponential smoothing: 70% previous, 30% new\n const newPersonaDriftRisk = clamp01(\n state.personaDriftRisk * 0.7 + driftRisk * 0.3\n );\n\n return {\n ...state,\n mode: 'listening',\n personaDriftRisk: newPersonaDriftRisk,\n };\n }\n\n default: {\n // Exhaustive check - TypeScript will error if we miss a case\n const _exhaustive: never = event;\n return state;\n }\n }\n}\n","// packages/bb-ui/src/cognition/controller.ts\n\n/**\n * CognitionController manages the cognitive state lifecycle for the Glyph character.\n *\n * It handles:\n * - Cognitive mode transitions (idle, listening, deliberating, acting, etc.)\n * - Continuous signal processing (attention, workload, risk, etc.)\n * - Event-driven state changes from UI and kernel events\n * - Emotion bridge (mood and emotion AVO dimensions)\n * - Time-based decay of stress signals\n */\n\nimport type { AVO, AnchorState } from '../emotion/types.js';\nimport type {\n CognitionState,\n CognitionEvent,\n CognitiveMode,\n} from './types.js';\nimport { createInitialCognitionState } from './types.js';\nimport { reduceEvent, reduceDecay } from './reducers.js';\n\n// =============================================================================\n// Mode Mappings\n// =============================================================================\n\n/**\n * Maps cognitive modes to emotion anchor states for visual representation\n */\nexport const MODE_TO_ANCHOR: Record<CognitiveMode, AnchorState> = {\n idle: 'idle',\n listening: 'listening',\n deliberating: 'thinking',\n acting: 'focused',\n explaining: 'explaining',\n recovering: 'recovering',\n blocked: 'concerned',\n};\n\n/**\n * Default AVO values for each cognitive mode\n * These are the target emotional states for each mode\n */\nexport const MODE_TO_AVO: Record<CognitiveMode, AVO> = {\n idle: { arousal: 0.25, valence: 0.60, openness: 0.35 },\n listening: { arousal: 0.45, valence: 0.70, openness: 0.05 },\n deliberating: { arousal: 0.60, valence: 0.60, openness: 0.40 },\n acting: { arousal: 0.70, valence: 0.70, openness: 0.50 },\n explaining: { arousal: 0.55, valence: 0.80, openness: 0.85 },\n recovering: { arousal: 0.40, valence: 0.45, openness: 0.40 },\n blocked: { arousal: 0.55, valence: 0.30, openness: 0.30 },\n};\n\n// =============================================================================\n// Types\n// =============================================================================\n\ntype EventHandler<T> = (data: T) => void;\n\nexport interface CognitionControllerEvents {\n /** Emitted when any state change occurs */\n change: CognitionState;\n /** Emitted when mode changes */\n modeChange: { from: CognitiveMode; to: CognitiveMode };\n}\n\nexport interface CognitionControllerOptions {\n /** Initial state overrides */\n initial?: Partial<CognitionState>;\n}\n\nexport interface EmotionTarget {\n /** The anchor state name for the current mode */\n anchor: AnchorState;\n /** The target AVO values adjusted by signals */\n avo: AVO;\n}\n\n/**\n * CognitionController manages the cognitive state lifecycle for the Glyph character.\n */\nexport class CognitionController {\n private _state: CognitionState;\n private _listeners: Map<keyof CognitionControllerEvents, Set<EventHandler<unknown>>> = new Map();\n private _disposed: boolean = false;\n\n constructor(options: CognitionControllerOptions = {}) {\n this._state = createInitialCognitionState(options.initial);\n }\n\n /**\n * Get current cognition state\n */\n getState(): CognitionState {\n return { ...this._state };\n }\n\n /**\n * Get the emotion target for the current cognitive state\n * Returns anchor state and AVO values adjusted by signals\n */\n getEmotionTarget(): EmotionTarget {\n const anchor = MODE_TO_ANCHOR[this._state.mode];\n const baseAVO = MODE_TO_AVO[this._state.mode];\n\n // Adjust AVO based on signals\n const avo = this._adjustAVOBySignals(baseAVO);\n\n return { anchor, avo };\n }\n\n /**\n * Get emotion bridge - derives anchor and AVO from cognitive state\n * @deprecated Use getEmotionTarget() instead\n */\n getEmotionBridge(): { anchor?: AnchorState; avo?: AVO } {\n const target = this.getEmotionTarget();\n return { anchor: target.anchor, avo: target.avo };\n }\n\n /**\n * Handle a cognition event and update state\n */\n handleEvent(event: CognitionEvent): void {\n if (this._disposed) return;\n\n const prevMode = this._state.mode;\n this._state = reduceEvent(this._state, event);\n\n if (this._state.mode !== prevMode) {\n this._emitEvent('modeChange', { from: prevMode, to: this._state.mode });\n }\n\n this._emitEvent('change', this._state);\n }\n\n /**\n * Process an event and update state\n * @deprecated Use handleEvent() instead\n */\n emit(event: CognitionEvent): void {\n this.handleEvent(event);\n }\n\n /**\n * Update tick - call each frame with delta time in milliseconds\n * Applies time-based decay to stress signals\n */\n tick(deltaMs: number): void {\n if (this._disposed) return;\n\n const prevState = this._state;\n this._state = reduceDecay(this._state, deltaMs);\n\n // Only emit change if state actually changed\n if (\n prevState.errorStress !== this._state.errorStress ||\n prevState.timePressure !== this._state.timePressure ||\n prevState.planDrift !== this._state.planDrift\n ) {\n this._emitEvent('change', this._state);\n }\n }\n\n /**\n * Subscribe to controller events\n * Returns unsubscribe function\n */\n on<K extends keyof CognitionControllerEvents>(\n event: K,\n handler: EventHandler<CognitionControllerEvents[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 * Dispose controller and clean up resources\n */\n dispose(): void {\n this._disposed = true;\n this._listeners.clear();\n }\n\n /**\n * Adjust AVO values based on current signal levels\n */\n private _adjustAVOBySignals(baseAVO: AVO): AVO {\n const { errorStress, workload, timePressure, uncertainty, confidence, personaDriftRisk } = this._state;\n\n // Arousal increases with workload, time pressure, and error stress\n const arousalBoost = (workload * 0.2) + (timePressure * 0.15) + (errorStress * 0.1);\n\n // Valence decreases with error stress and uncertainty\n const valenceDrops = (errorStress * 0.3) + (uncertainty * 0.15);\n const valenceBoost = (confidence - 0.5) * 0.2; // Confidence above 0.5 boosts valence\n\n // Openness decreases with persona drift risk (more grounded when drift risk is high)\n // Per spec section 7.6: high drift risk should reduce openness to signal groundedness\n const opennessDrop = personaDriftRisk * 0.3;\n\n return {\n arousal: Math.max(0, Math.min(1, baseAVO.arousal + arousalBoost)),\n valence: Math.max(0, Math.min(1, baseAVO.valence - valenceDrops + valenceBoost)),\n openness: Math.max(0, Math.min(1, baseAVO.openness - opennessDrop)),\n };\n }\n\n private _emitEvent<K extends keyof CognitionControllerEvents>(\n event: K,\n data: CognitionControllerEvents[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 { AVO, AnchorState } from '../../emotion/types.js';\nimport type { CognitionState, CognitionEvent } from '../types.js';\nimport { CognitionController, type CognitionControllerOptions, type EmotionTarget } from '../controller.js';\n\nexport interface UseCognitionOptions extends CognitionControllerOptions {\n onChange?: (state: CognitionState) => void;\n autoTick?: boolean;\n}\n\nexport interface UseCognitionResult {\n state: CognitionState;\n emotion: EmotionTarget;\n handleEvent: (event: CognitionEvent) => void;\n tick: (deltaMs: number) => void;\n /** @deprecated Use handleEvent instead */\n emit: (event: CognitionEvent) => void;\n}\n\n/**\n * React hook for managing Glyph cognition state.\n *\n * Creates a CognitionController and provides reactive state updates.\n * Automatically handles RAF-based animation when autoTick is true (default).\n *\n * @example\n * ```tsx\n * const { state, emotion, emit, tick } = useCognition({\n * initial: { mode: 'idle' },\n * onChange: (state) => console.log('Cognition changed:', state),\n * });\n *\n * // Handle agent events\n * emit({ type: 'run.started', runId: 'r1' });\n *\n * // Access emotion bridge for rendering\n * console.log(emotion.anchor, emotion.avo);\n * ```\n */\nexport function useCognition(options: UseCognitionOptions = {}): UseCognitionResult {\n const { initial, onChange, autoTick = true } = options;\n\n // Create controller ref (stable across renders)\n const controllerRef = useRef<CognitionController | null>(null);\n\n if (!controllerRef.current) {\n controllerRef.current = new CognitionController({ initial });\n }\n\n const controller = controllerRef.current;\n\n // State for React reactivity\n const [state, setState] = useState<CognitionState>(controller.getState());\n const [emotion, setEmotion] = useState<EmotionTarget>(\n controller.getEmotionTarget()\n );\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', (newState) => {\n setState({ ...newState });\n setEmotion(controller.getEmotionTarget());\n onChangeRef.current?.(newState);\n });\n\n return () => {\n unsub();\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 tickFn = (time: number) => {\n const delta = time - lastTime;\n lastTime = time;\n\n controller.tick(delta);\n\n rafId = requestAnimationFrame(tickFn);\n };\n\n rafId = requestAnimationFrame(tickFn);\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 handleEvent = useCallback(\n (event: CognitionEvent) => {\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 // Deprecated alias for backwards compatibility\n const emit = handleEvent;\n\n return {\n state,\n emotion,\n handleEvent,\n tick,\n emit,\n };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,583 @@
|
|
|
1
|
+
// src/emotion/constants.ts
|
|
2
|
+
function isValidAVO(avo) {
|
|
3
|
+
return avo.arousal >= 0 && avo.arousal <= 1 && avo.valence >= 0 && avo.valence <= 1 && avo.openness >= 0 && avo.openness <= 1;
|
|
4
|
+
}
|
|
5
|
+
function clampAVO(avo) {
|
|
6
|
+
return {
|
|
7
|
+
arousal: Math.max(0, Math.min(1, avo.arousal ?? 0.25)),
|
|
8
|
+
valence: Math.max(0, Math.min(1, avo.valence ?? 0.6)),
|
|
9
|
+
openness: Math.max(0, Math.min(1, avo.openness ?? 0.35))
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
var ANCHOR_STATES = {
|
|
13
|
+
// Rest states
|
|
14
|
+
dormant: { arousal: 0.05, valence: 0.55, openness: 0.3 },
|
|
15
|
+
idle: { arousal: 0.25, valence: 0.6, openness: 0.35 },
|
|
16
|
+
// Receptive states
|
|
17
|
+
attentive: { arousal: 0.4, valence: 0.7, openness: 0.2 },
|
|
18
|
+
curious: { arousal: 0.5, valence: 0.75, openness: 0.1 },
|
|
19
|
+
listening: { arousal: 0.45, valence: 0.7, openness: 0.05 },
|
|
20
|
+
// Processing states
|
|
21
|
+
thinking: { arousal: 0.6, valence: 0.6, openness: 0.4 },
|
|
22
|
+
contemplating: { arousal: 0.55, valence: 0.65, openness: 0.45 },
|
|
23
|
+
focused: { arousal: 0.7, valence: 0.7, openness: 0.5 },
|
|
24
|
+
// Expressive states
|
|
25
|
+
responding: { arousal: 0.6, valence: 0.75, openness: 0.8 },
|
|
26
|
+
explaining: { arousal: 0.55, valence: 0.8, openness: 0.85 },
|
|
27
|
+
enthusiastic: { arousal: 0.8, valence: 0.9, openness: 0.75 },
|
|
28
|
+
// Completion states
|
|
29
|
+
satisfied: { arousal: 0.3, valence: 0.9, openness: 0.5 },
|
|
30
|
+
proud: { arousal: 0.45, valence: 0.95, openness: 0.6 },
|
|
31
|
+
// Negative states
|
|
32
|
+
uncertain: { arousal: 0.45, valence: 0.4, openness: 0.35 },
|
|
33
|
+
concerned: { arousal: 0.55, valence: 0.3, openness: 0.3 },
|
|
34
|
+
struggling: { arousal: 0.7, valence: 0.35, openness: 0.45 },
|
|
35
|
+
alarmed: { arousal: 0.8, valence: 0.2, openness: 0.4 },
|
|
36
|
+
error: { arousal: 0.75, valence: 0.1, openness: 0.35 },
|
|
37
|
+
// Recovery states
|
|
38
|
+
recovering: { arousal: 0.4, valence: 0.45, openness: 0.4 },
|
|
39
|
+
relieved: { arousal: 0.35, valence: 0.75, openness: 0.45 }
|
|
40
|
+
};
|
|
41
|
+
var LEGACY_STATE_MAP = {
|
|
42
|
+
idle: "idle",
|
|
43
|
+
listening: "listening",
|
|
44
|
+
thinking: "thinking",
|
|
45
|
+
responding: "responding",
|
|
46
|
+
success: "satisfied",
|
|
47
|
+
error: "error",
|
|
48
|
+
sleep: "dormant"
|
|
49
|
+
};
|
|
50
|
+
var DEFAULT_MICRO_CONFIG = {
|
|
51
|
+
enabled: true,
|
|
52
|
+
arousalNoise: 0.02,
|
|
53
|
+
valenceNoise: 0.015,
|
|
54
|
+
opennessNoise: 0.01,
|
|
55
|
+
frequency: 0.3
|
|
56
|
+
};
|
|
57
|
+
var DEFAULT_TRANSITION_DURATIONS = {
|
|
58
|
+
micro: 150,
|
|
59
|
+
standard: 400,
|
|
60
|
+
mood: 800,
|
|
61
|
+
major: 1200
|
|
62
|
+
};
|
|
63
|
+
var DEFAULT_AVO = ANCHOR_STATES.idle;
|
|
64
|
+
|
|
65
|
+
// src/emotion/mapping.ts
|
|
66
|
+
function lerp(a, b, t) {
|
|
67
|
+
return a + (b - a) * t;
|
|
68
|
+
}
|
|
69
|
+
function mapArousal(a) {
|
|
70
|
+
return {
|
|
71
|
+
breathingRate: 0.3 + Math.pow(a, 1.5) * 1.7,
|
|
72
|
+
// 0.3 - 2.0 Hz
|
|
73
|
+
breathingAmplitude: 0.01 + a * 0.05,
|
|
74
|
+
// 1% - 6%
|
|
75
|
+
ringRotationSpeed: 0.1 + Math.pow(a, 1.3) * 1.9,
|
|
76
|
+
// 0.1 - 2.0 rad/s
|
|
77
|
+
particleVelocity: 0.02 + a * 0.18,
|
|
78
|
+
// 0.02 - 0.20
|
|
79
|
+
particleCount: Math.floor(20 + a * 80),
|
|
80
|
+
// 20 - 100
|
|
81
|
+
glowPulseRate: 0.2 + Math.pow(a, 1.4) * 1.3
|
|
82
|
+
// 0.2 - 1.5 Hz
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
function mapValence(v) {
|
|
86
|
+
const colorT = 1 / (1 + Math.exp(-8 * (v - 0.4)));
|
|
87
|
+
return {
|
|
88
|
+
coreHue: lerp(220, 35, colorT),
|
|
89
|
+
// Blue(220) → Gold(35)
|
|
90
|
+
coreSaturation: 0.4 + v * 0.45,
|
|
91
|
+
// 40% - 85%
|
|
92
|
+
motionNoise: 0.15 * Math.pow(1 - v, 2),
|
|
93
|
+
// High noise when low
|
|
94
|
+
scaleFactor: 0.92 + v * 0.16,
|
|
95
|
+
// 0.92x - 1.08x
|
|
96
|
+
emissiveIntensity: 0.2 + Math.pow(v, 1.5) * 0.7
|
|
97
|
+
// 0.2 - 0.9
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
function mapOpenness(o) {
|
|
101
|
+
return {
|
|
102
|
+
particleFlowDirection: lerp(-1, 1, o),
|
|
103
|
+
// -1 (in) to +1 (out)
|
|
104
|
+
particleSpreadAngle: lerp(30, 120, o),
|
|
105
|
+
// 30° - 120°
|
|
106
|
+
breathingPhaseBias: lerp(-0.3, 0.3, o),
|
|
107
|
+
// Inhale vs exhale bias
|
|
108
|
+
ringTilt: lerp(-15, 15, o),
|
|
109
|
+
// -15° to +15°
|
|
110
|
+
auraExpansion: lerp(0.95, 1.1, o)
|
|
111
|
+
// 0.95x - 1.1x
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
function computeVisualState(avo) {
|
|
115
|
+
const arousalMap = mapArousal(avo.arousal);
|
|
116
|
+
const valenceMap = mapValence(avo.valence);
|
|
117
|
+
const opennessMap = mapOpenness(avo.openness);
|
|
118
|
+
const overallIntensity = 0.3 + avo.arousal * 0.4 + avo.valence * 0.3;
|
|
119
|
+
return {
|
|
120
|
+
...arousalMap,
|
|
121
|
+
...valenceMap,
|
|
122
|
+
...opennessMap,
|
|
123
|
+
overallIntensity
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
function avoDistance(a, b) {
|
|
127
|
+
return Math.sqrt(
|
|
128
|
+
Math.pow(a.arousal - b.arousal, 2) + Math.pow(a.valence - b.valence, 2) + Math.pow(a.openness - b.openness, 2)
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
function blendAVO(from, to, t) {
|
|
132
|
+
return {
|
|
133
|
+
arousal: lerp(from.arousal, to.arousal, t),
|
|
134
|
+
valence: lerp(from.valence, to.valence, t),
|
|
135
|
+
openness: lerp(from.openness, to.openness, t)
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
function getAnimationWeights(currentAVO) {
|
|
139
|
+
const weights = {
|
|
140
|
+
idle: 0,
|
|
141
|
+
listening: 0,
|
|
142
|
+
thinking: 0,
|
|
143
|
+
responding: 0,
|
|
144
|
+
success: 0,
|
|
145
|
+
error: 0,
|
|
146
|
+
sleep: 0
|
|
147
|
+
};
|
|
148
|
+
for (const [state, anchor] of Object.entries(LEGACY_STATE_MAP)) {
|
|
149
|
+
const targetAVO = ANCHOR_STATES[anchor];
|
|
150
|
+
const distance = avoDistance(currentAVO, targetAVO);
|
|
151
|
+
weights[state] = Math.max(0, 1 - distance * 2);
|
|
152
|
+
}
|
|
153
|
+
const total = Object.values(weights).reduce((a, b) => a + b, 0);
|
|
154
|
+
if (total > 0) {
|
|
155
|
+
for (const key of Object.keys(weights)) {
|
|
156
|
+
weights[key] /= total;
|
|
157
|
+
}
|
|
158
|
+
} else {
|
|
159
|
+
weights.idle = 1;
|
|
160
|
+
}
|
|
161
|
+
return weights;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// src/emotion/transitions.ts
|
|
165
|
+
var EASING_FUNCTIONS = {
|
|
166
|
+
linear: (t) => t,
|
|
167
|
+
easeIn: (t) => t * t,
|
|
168
|
+
easeOut: (t) => 1 - Math.pow(1 - t, 2),
|
|
169
|
+
easeInOut: (t) => t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2,
|
|
170
|
+
spring: (t) => {
|
|
171
|
+
const c4 = 2 * Math.PI / 3;
|
|
172
|
+
return t === 0 ? 0 : t === 1 ? 1 : Math.pow(2, -10 * t) * Math.sin((t * 10 - 0.75) * c4) + 1;
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
function ease(fn, t) {
|
|
176
|
+
return EASING_FUNCTIONS[fn](Math.max(0, Math.min(1, t)));
|
|
177
|
+
}
|
|
178
|
+
function getTransitionDuration(from, to) {
|
|
179
|
+
const distance = avoDistance(from, to);
|
|
180
|
+
const valenceDrop = from.valence - to.valence;
|
|
181
|
+
const arousalSpike = to.arousal - from.arousal;
|
|
182
|
+
if (valenceDrop > 0.3 && arousalSpike > 0.2) {
|
|
183
|
+
return 200;
|
|
184
|
+
}
|
|
185
|
+
if (to.valence > from.valence && to.valence > 0.6) {
|
|
186
|
+
return 600 + distance * 400;
|
|
187
|
+
}
|
|
188
|
+
return Math.floor(200 + distance * 800);
|
|
189
|
+
}
|
|
190
|
+
function getTransitionEasing(from, to) {
|
|
191
|
+
const valenceDrop = from.valence - to.valence;
|
|
192
|
+
const arousalSpike = to.arousal - from.arousal;
|
|
193
|
+
if (valenceDrop > 0.3 && arousalSpike > 0.2) {
|
|
194
|
+
return "easeOut";
|
|
195
|
+
}
|
|
196
|
+
if (to.valence > from.valence && to.valence > 0.7) {
|
|
197
|
+
return "spring";
|
|
198
|
+
}
|
|
199
|
+
return "easeInOut";
|
|
200
|
+
}
|
|
201
|
+
function getTransitionConfig(from, to) {
|
|
202
|
+
return {
|
|
203
|
+
duration: getTransitionDuration(from, to),
|
|
204
|
+
easing: getTransitionEasing(from, to),
|
|
205
|
+
onComplete: () => {
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// src/emotion/micro-expressions.ts
|
|
211
|
+
function seededRandom(seed) {
|
|
212
|
+
let state = seed;
|
|
213
|
+
return () => {
|
|
214
|
+
state = state * 1103515245 + 12345 & 2147483647;
|
|
215
|
+
return state / 2147483647;
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
function createNoiseGenerator(seed = 42) {
|
|
219
|
+
const rand = seededRandom(seed);
|
|
220
|
+
const gradients = [];
|
|
221
|
+
for (let i = 0; i < 256; i++) {
|
|
222
|
+
gradients.push(rand() * 2 - 1);
|
|
223
|
+
}
|
|
224
|
+
const smoothstep = (t) => t * t * (3 - 2 * t);
|
|
225
|
+
return (t) => {
|
|
226
|
+
const i0 = Math.floor(t) & 255;
|
|
227
|
+
const i1 = i0 + 1 & 255;
|
|
228
|
+
const frac = t - Math.floor(t);
|
|
229
|
+
const g0 = gradients[i0];
|
|
230
|
+
const g1 = gradients[i1];
|
|
231
|
+
const d0 = g0 * frac;
|
|
232
|
+
const d1 = g1 * (frac - 1);
|
|
233
|
+
return smoothstep(frac) * (d1 - d0) + d0;
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
var arousalNoise = createNoiseGenerator(42);
|
|
237
|
+
var valenceNoise = createNoiseGenerator(137);
|
|
238
|
+
var opennessNoise = createNoiseGenerator(256);
|
|
239
|
+
function applyMicroExpression(base, config, time) {
|
|
240
|
+
if (!config.enabled) {
|
|
241
|
+
return base;
|
|
242
|
+
}
|
|
243
|
+
const t = time * config.frequency;
|
|
244
|
+
const noiseA = arousalNoise(t) * config.arousalNoise;
|
|
245
|
+
const noiseV = valenceNoise(t + 100) * config.valenceNoise;
|
|
246
|
+
const noiseO = opennessNoise(t + 200) * config.opennessNoise;
|
|
247
|
+
return {
|
|
248
|
+
arousal: Math.max(0, Math.min(1, base.arousal + noiseA)),
|
|
249
|
+
valence: Math.max(0, Math.min(1, base.valence + noiseV)),
|
|
250
|
+
openness: Math.max(0, Math.min(1, base.openness + noiseO))
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
function createMicroExpressionAnimator(config) {
|
|
254
|
+
let time = 0;
|
|
255
|
+
return {
|
|
256
|
+
tick(deltaMs) {
|
|
257
|
+
time += deltaMs / 1e3;
|
|
258
|
+
},
|
|
259
|
+
apply(base) {
|
|
260
|
+
return applyMicroExpression(base, config, time);
|
|
261
|
+
},
|
|
262
|
+
reset() {
|
|
263
|
+
time = 0;
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// src/emotion/controller.ts
|
|
269
|
+
var EmotionController = class {
|
|
270
|
+
_dimensions;
|
|
271
|
+
_transition = null;
|
|
272
|
+
_microConfig;
|
|
273
|
+
_time = 0;
|
|
274
|
+
_listeners = /* @__PURE__ */ new Map();
|
|
275
|
+
_disposed = false;
|
|
276
|
+
constructor(options = {}) {
|
|
277
|
+
if (options.initialAnchor) {
|
|
278
|
+
this._dimensions = { ...ANCHOR_STATES[options.initialAnchor] };
|
|
279
|
+
} else if (options.initial) {
|
|
280
|
+
this._dimensions = clampAVO(options.initial);
|
|
281
|
+
} else {
|
|
282
|
+
this._dimensions = { ...DEFAULT_AVO };
|
|
283
|
+
}
|
|
284
|
+
if (options.microExpressions === false) {
|
|
285
|
+
this._microConfig = { ...DEFAULT_MICRO_CONFIG, enabled: false };
|
|
286
|
+
} else if (typeof options.microExpressions === "object") {
|
|
287
|
+
this._microConfig = { ...DEFAULT_MICRO_CONFIG, ...options.microExpressions };
|
|
288
|
+
} else {
|
|
289
|
+
this._microConfig = { ...DEFAULT_MICRO_CONFIG };
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Get current base dimensions (without micro-expressions)
|
|
294
|
+
*/
|
|
295
|
+
getDimensions() {
|
|
296
|
+
return { ...this._dimensions };
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Get current dimensions with micro-expressions applied
|
|
300
|
+
*/
|
|
301
|
+
getAnimatedDimensions() {
|
|
302
|
+
return applyMicroExpression(this._dimensions, this._microConfig, this._time);
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Get computed visual state for rendering
|
|
306
|
+
*/
|
|
307
|
+
getVisualState() {
|
|
308
|
+
return computeVisualState(this.getAnimatedDimensions());
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Set dimensions immediately (no transition)
|
|
312
|
+
* Values are clamped to valid 0-1 range
|
|
313
|
+
*/
|
|
314
|
+
setDimensions(dims) {
|
|
315
|
+
this._dimensions = clampAVO({ ...this._dimensions, ...dims });
|
|
316
|
+
this._transition = null;
|
|
317
|
+
this._emit("change", this._dimensions);
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Transition to target dimensions over time
|
|
321
|
+
* Auto-calculates duration and easing if not specified
|
|
322
|
+
*/
|
|
323
|
+
transitionTo(target, options = {}) {
|
|
324
|
+
const from = { ...this._dimensions };
|
|
325
|
+
const to = clampAVO({ ...this._dimensions, ...target });
|
|
326
|
+
const autoConfig = getTransitionConfig(from, to);
|
|
327
|
+
this._transition = {
|
|
328
|
+
from,
|
|
329
|
+
to,
|
|
330
|
+
duration: options.duration ?? autoConfig.duration,
|
|
331
|
+
easing: options.easing ?? autoConfig.easing,
|
|
332
|
+
elapsed: 0,
|
|
333
|
+
onComplete: options.onComplete
|
|
334
|
+
};
|
|
335
|
+
this._emit("transitionStart", { from, to });
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Transition to a named anchor state
|
|
339
|
+
* Emits anchorReached when transition completes
|
|
340
|
+
*/
|
|
341
|
+
transitionToAnchor(anchor, options = {}) {
|
|
342
|
+
this.transitionTo(ANCHOR_STATES[anchor], {
|
|
343
|
+
...options,
|
|
344
|
+
onComplete: () => {
|
|
345
|
+
this._emit("anchorReached", anchor);
|
|
346
|
+
options.onComplete?.();
|
|
347
|
+
}
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Handle emotion events from agent behaviors
|
|
352
|
+
* Maps event types to appropriate anchor transitions
|
|
353
|
+
*/
|
|
354
|
+
handleEvent(event) {
|
|
355
|
+
const intensity = event.intensity ?? 0.5;
|
|
356
|
+
switch (event.type) {
|
|
357
|
+
case "input_received":
|
|
358
|
+
this.transitionToAnchor("listening");
|
|
359
|
+
break;
|
|
360
|
+
case "processing_start":
|
|
361
|
+
this.transitionToAnchor("thinking");
|
|
362
|
+
break;
|
|
363
|
+
case "processing_complete":
|
|
364
|
+
this.transitionToAnchor("responding");
|
|
365
|
+
break;
|
|
366
|
+
case "error_occurred":
|
|
367
|
+
this.transitionToAnchor(intensity > 0.7 ? "error" : "concerned");
|
|
368
|
+
break;
|
|
369
|
+
case "success":
|
|
370
|
+
this.transitionToAnchor(intensity > 0.7 ? "proud" : "satisfied");
|
|
371
|
+
break;
|
|
372
|
+
case "user_idle":
|
|
373
|
+
this.transitionToAnchor("idle", { duration: 2e3 });
|
|
374
|
+
break;
|
|
375
|
+
case "interrupt":
|
|
376
|
+
this.setDimensions({ arousal: Math.min(this._dimensions.arousal + 0.2, 1) });
|
|
377
|
+
break;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Blend toward target dimensions by a factor (0-1)
|
|
382
|
+
* Useful for continuous input-driven changes
|
|
383
|
+
*/
|
|
384
|
+
blendToward(target, factor) {
|
|
385
|
+
const to = clampAVO({ ...this._dimensions, ...target });
|
|
386
|
+
this._dimensions = blendAVO(this._dimensions, to, factor);
|
|
387
|
+
this._emit("change", this._dimensions);
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Check if currently transitioning
|
|
391
|
+
*/
|
|
392
|
+
isTransitioning() {
|
|
393
|
+
return this._transition !== null;
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Cancel current transition, keeping current position
|
|
397
|
+
*/
|
|
398
|
+
cancelTransition() {
|
|
399
|
+
this._transition = null;
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Subscribe to controller events
|
|
403
|
+
* Returns unsubscribe function
|
|
404
|
+
*/
|
|
405
|
+
on(event, handler) {
|
|
406
|
+
if (!this._listeners.has(event)) {
|
|
407
|
+
this._listeners.set(event, /* @__PURE__ */ new Set());
|
|
408
|
+
}
|
|
409
|
+
this._listeners.get(event).add(handler);
|
|
410
|
+
return () => {
|
|
411
|
+
this._listeners.get(event)?.delete(handler);
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* Update tick - call each frame with delta time in milliseconds
|
|
416
|
+
* Advances transitions and micro-expression time
|
|
417
|
+
*/
|
|
418
|
+
tick(deltaMs) {
|
|
419
|
+
if (this._disposed) return;
|
|
420
|
+
this._time += deltaMs / 1e3;
|
|
421
|
+
if (this._transition) {
|
|
422
|
+
this._transition.elapsed += deltaMs;
|
|
423
|
+
const progress = this._transition.duration <= 0 ? 1 : Math.min(this._transition.elapsed / this._transition.duration, 1);
|
|
424
|
+
const easedProgress = ease(this._transition.easing, progress);
|
|
425
|
+
this._dimensions = blendAVO(this._transition.from, this._transition.to, easedProgress);
|
|
426
|
+
this._emit("change", this._dimensions);
|
|
427
|
+
if (progress >= 1) {
|
|
428
|
+
const onComplete = this._transition.onComplete;
|
|
429
|
+
this._transition = null;
|
|
430
|
+
this._emit("transitionEnd", this._dimensions);
|
|
431
|
+
onComplete?.();
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* Dispose controller and clean up resources
|
|
437
|
+
*/
|
|
438
|
+
dispose() {
|
|
439
|
+
this._disposed = true;
|
|
440
|
+
this._listeners.clear();
|
|
441
|
+
this._transition = null;
|
|
442
|
+
}
|
|
443
|
+
_emit(event, data) {
|
|
444
|
+
this._listeners.get(event)?.forEach((handler) => handler(data));
|
|
445
|
+
}
|
|
446
|
+
};
|
|
447
|
+
|
|
448
|
+
// src/emotion/hooks/useEmotion.ts
|
|
449
|
+
import { useState, useEffect, useCallback, useRef } from "react";
|
|
450
|
+
function useEmotion(options = {}) {
|
|
451
|
+
const {
|
|
452
|
+
initial,
|
|
453
|
+
initialAnchor,
|
|
454
|
+
microExpressions = true,
|
|
455
|
+
onChange,
|
|
456
|
+
autoTick = true
|
|
457
|
+
} = options;
|
|
458
|
+
const controllerRef = useRef(null);
|
|
459
|
+
if (!controllerRef.current) {
|
|
460
|
+
controllerRef.current = new EmotionController({
|
|
461
|
+
initial,
|
|
462
|
+
initialAnchor,
|
|
463
|
+
microExpressions
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
const controller = controllerRef.current;
|
|
467
|
+
const [dimensions, setDimensions] = useState(controller.getAnimatedDimensions());
|
|
468
|
+
const [baseDimensions, setBaseDimensions] = useState(controller.getDimensions());
|
|
469
|
+
const [visualState, setVisualState] = useState(controller.getVisualState());
|
|
470
|
+
const [isTransitioning, setIsTransitioning] = useState(false);
|
|
471
|
+
const onChangeRef = useRef(onChange);
|
|
472
|
+
onChangeRef.current = onChange;
|
|
473
|
+
useEffect(() => {
|
|
474
|
+
const unsub = controller.on("change", (dims) => {
|
|
475
|
+
setBaseDimensions({ ...dims });
|
|
476
|
+
setDimensions(controller.getAnimatedDimensions());
|
|
477
|
+
setVisualState(controller.getVisualState());
|
|
478
|
+
onChangeRef.current?.(dims);
|
|
479
|
+
});
|
|
480
|
+
const unsubStart = controller.on("transitionStart", () => {
|
|
481
|
+
setIsTransitioning(true);
|
|
482
|
+
});
|
|
483
|
+
const unsubEnd = controller.on("transitionEnd", () => {
|
|
484
|
+
setIsTransitioning(false);
|
|
485
|
+
});
|
|
486
|
+
return () => {
|
|
487
|
+
unsub();
|
|
488
|
+
unsubStart();
|
|
489
|
+
unsubEnd();
|
|
490
|
+
};
|
|
491
|
+
}, [controller]);
|
|
492
|
+
useEffect(() => {
|
|
493
|
+
if (!autoTick) return;
|
|
494
|
+
let lastTime = performance.now();
|
|
495
|
+
let rafId;
|
|
496
|
+
const tick2 = (time) => {
|
|
497
|
+
const delta = time - lastTime;
|
|
498
|
+
lastTime = time;
|
|
499
|
+
controller.tick(delta);
|
|
500
|
+
setDimensions(controller.getAnimatedDimensions());
|
|
501
|
+
setVisualState(controller.getVisualState());
|
|
502
|
+
rafId = requestAnimationFrame(tick2);
|
|
503
|
+
};
|
|
504
|
+
rafId = requestAnimationFrame(tick2);
|
|
505
|
+
return () => {
|
|
506
|
+
cancelAnimationFrame(rafId);
|
|
507
|
+
};
|
|
508
|
+
}, [controller, autoTick]);
|
|
509
|
+
useEffect(() => {
|
|
510
|
+
return () => {
|
|
511
|
+
controller.dispose();
|
|
512
|
+
};
|
|
513
|
+
}, [controller]);
|
|
514
|
+
const set = useCallback(
|
|
515
|
+
(dims) => {
|
|
516
|
+
controller.setDimensions(dims);
|
|
517
|
+
},
|
|
518
|
+
[controller]
|
|
519
|
+
);
|
|
520
|
+
const transition = useCallback(
|
|
521
|
+
(dims, opts) => {
|
|
522
|
+
controller.transitionTo(dims, opts);
|
|
523
|
+
},
|
|
524
|
+
[controller]
|
|
525
|
+
);
|
|
526
|
+
const goTo = useCallback(
|
|
527
|
+
(anchor, opts) => {
|
|
528
|
+
controller.transitionToAnchor(anchor, opts);
|
|
529
|
+
},
|
|
530
|
+
[controller]
|
|
531
|
+
);
|
|
532
|
+
const emit = useCallback(
|
|
533
|
+
(event) => {
|
|
534
|
+
controller.handleEvent(event);
|
|
535
|
+
},
|
|
536
|
+
[controller]
|
|
537
|
+
);
|
|
538
|
+
const tick = useCallback(
|
|
539
|
+
(deltaMs) => {
|
|
540
|
+
controller.tick(deltaMs);
|
|
541
|
+
},
|
|
542
|
+
[controller]
|
|
543
|
+
);
|
|
544
|
+
return {
|
|
545
|
+
dimensions,
|
|
546
|
+
baseDimensions,
|
|
547
|
+
visualState,
|
|
548
|
+
set,
|
|
549
|
+
transition,
|
|
550
|
+
goTo,
|
|
551
|
+
emit,
|
|
552
|
+
isTransitioning,
|
|
553
|
+
tick
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
export {
|
|
558
|
+
isValidAVO,
|
|
559
|
+
clampAVO,
|
|
560
|
+
ANCHOR_STATES,
|
|
561
|
+
LEGACY_STATE_MAP,
|
|
562
|
+
DEFAULT_MICRO_CONFIG,
|
|
563
|
+
DEFAULT_TRANSITION_DURATIONS,
|
|
564
|
+
DEFAULT_AVO,
|
|
565
|
+
lerp,
|
|
566
|
+
mapArousal,
|
|
567
|
+
mapValence,
|
|
568
|
+
mapOpenness,
|
|
569
|
+
computeVisualState,
|
|
570
|
+
avoDistance,
|
|
571
|
+
blendAVO,
|
|
572
|
+
getAnimationWeights,
|
|
573
|
+
ease,
|
|
574
|
+
getTransitionDuration,
|
|
575
|
+
getTransitionEasing,
|
|
576
|
+
getTransitionConfig,
|
|
577
|
+
createNoiseGenerator,
|
|
578
|
+
applyMicroExpression,
|
|
579
|
+
createMicroExpressionAnimator,
|
|
580
|
+
EmotionController,
|
|
581
|
+
useEmotion
|
|
582
|
+
};
|
|
583
|
+
//# sourceMappingURL=chunk-VU2XK2NI.js.map
|