@bod.ee/ai-avatar 1.0.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
+ "use strict";var L=Object.defineProperty;var O=(r,t,e)=>t in r?L(r,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):r[t]=e;var a=(r,t,e)=>O(r,typeof t!="symbol"?t+"":t,e);const y=require("react");class W{constructor(){a(this,"events",new Map)}on(t,e){return this.events.has(t)||this.events.set(t,[]),this.events.get(t).push(e),this}off(t,e){const i=this.events.get(t);if(i){const s=i.indexOf(e);s!==-1&&i.splice(s,1)}return this}emit(t,...e){const i=this.events.get(t);return i?(i.forEach(s=>s(...e)),!0):!1}removeAllListeners(t){return t?this.events.delete(t):this.events.clear(),this}}const S={normal:1,energized:.6,tired:1.8},Y={neutral:{id:"neutral",name:"Neutral",state:{eyes:{scaleY:1,scaleX:1,position:{x:0,y:0}},mouth:{shape:"closed"}},transitionDuration:150,easing:"cubic-bezier(0.34, 1.56, 0.64, 1)"},blink:{id:"blink",name:"Blink",state:{eyes:{scaleY:.08,scaleX:1.05,position:{x:0,y:0}},mouth:{shape:"closed"}},transitionDuration:80,easing:"ease-out"},squintLight:{id:"squintLight",name:"Light Squint",state:{eyes:{scaleY:.7,scaleX:1,position:{x:0,y:.05}},mouth:{shape:"closed"}},transitionDuration:200,easing:"ease-in-out"},squintMedium:{id:"squintMedium",name:"Medium Squint",state:{eyes:{scaleY:.4,scaleX:1,position:{x:0,y:.08}},mouth:{shape:"closed"}},transitionDuration:200,easing:"ease-in-out"},squint:{id:"squint",name:"Squint",state:{eyes:{scaleY:.15,scaleX:1.02,position:{x:0,y:.1}},mouth:{shape:"closed"}},transitionDuration:200,easing:"ease-in-out"},squintDeep:{id:"squintDeep",name:"Deep Squint",state:{eyes:{scaleY:.08,scaleX:1.05,position:{x:0,y:.12}},mouth:{shape:"closed"}},transitionDuration:200,easing:"ease-in-out"},happy:{id:"happy",name:"Happy",state:{eyes:{scaleY:.6,scaleX:1.05,position:{x:0,y:.05}},mouth:{shape:"smile",openness:.6}},transitionDuration:100,easing:"cubic-bezier(0.34, 1.56, 0.64, 1)"},happySmall:{id:"happySmall",name:"Happy (Small)",state:{eyes:{scaleY:.75,scaleX:1.02,position:{x:0,y:.03}},mouth:{shape:"smile",openness:.4}},transitionDuration:100,easing:"cubic-bezier(0.34, 1.56, 0.64, 1)"},happyBig:{id:"happyBig",name:"Happy (Big)",state:{eyes:{scaleY:.5,scaleX:1.08,position:{x:0,y:.06}},mouth:{shape:"smile",openness:.9}},transitionDuration:100,easing:"cubic-bezier(0.34, 1.56, 0.64, 1)"},talking1:{id:"talking1",name:"Talking 1",state:{eyes:{scaleY:1,scaleX:1,position:{x:-.02,y:0}},mouth:{shape:"neutral",openness:.4}},transitionDuration:60,easing:"ease-out"},talking2:{id:"talking2",name:"Talking 2",state:{eyes:{scaleY:1,scaleX:1,position:{x:.02,y:-.02}},mouth:{shape:"open",openness:.6}},transitionDuration:60,easing:"ease-out"},talking3:{id:"talking3",name:"Talking 3",state:{eyes:{scaleY:1,scaleX:1,position:{x:0,y:-.03}},mouth:{shape:"open",openness:.8}},transitionDuration:60,easing:"ease-out"},surprised:{id:"surprised",name:"Surprised",state:{eyes:{scaleY:1.5,scaleX:1.4,position:{x:0,y:-.2}},mouth:{shape:"O",openness:1.1},face:{x:0,y:-.4,tilt:0}},transitionDuration:60,easing:"cubic-bezier(0.68, -0.55, 0.265, 1.55)"},focused:{id:"focused",name:"Focused",state:{eyes:{scaleY:.65,scaleX:1.05,position:{x:0,y:.08}},mouth:{shape:"closed"},face:{x:0,y:.1,tilt:-2}},transitionDuration:300,easing:"ease-in-out"},tired:{id:"tired",name:"Tired",state:{eyes:{scaleY:.5,scaleX:1,position:{x:0,y:.15}},mouth:{shape:"closed"}},transitionDuration:400,easing:"ease-out"},sleepy:{id:"sleepy",name:"Sleepy",state:{eyes:{scaleY:.25,scaleX:1,position:{x:0,y:.2}},mouth:{shape:"closed"}},transitionDuration:500,easing:"ease-out"},cheerful:{id:"cheerful",name:"Cheerful",state:{eyes:{scaleY:.5,scaleX:1.05,position:{x:0,y:.05}},mouth:{shape:"smile",openness:.8},face:{x:0,y:-.1,tilt:4}},transitionDuration:150,easing:"cubic-bezier(0.34, 1.56, 0.64, 1)"},straining:{id:"straining",name:"Straining",state:{eyes:{scaleY:.12,scaleX:1.05,position:{x:0,y:.1}},mouth:{shape:"closed"}},transitionDuration:250,easing:"ease-in"},lookLeft:{id:"lookLeft",name:"Look Left",state:{eyes:{scaleY:1,scaleX:1,position:{x:-.3,y:0}},mouth:{shape:"closed"}},transitionDuration:150,easing:"ease-out"},lookRight:{id:"lookRight",name:"Look Right",state:{eyes:{scaleY:1,scaleX:1,position:{x:.3,y:0}},mouth:{shape:"closed"}},transitionDuration:150,easing:"ease-out"},lookUp:{id:"lookUp",name:"Look Up",state:{eyes:{scaleY:1.05,scaleX:1,position:{x:0,y:-.25}},mouth:{shape:"closed"}},transitionDuration:150,easing:"ease-out"},lookDown:{id:"lookDown",name:"Look Down",state:{eyes:{scaleY:.9,scaleX:1,position:{x:0,y:.2}},mouth:{shape:"closed"}},transitionDuration:150,easing:"ease-out"},curious:{id:"curious",name:"Curious",state:{eyes:{scaleY:1.2,scaleX:1.1,position:{x:.25,y:-.15}},mouth:{shape:"neutral",openness:.4},face:{x:.35,y:-.2,tilt:15}},transitionDuration:200,easing:"cubic-bezier(0.34, 1.56, 0.64, 1)"},skeptical:{id:"skeptical",name:"Skeptical",state:{eyes:{scaleY:.75,scaleX:1,position:{x:.15,y:.05}},mouth:{shape:"closed"},face:{x:-.1,y:.05,tilt:-5}},transitionDuration:250,easing:"ease-in-out"},excited:{id:"excited",name:"Excited",state:{eyes:{scaleY:1.4,scaleX:1.3,position:{x:0,y:-.25}},mouth:{shape:"smile",openness:1.2},face:{x:0,y:-.35,tilt:0}},transitionDuration:80,easing:"cubic-bezier(0.68, -0.55, 0.265, 1.55)"},shy:{id:"shy",name:"Shy",state:{eyes:{scaleY:.7,scaleX:.85,position:{x:-.4,y:.25}},mouth:{shape:"smile",openness:.3},face:{x:-.45,y:.25,tilt:-18}},transitionDuration:300,easing:"ease-out"},wink:{id:"wink",name:"Wink",state:{eyes:{scaleY:.5,leftScaleY:.06,rightScaleY:.5,position:{x:.1,y:0}},mouth:{shape:"smile",openness:.5},face:{x:.1,y:-.05,tilt:5}},transitionDuration:100,easing:"ease-out"},"talking-A":{id:"talking-A",name:"Talking (A)",state:{eyes:{scaleY:1,scaleX:1,position:{x:0,y:0}},mouth:{shape:"A",openness:.7}},transitionDuration:60,easing:"ease-in-out"},"talking-E":{id:"talking-E",name:"Talking (E)",state:{eyes:{scaleY:1,scaleX:1,position:{x:0,y:0}},mouth:{shape:"E",openness:.5}},transitionDuration:60,easing:"ease-in-out"},"talking-I":{id:"talking-I",name:"Talking (I)",state:{eyes:{scaleY:1,scaleX:1,position:{x:0,y:0}},mouth:{shape:"I",openness:.4}},transitionDuration:60,easing:"ease-in-out"},"talking-O":{id:"talking-O",name:"Talking (O)",state:{eyes:{scaleY:1,scaleX:1,position:{x:0,y:0}},mouth:{shape:"O",openness:.8}},transitionDuration:60,easing:"ease-in-out"},"talking-U":{id:"talking-U",name:"Talking (U)",state:{eyes:{scaleY:1,scaleX:1,position:{x:0,y:0}},mouth:{shape:"U",openness:.6}},transitionDuration:60,easing:"ease-in-out"},"talking-M":{id:"talking-M",name:"Talking (M)",state:{eyes:{scaleY:1,scaleX:1,position:{x:0,y:0}},mouth:{shape:"M"}},transitionDuration:60,easing:"ease-in-out"},"talking-F":{id:"talking-F",name:"Talking (F)",state:{eyes:{scaleY:1,scaleX:1,position:{x:0,y:0}},mouth:{shape:"F",openness:.3}},transitionDuration:60,easing:"ease-in-out"},"talking-W":{id:"talking-W",name:"Talking (W)",state:{eyes:{scaleY:1,scaleX:1,position:{x:0,y:0}},mouth:{shape:"W",openness:.5}},transitionDuration:60,easing:"ease-in-out"},hyper:{id:"hyper",name:"Hyper",state:{eyes:{scaleY:1.6,scaleX:1.5,position:{x:.3,y:-.3}},mouth:{shape:"smile",openness:1.5},face:{x:.4,y:-.5,tilt:12}},transitionDuration:60,easing:"cubic-bezier(0.68, -0.55, 0.265, 1.55)"},shocked:{id:"shocked",name:"Shocked",state:{eyes:{scaleY:1.3,scaleX:1.2,position:{x:0,y:-.2}},mouth:{shape:"O",openness:1},face:{x:0,y:-.3,tilt:0}},transitionDuration:40,easing:"cubic-bezier(0.68, -0.55, 0.265, 1.55)"},crazy:{id:"crazy",name:"Crazy",state:{eyes:{scaleY:1.5,scaleX:1.4,position:{x:.5,y:-.2}},mouth:{shape:"open",openness:1.3},face:{x:.5,y:-.3,tilt:20}},transitionDuration:50,easing:"cubic-bezier(0.68, -0.55, 0.265, 1.55)"},sneaky:{id:"sneaky",name:"Sneaky",state:{eyes:{scaleY:.4,scaleX:.9,position:{x:.4,y:.15}},mouth:{shape:"smile",openness:.5},face:{x:.3,y:.2,tilt:-12}},transitionDuration:200,easing:"ease-in-out"},listening:{id:"listening",name:"Listening",state:{eyes:{scaleY:1,leftScaleY:.85,rightScaleY:1.2,position:{x:.08,y:-.05}},mouth:{shape:"closed"},face:{x:.12,y:-.08,tilt:6}},transitionDuration:250,easing:"ease-in-out"},dramatic:{id:"dramatic",name:"Dramatic",state:{eyes:{scaleY:1.3,scaleX:1.2,position:{x:-.3,y:-.2}},mouth:{shape:"O",openness:1},face:{x:-.4,y:-.3,tilt:-15}},transitionDuration:150,easing:"cubic-bezier(0.34, 1.56, 0.64, 1)"},flirty:{id:"flirty",name:"Flirty",state:{eyes:{scaleY:.55,scaleX:1.05,leftScaleY:.08,rightScaleY:.55,position:{x:.15,y:.05}},mouth:{shape:"smile",openness:.5},face:{x:.15,y:-.1,tilt:8}},transitionDuration:200,easing:"cubic-bezier(0.34, 1.56, 0.64, 1)"},sassy:{id:"sassy",name:"Sassy",state:{eyes:{scaleY:.45,scaleX:1,leftScaleY:.7,rightScaleY:.25,position:{x:-.1,y:.08}},mouth:{shape:"smile",openness:.4},face:{x:-.2,y:.1,tilt:-10}},transitionDuration:180,easing:"ease-in-out"},smug:{id:"smug",name:"Smug",state:{eyes:{scaleY:.6,scaleX:.95,position:{x:.2,y:.08}},mouth:{shape:"smile",openness:.35},face:{x:.15,y:.15,tilt:-7}},transitionDuration:250,easing:"ease-in-out"},pouty:{id:"pouty",name:"Pouty",state:{eyes:{scaleY:1.1,scaleX:1.05,position:{x:0,y:-.1}},mouth:{shape:"U",openness:.5},face:{x:0,y:-.15,tilt:3}},transitionDuration:200,easing:"ease-out"}},T=Object.values(Y),D=r=>Y[r],P=()=>Y.neutral.state,q={demoLoop:{id:"demoLoop",name:"Demo Loop",loop:!0,frames:[{expression:"neutral",duration:2500,transitionDuration:0},{expression:"squintLight",duration:500,transitionDuration:300},{expression:"squintMedium",duration:600,transitionDuration:300},{expression:"squint",duration:800,transitionDuration:300},{expression:"squintDeep",duration:1300,transitionDuration:400},{expression:"happySmall",duration:800,transitionDuration:150},{expression:"happy",duration:1e3,transitionDuration:200},{expression:"happyBig",duration:1200,transitionDuration:200},{expression:"neutral",duration:500,transitionDuration:50},{expression:"squintLight",duration:700,transitionDuration:400},{expression:"squintMedium",duration:900,transitionDuration:400},{expression:"squint",duration:1200,transitionDuration:400},{expression:"squintDeep",duration:2700,transitionDuration:500},{expression:"happySmall",duration:1e3,transitionDuration:200},{expression:"happy",duration:1500,transitionDuration:250},{expression:"happyBig",duration:2e3,transitionDuration:300}]},blink:{id:"blink",name:"Blink",loop:!1,frames:[{expression:"blink",duration:80,transitionDuration:60},{expression:"neutral",duration:0,transitionDuration:80}]},doubleBlink:{id:"doubleBlink",name:"Double Blink",loop:!1,frames:[{expression:"blink",duration:80,transitionDuration:60},{expression:"neutral",duration:150,transitionDuration:80},{expression:"blink",duration:80,transitionDuration:60},{expression:"neutral",duration:0,transitionDuration:80}]},slowBlink:{id:"slowBlink",name:"Slow Blink",loop:!1,frames:[{expression:"tired",duration:200,transitionDuration:200},{expression:"sleepy",duration:300,transitionDuration:200},{expression:"blink",duration:200,transitionDuration:150},{expression:"sleepy",duration:200,transitionDuration:200},{expression:"neutral",duration:0,transitionDuration:400}]},wakeUp:{id:"wakeUp",name:"Wake Up",loop:!1,frames:[{expression:"blink",duration:500,transitionDuration:0},{expression:"sleepy",duration:400,transitionDuration:300},{expression:"tired",duration:400,transitionDuration:300},{expression:"squintLight",duration:300,transitionDuration:200},{expression:"neutral",duration:0,transitionDuration:200}]},surprised:{id:"surprised",name:"Surprised",loop:!1,frames:[{expression:"surprised",duration:800,transitionDuration:80},{expression:"neutral",duration:0,transitionDuration:300}]},thinking:{id:"thinking",name:"Thinking",loop:!1,frames:[{expression:"focused",duration:600,transitionDuration:200},{expression:"squintLight",duration:400,transitionDuration:200},{expression:"focused",duration:600,transitionDuration:200},{expression:"neutral",duration:0,transitionDuration:200}]},greeting:{id:"greeting",name:"Greeting",loop:!1,frames:[{expression:"blink",duration:100,transitionDuration:80},{expression:"happy",duration:1500,transitionDuration:100},{expression:"neutral",duration:0,transitionDuration:200}]},talking:{id:"talking",name:"Talking",loop:!0,frames:[{expression:"talking1",duration:80,transitionDuration:50},{expression:"talking2",duration:100,transitionDuration:50},{expression:"talking3",duration:100,transitionDuration:50},{expression:"talking2",duration:80,transitionDuration:50},{expression:"talking1",duration:60,transitionDuration:50},{expression:"happy",duration:120,transitionDuration:50}]},wink:{id:"wink",name:"Wink",loop:!1,frames:[{expression:"wink",duration:120,transitionDuration:80},{expression:"happySmall",duration:400,transitionDuration:100},{expression:"neutral",duration:0,transitionDuration:200}]},flirty:{id:"flirty",name:"Flirty",loop:!1,frames:[{state:{eyes:{scaleY:1.4,scaleX:1.2,position:{x:0,y:-.2}},mouth:{shape:"smile",openness:.3},face:{x:.1,y:-.25,tilt:5}},duration:160,transitionDuration:80},{state:{eyes:{scaleY:.9,scaleX:1,position:{x:0,y:0}},mouth:{shape:"closed"},face:{x:0,y:0,tilt:0}},duration:120,transitionDuration:100},{state:{eyes:{scaleY:1.5,scaleX:1.25,position:{x:0,y:-.22}},mouth:{shape:"smile",openness:.4},face:{x:.15,y:-.3,tilt:7}},duration:180,transitionDuration:80},{expression:"smug",duration:600,transitionDuration:200},{expression:"neutral",duration:0,transitionDuration:300}]},idle:{id:"idle",name:"Idle",loop:!0,frames:[{expression:"neutral",duration:3e3,transitionDuration:0},{expression:"blink",duration:80,transitionDuration:60},{expression:"neutral",duration:4e3,transitionDuration:80},{expression:"focused",duration:800,transitionDuration:300},{expression:"neutral",duration:3500,transitionDuration:200},{expression:"blink",duration:80,transitionDuration:60},{expression:"neutral",duration:2500,transitionDuration:80},{expression:"blink",duration:80,transitionDuration:60},{expression:"neutral",duration:200,transitionDuration:80},{expression:"blink",duration:80,transitionDuration:60},{expression:"neutral",duration:5e3,transitionDuration:80}]},cheerful:{id:"cheerful",name:"Cheerful",loop:!1,frames:[{expression:"blink",duration:100,transitionDuration:80},{expression:"cheerful",duration:2e3,transitionDuration:100},{expression:"happy",duration:500,transitionDuration:150},{expression:"neutral",duration:0,transitionDuration:200}]},glitchMood:{id:"glitchMood",name:"Glitch Mood",loop:!1,frames:[{expression:"neutral",duration:50,transitionDuration:0},{expression:"surprised",duration:40,transitionDuration:20},{expression:"blink",duration:30,transitionDuration:10},{expression:"squint",duration:50,transitionDuration:20},{expression:"happy",duration:40,transitionDuration:15},{expression:"neutral",duration:30,transitionDuration:10},{expression:"excited",duration:60,transitionDuration:20},{expression:"blink",duration:40,transitionDuration:15},{expression:"cheerful",duration:800,transitionDuration:50},{expression:"neutral",duration:0,transitionDuration:150}]},listening:{id:"listening",name:"Listening",loop:!0,frames:[{expression:"listening",duration:1800,transitionDuration:250},{state:{eyes:{scaleY:1,leftScaleY:.8,rightScaleY:1.15,position:{x:.08,y:.1}},mouth:{shape:"closed"},face:{x:.12,y:.12,tilt:8}},duration:200,transitionDuration:120},{expression:"listening",duration:1400,transitionDuration:150},{state:{eyes:{scaleY:.08,scaleX:1.05},mouth:{shape:"closed"},face:{x:.12,y:-.08,tilt:6}},duration:80,transitionDuration:60},{expression:"listening",duration:2e3,transitionDuration:100},{state:{eyes:{scaleY:1,leftScaleY:1.1,rightScaleY:.9,position:{x:-.05,y:-.03}},mouth:{shape:"closed"},face:{x:-.08,y:-.05,tilt:-4}},duration:1200,transitionDuration:300},{state:{eyes:{scaleY:1,leftScaleY:.85,rightScaleY:1.15,position:{x:.06,y:.08}},mouth:{shape:"closed"},face:{x:.1,y:.1,tilt:7}},duration:180,transitionDuration:100},{expression:"listening",duration:1600,transitionDuration:200},{state:{eyes:{scaleY:.08,scaleX:1.05},mouth:{shape:"closed"},face:{x:.12,y:-.08,tilt:6}},duration:80,transitionDuration:60},{expression:"listening",duration:1500,transitionDuration:100}]},curiousScan:{id:"curiousScan",name:"Curious Scan",loop:!1,frames:[{expression:"curious",duration:400,transitionDuration:150},{expression:"lookLeft",duration:600,transitionDuration:200},{expression:"neutral",duration:200,transitionDuration:100},{expression:"lookRight",duration:600,transitionDuration:200},{expression:"curious",duration:300,transitionDuration:100},{expression:"lookUp",duration:400,transitionDuration:150},{expression:"neutral",duration:0,transitionDuration:200}]},shyReaction:{id:"shyReaction",name:"Shy Reaction",loop:!1,frames:[{expression:"surprised",duration:150,transitionDuration:50},{expression:"shy",duration:1500,transitionDuration:200},{expression:"blink",duration:80,transitionDuration:60},{expression:"happySmall",duration:800,transitionDuration:150},{expression:"neutral",duration:0,transitionDuration:200}]},winkSequence:{id:"winkSequence",name:"Wink",loop:!1,frames:[{expression:"wink",duration:300,transitionDuration:60},{expression:"happySmall",duration:400,transitionDuration:80},{expression:"neutral",duration:0,transitionDuration:150}]},digitalAwaken:{id:"digitalAwaken",name:"Digital Awaken",loop:!1,frames:[{expression:"blink",duration:200,transitionDuration:0},{expression:"sleepy",duration:100,transitionDuration:50},{expression:"blink",duration:50,transitionDuration:30},{expression:"tired",duration:80,transitionDuration:40},{expression:"blink",duration:40,transitionDuration:20},{expression:"squintLight",duration:60,transitionDuration:30},{expression:"surprised",duration:150,transitionDuration:40},{expression:"curious",duration:400,transitionDuration:100},{expression:"happy",duration:600,transitionDuration:80},{expression:"neutral",duration:0,transitionDuration:150}]},headShakeNo:{id:"headShakeNo",name:"Head Shake No",loop:!1,frames:[{state:{eyes:{scaleY:1,position:{x:.08,y:0}},mouth:{shape:"closed"},face:{x:.1,y:0,tilt:2}},duration:60,transitionDuration:50},{state:{eyes:{scaleY:1,position:{x:-.55,y:0}},mouth:{shape:"closed"},face:{x:-.65,y:.03,tilt:-16}},duration:110,transitionDuration:85},{state:{eyes:{scaleY:1,position:{x:.6,y:0}},mouth:{shape:"closed"},face:{x:.7,y:.03,tilt:18}},duration:120,transitionDuration:100},{state:{eyes:{scaleY:1,position:{x:-.5,y:0}},mouth:{shape:"closed"},face:{x:-.6,y:.02,tilt:-15}},duration:110,transitionDuration:95},{state:{eyes:{scaleY:1,position:{x:.45,y:0}},mouth:{shape:"closed"},face:{x:.55,y:.02,tilt:14}},duration:105,transitionDuration:90},{state:{eyes:{scaleY:1,position:{x:-.3,y:0}},mouth:{shape:"closed"},face:{x:-.35,y:0,tilt:-9}},duration:95,transitionDuration:85},{state:{eyes:{scaleY:1,position:{x:.12,y:0}},mouth:{shape:"closed"},face:{x:.15,y:0,tilt:4}},duration:85,transitionDuration:80},{state:{eyes:{scaleY:1,position:{x:-.03,y:0}},mouth:{shape:"closed"},face:{x:-.04,y:0,tilt:-1}},duration:70,transitionDuration:90},{state:{eyes:{scaleY:1,position:{x:0,y:0}},mouth:{shape:"closed"},face:{x:0,y:0,tilt:0}},duration:0,transitionDuration:100}]},headNodYes:{id:"headNodYes",name:"Head Nod Yes",loop:!1,frames:[{state:{eyes:{scaleY:1.08,position:{x:0,y:-.12}},mouth:{shape:"closed"},face:{x:0,y:-.18,tilt:-5}},duration:90,transitionDuration:75},{state:{eyes:{scaleY:.8,scaleX:1.08,position:{x:0,y:.35}},mouth:{shape:"closed"},face:{x:0,y:.55,tilt:14}},duration:130,transitionDuration:95},{state:{eyes:{scaleY:1.05,position:{x:0,y:-.08}},mouth:{shape:"closed"},face:{x:0,y:-.12,tilt:-3}},duration:90,transitionDuration:75},{state:{eyes:{scaleY:.82,scaleX:1.06,position:{x:0,y:.32}},mouth:{shape:"closed"},face:{x:0,y:.5,tilt:13}},duration:120,transitionDuration:90},{state:{eyes:{scaleY:1.03,position:{x:0,y:-.05}},mouth:{shape:"closed"},face:{x:0,y:-.08,tilt:-2}},duration:80,transitionDuration:70},{state:{eyes:{scaleY:.88,scaleX:1.04,position:{x:0,y:.22}},mouth:{shape:"closed"},face:{x:0,y:.35,tilt:9}},duration:110,transitionDuration:85},{state:{eyes:{scaleY:1.01,position:{x:0,y:-.02}},mouth:{shape:"closed"},face:{x:0,y:-.03,tilt:-1}},duration:75,transitionDuration:65},{state:{eyes:{scaleY:.98,position:{x:0,y:.03}},mouth:{shape:"closed"},face:{x:0,y:.04,tilt:1}},duration:70,transitionDuration:80},{state:{eyes:{scaleY:1,position:{x:0,y:0}},mouth:{shape:"closed"},face:{x:0,y:0,tilt:0}},duration:0,transitionDuration:100}]},quickNod:{id:"quickNod",name:"Quick Nod",loop:!1,frames:[{state:{eyes:{scaleY:.85,scaleX:1.06,position:{x:0,y:.3}},mouth:{shape:"closed"},face:{x:0,y:.45,tilt:12}},duration:100,transitionDuration:70},{state:{eyes:{scaleY:1,position:{x:0,y:0}},mouth:{shape:"closed"},face:{x:0,y:0,tilt:0}},duration:0,transitionDuration:100}]},strongNo:{id:"strongNo",name:"Strong No",loop:!1,frames:[{state:{eyes:{scaleY:1,position:{x:.1,y:0}},mouth:{shape:"closed"},face:{x:.12,y:0,tilt:3}},duration:60,transitionDuration:50},{state:{eyes:{scaleY:1,position:{x:-.7,y:0}},mouth:{shape:"closed"},face:{x:-.8,y:.05,tilt:-20}},duration:130,transitionDuration:90},{state:{eyes:{scaleY:1,position:{x:.5,y:0}},mouth:{shape:"closed"},face:{x:.6,y:.03,tilt:15}},duration:120,transitionDuration:100},{state:{eyes:{scaleY:1,position:{x:-.15,y:0}},mouth:{shape:"closed"},face:{x:-.18,y:0,tilt:-5}},duration:90,transitionDuration:95},{state:{eyes:{scaleY:1,position:{x:0,y:0}},mouth:{shape:"closed"},face:{x:0,y:0,tilt:0}},duration:0,transitionDuration:110}]},headTiltConfused:{id:"headTiltConfused",name:"Head Tilt Confused",loop:!1,frames:[{state:{eyes:{scaleY:1.1,position:{x:.2,y:-.1}},mouth:{shape:"neutral",openness:.3},face:{x:.15,y:-.1,tilt:18}},duration:300,transitionDuration:150},{state:{eyes:{scaleY:1.05,position:{x:0,y:0}},mouth:{shape:"neutral",openness:.3},face:{x:0,y:0,tilt:0}},duration:200,transitionDuration:120},{state:{eyes:{scaleY:1.1,position:{x:-.2,y:-.1}},mouth:{shape:"neutral",openness:.3},face:{x:-.15,y:-.1,tilt:-18}},duration:300,transitionDuration:150},{state:{eyes:{scaleY:1.05,position:{x:0,y:0}},mouth:{shape:"neutral",openness:.3},face:{x:0,y:0,tilt:0}},duration:200,transitionDuration:120},{state:{eyes:{scaleY:1.1,position:{x:.15,y:-.1}},mouth:{shape:"neutral",openness:.4},face:{x:.1,y:-.05,tilt:12}},duration:250,transitionDuration:130},{state:{eyes:{scaleY:1,position:{x:0,y:0}},mouth:{shape:"closed"},face:{x:0,y:0,tilt:0}},duration:0,transitionDuration:180}]},lookAroundScan:{id:"lookAroundScan",name:"Look Around Scan",loop:!1,frames:[{state:{eyes:{scaleY:1.05,position:{x:0,y:0}},mouth:{shape:"closed"},face:{x:0,y:0,tilt:0}},duration:150,transitionDuration:0},{state:{eyes:{scaleY:1.05,position:{x:.5,y:0}},mouth:{shape:"closed"},face:{x:.6,y:.05,tilt:10}},duration:400,transitionDuration:250},{state:{eyes:{scaleY:.9,position:{x:.4,y:.3}},mouth:{shape:"closed"},face:{x:.5,y:.35,tilt:8}},duration:350,transitionDuration:220},{state:{eyes:{scaleY:.85,position:{x:0,y:.4}},mouth:{shape:"closed"},face:{x:0,y:.45,tilt:5}},duration:350,transitionDuration:200},{state:{eyes:{scaleY:.9,position:{x:-.4,y:.3}},mouth:{shape:"closed"},face:{x:-.5,y:.35,tilt:-8}},duration:350,transitionDuration:220},{state:{eyes:{scaleY:1.05,position:{x:-.5,y:0}},mouth:{shape:"closed"},face:{x:-.6,y:.05,tilt:-10}},duration:400,transitionDuration:250},{state:{eyes:{scaleY:1.15,position:{x:-.3,y:-.3}},mouth:{shape:"closed"},face:{x:-.35,y:-.35,tilt:-6}},duration:350,transitionDuration:220},{state:{eyes:{scaleY:1.2,position:{x:0,y:-.4}},mouth:{shape:"closed"},face:{x:0,y:-.45,tilt:0}},duration:350,transitionDuration:200},{state:{eyes:{scaleY:1.15,position:{x:.3,y:-.3}},mouth:{shape:"closed"},face:{x:.35,y:-.35,tilt:6}},duration:350,transitionDuration:220},{state:{eyes:{scaleY:1,position:{x:0,y:0}},mouth:{shape:"closed"},face:{x:0,y:0,tilt:0}},duration:0,transitionDuration:300}]},excitedBounce:{id:"excitedBounce",name:"Excited Bounce",loop:!1,frames:[{state:{eyes:{scaleY:1.4,position:{x:0,y:-.3}},mouth:{shape:"smile",openness:1.2},face:{x:0,y:-.7,tilt:0}},duration:100,transitionDuration:60},{state:{eyes:{scaleY:.9,position:{x:0,y:.15}},mouth:{shape:"smile",openness:1},face:{x:0,y:.25,tilt:0}},duration:90,transitionDuration:70},{state:{eyes:{scaleY:1.3,position:{x:0,y:-.25}},mouth:{shape:"smile",openness:1.1},face:{x:0,y:-.55,tilt:0}},duration:85,transitionDuration:55},{state:{eyes:{scaleY:.95,position:{x:0,y:.1}},mouth:{shape:"smile",openness:.9},face:{x:0,y:.18,tilt:0}},duration:80,transitionDuration:60},{state:{eyes:{scaleY:1.2,position:{x:0,y:-.15}},mouth:{shape:"smile",openness:1},face:{x:0,y:-.35,tilt:0}},duration:75,transitionDuration:50},{state:{eyes:{scaleY:1,position:{x:0,y:.05}},mouth:{shape:"smile",openness:.85},face:{x:0,y:.1,tilt:0}},duration:70,transitionDuration:55},{state:{eyes:{scaleY:1.1,position:{x:0,y:-.05}},mouth:{shape:"smile",openness:.9},face:{x:0,y:-.1,tilt:0}},duration:150,transitionDuration:100},{state:{eyes:{scaleY:1,position:{x:0,y:0}},mouth:{shape:"closed"},face:{x:0,y:0,tilt:0}},duration:0,transitionDuration:150}]},leanInCurious:{id:"leanInCurious",name:"Lean In Curious",loop:!1,frames:[{state:{eyes:{scaleY:1.1,position:{x:0,y:-.1}},mouth:{shape:"neutral",openness:.3},face:{x:.2,y:-.15,tilt:5}},duration:250,transitionDuration:180},{state:{eyes:{scaleY:1.15,position:{x:.1,y:-.15}},mouth:{shape:"neutral",openness:.4},face:{x:.4,y:-.3,tilt:10}},duration:250,transitionDuration:180},{state:{eyes:{scaleY:1.2,position:{x:.15,y:-.2}},mouth:{shape:"neutral",openness:.5},face:{x:.6,y:-.45,tilt:15}},duration:300,transitionDuration:200},{state:{eyes:{scaleY:1.25,position:{x:.2,y:-.25}},mouth:{shape:"O",openness:.6},face:{x:.7,y:-.5,tilt:18}},duration:400,transitionDuration:100},{state:{eyes:{scaleY:1,position:{x:0,y:0}},mouth:{shape:"closed"},face:{x:0,y:0,tilt:0}},duration:0,transitionDuration:250}]},recoilBack:{id:"recoilBack",name:"Recoil Back",loop:!1,frames:[{state:{eyes:{scaleY:1.6,scaleX:1.5,position:{x:0,y:-.3}},mouth:{shape:"O",openness:1.3},face:{x:0,y:-.8,tilt:0}},duration:80,transitionDuration:30},{state:{eyes:{scaleY:1.5,scaleX:1.4,position:{x:0,y:-.25}},mouth:{shape:"O",openness:1.2},face:{x:0,y:-.7,tilt:0}},duration:60,transitionDuration:40},{state:{eyes:{scaleY:1.55,scaleX:1.45,position:{x:0,y:-.3}},mouth:{shape:"O",openness:1.25},face:{x:0,y:-.75,tilt:0}},duration:300,transitionDuration:50},{state:{eyes:{scaleY:1.3,position:{x:0,y:-.15}},mouth:{shape:"neutral",openness:.8},face:{x:0,y:-.4,tilt:0}},duration:200,transitionDuration:150},{state:{eyes:{scaleY:1,position:{x:0,y:0}},mouth:{shape:"closed"},face:{x:0,y:0,tilt:0}},duration:0,transitionDuration:200}]},shiftyEyes:{id:"shiftyEyes",name:"Shifty Eyes",loop:!1,frames:[{state:{eyes:{scaleY:.4,position:{x:-.6,y:.1}},mouth:{shape:"closed"},face:{x:-.15,y:.08,tilt:-4}},duration:500,transitionDuration:200},{state:{eyes:{scaleY:.4,position:{x:.6,y:.1}},mouth:{shape:"closed"},face:{x:.15,y:.08,tilt:4}},duration:450,transitionDuration:250},{state:{eyes:{scaleY:.4,position:{x:-.6,y:.1}},mouth:{shape:"closed"},face:{x:-.15,y:.08,tilt:-4}},duration:450,transitionDuration:250},{state:{eyes:{scaleY:.4,position:{x:.6,y:.1}},mouth:{shape:"closed"},face:{x:.15,y:.08,tilt:4}},duration:450,transitionDuration:250},{state:{eyes:{scaleY:.5,position:{x:0,y:.05}},mouth:{shape:"closed"},face:{x:0,y:.05,tilt:0}},duration:500,transitionDuration:200},{state:{eyes:{scaleY:.4,position:{x:-.5,y:.1}},mouth:{shape:"closed"},face:{x:-.12,y:.08,tilt:-3}},duration:400,transitionDuration:180},{state:{eyes:{scaleY:1,position:{x:0,y:0}},mouth:{shape:"closed"},face:{x:0,y:0,tilt:0}},duration:0,transitionDuration:300}]},suspiciousSquint:{id:"suspiciousSquint",name:"Suspicious Squint",loop:!1,frames:[{state:{eyes:{scaleY:.35,position:{x:0,y:.08}},mouth:{shape:"closed"},face:{x:0,y:.05,tilt:0}},duration:600,transitionDuration:200},{state:{eyes:{scaleY:.25,position:{x:.1,y:.1}},mouth:{shape:"closed"},face:{x:.05,y:.08,tilt:2}},duration:800,transitionDuration:150},{state:{eyes:{scaleY:.25,position:{x:-.1,y:.1}},mouth:{shape:"closed"},face:{x:-.05,y:.08,tilt:-2}},duration:800,transitionDuration:150},{state:{eyes:{scaleY:.4,position:{x:0,y:.05}},mouth:{shape:"closed"},face:{x:0,y:.03,tilt:0}},duration:500,transitionDuration:200},{state:{eyes:{scaleY:1,position:{x:0,y:0}},mouth:{shape:"closed"},face:{x:0,y:0,tilt:0}},duration:0,transitionDuration:300}]},eyeRoll:{id:"eyeRoll",name:"Eye Roll",loop:!1,frames:[{state:{eyes:{scaleY:.85,position:{x:0,y:0}},mouth:{shape:"closed"},face:{x:0,y:0,tilt:0}},duration:100,transitionDuration:80},{state:{eyes:{scaleY:.75,position:{x:0,y:.3}},mouth:{shape:"closed"},face:{x:0,y:.1,tilt:0}},duration:120,transitionDuration:100},{state:{eyes:{scaleY:.8,position:{x:.4,y:.25}},mouth:{shape:"closed"},face:{x:.08,y:.08,tilt:2}},duration:100,transitionDuration:90},{state:{eyes:{scaleY:.9,position:{x:.3,y:-.3}},mouth:{shape:"closed"},face:{x:.05,y:-.05,tilt:1}},duration:110,transitionDuration:95},{state:{eyes:{scaleY:1,position:{x:0,y:-.5}},mouth:{shape:"closed"},face:{x:0,y:-.1,tilt:0}},duration:120,transitionDuration:100},{state:{eyes:{scaleY:.9,position:{x:-.3,y:-.3}},mouth:{shape:"closed"},face:{x:-.05,y:-.05,tilt:-1}},duration:110,transitionDuration:95},{state:{eyes:{scaleY:.7,position:{x:0,y:.05}},mouth:{shape:"closed"},face:{x:0,y:.03,tilt:0}},duration:180,transitionDuration:120},{state:{eyes:{scaleY:1,position:{x:0,y:0}},mouth:{shape:"closed"},face:{x:0,y:0,tilt:0}},duration:0,transitionDuration:150}]},sideEye:{id:"sideEye",name:"Side Eye",loop:!1,frames:[{state:{eyes:{scaleY:1,position:{x:0,y:0}},mouth:{shape:"closed"},face:{x:0,y:0,tilt:0}},duration:120,transitionDuration:0},{state:{eyes:{scaleY:.5,position:{x:.7,y:.08}},mouth:{shape:"closed"},face:{x:.2,y:.05,tilt:5}},duration:300,transitionDuration:120},{state:{eyes:{scaleY:.35,position:{x:.75,y:.1}},mouth:{shape:"closed"},face:{x:.25,y:.08,tilt:6}},duration:400,transitionDuration:100},{state:{eyes:{scaleY:1.2,position:{x:0,y:-.05}},mouth:{shape:"closed"},face:{x:0,y:-.03,tilt:0}},duration:100,transitionDuration:80},{state:{eyes:{scaleY:1,position:{x:0,y:0}},mouth:{shape:"closed"},face:{x:0,y:0,tilt:0}},duration:0,transitionDuration:120}]},nervousGlance:{id:"nervousGlance",name:"Nervous Glance",loop:!1,frames:[{state:{eyes:{scaleY:1.1,position:{x:-.5,y:-.05}},mouth:{shape:"closed"},face:{x:-.1,y:0,tilt:-3}},duration:90,transitionDuration:60},{state:{eyes:{scaleY:1.1,position:{x:.5,y:-.05}},mouth:{shape:"closed"},face:{x:.1,y:0,tilt:3}},duration:85,transitionDuration:55},{state:{eyes:{scaleY:.85,position:{x:.2,y:.3}},mouth:{shape:"closed"},face:{x:.05,y:.1,tilt:1}},duration:110,transitionDuration:70},{state:{eyes:{scaleY:1.15,position:{x:-.4,y:-.25}},mouth:{shape:"closed"},face:{x:-.08,y:-.08,tilt:-2}},duration:95,transitionDuration:65},{state:{eyes:{scaleY:1.05,position:{x:0,y:0}},mouth:{shape:"closed"},face:{x:0,y:0,tilt:0}},duration:70,transitionDuration:60},{state:{eyes:{scaleY:1.1,position:{x:.45,y:-.1}},mouth:{shape:"closed"},face:{x:.09,y:-.02,tilt:2}},duration:80,transitionDuration:55},{state:{eyes:{scaleY:.1,position:{x:0,y:0}},mouth:{shape:"closed"},face:{x:0,y:0,tilt:0}},duration:60,transitionDuration:40},{state:{eyes:{scaleY:1,position:{x:0,y:0}},mouth:{shape:"closed"},face:{x:0,y:0,tilt:0}},duration:0,transitionDuration:100}]},wideEyedWonder:{id:"wideEyedWonder",name:"Wide Eyed Wonder",loop:!1,frames:[{state:{eyes:{scaleY:1.4,scaleX:1.3,position:{x:0,y:-.2}},mouth:{shape:"O",openness:.7},face:{x:0,y:-.15,tilt:0}},duration:150,transitionDuration:80},{state:{eyes:{scaleY:1.5,scaleX:1.35,position:{x:.3,y:-.4}},mouth:{shape:"O",openness:.8},face:{x:.15,y:-.3,tilt:5}},duration:250,transitionDuration:150},{state:{eyes:{scaleY:1.5,scaleX:1.35,position:{x:-.3,y:-.4}},mouth:{shape:"O",openness:.8},face:{x:-.15,y:-.3,tilt:-5}},duration:250,transitionDuration:180},{state:{eyes:{scaleY:1.3,scaleX:1.25,position:{x:0,y:.2}},mouth:{shape:"smile",openness:.9},face:{x:0,y:.15,tilt:0}},duration:220,transitionDuration:140},{state:{eyes:{scaleY:1.4,scaleX:1.3,position:{x:0,y:-.15}},mouth:{shape:"smile",openness:1},face:{x:0,y:-.12,tilt:0}},duration:200,transitionDuration:120},{state:{eyes:{scaleY:1.2,position:{x:0,y:-.05}},mouth:{shape:"smile",openness:.8},face:{x:0,y:-.05,tilt:0}},duration:180,transitionDuration:140},{state:{eyes:{scaleY:1,position:{x:0,y:0}},mouth:{shape:"closed"},face:{x:0,y:0,tilt:0}},duration:0,transitionDuration:150}]},doubleTake:{id:"doubleTake",name:"Double Take",loop:!1,frames:[{state:{eyes:{scaleY:1,position:{x:.4,y:0}},mouth:{shape:"closed"},face:{x:.3,y:0,tilt:5}},duration:200,transitionDuration:120},{state:{eyes:{scaleY:1.2,position:{x:0,y:-.05}},mouth:{shape:"neutral",openness:.4},face:{x:0,y:-.05,tilt:0}},duration:100,transitionDuration:70},{state:{eyes:{scaleY:.95,position:{x:.35,y:.05}},mouth:{shape:"closed"},face:{x:.25,y:.03,tilt:4}},duration:150,transitionDuration:100},{state:{eyes:{scaleY:1.6,scaleX:1.5,position:{x:0,y:-.3}},mouth:{shape:"O",openness:1.2},face:{x:0,y:-.25,tilt:0}},duration:120,transitionDuration:60},{state:{eyes:{scaleY:1.55,scaleX:1.45,position:{x:0,y:-.28}},mouth:{shape:"O",openness:1.1},face:{x:0,y:-.23,tilt:0}},duration:350,transitionDuration:50},{state:{eyes:{scaleY:1.3,position:{x:0,y:-.15}},mouth:{shape:"neutral",openness:.7},face:{x:0,y:-.12,tilt:0}},duration:200,transitionDuration:150},{state:{eyes:{scaleY:1,position:{x:0,y:0}},mouth:{shape:"closed"},face:{x:0,y:0,tilt:0}},duration:0,transitionDuration:180}]},quirkyGlitch:{id:"quirkyGlitch",name:"Quirky Glitch",loop:!1,frames:[{state:{eyes:{scaleY:1.3,position:{x:.4,y:-.3}},mouth:{shape:"open",openness:.8},face:{x:.5,y:-.4,tilt:15}},duration:80,transitionDuration:0},{state:{eyes:{scaleY:.3,position:{x:-.5,y:.4}},mouth:{shape:"smile",openness:1},face:{x:-.6,y:.3,tilt:-20}},duration:70,transitionDuration:0},{state:{eyes:{scaleY:1.5,position:{x:.2,y:-.5}},mouth:{shape:"O",openness:.9},face:{x:.3,y:-.5,tilt:25}},duration:60,transitionDuration:0},{state:{eyes:{scaleY:.5,position:{x:-.4,y:.2}},mouth:{shape:"neutral",openness:.3},face:{x:-.4,y:.4,tilt:-15}},duration:90,transitionDuration:0},{state:{eyes:{scaleY:1.4,position:{x:.5,y:.1}},mouth:{shape:"smile",openness:1},face:{x:.6,y:.2,tilt:18}},duration:75,transitionDuration:0},{state:{eyes:{scaleY:.2,position:{x:-.3,y:-.4}},mouth:{shape:"closed"},face:{x:-.5,y:-.3,tilt:-22}},duration:65,transitionDuration:0},{state:{eyes:{scaleY:1.2,position:{x:0,y:.3}},mouth:{shape:"open",openness:.7},face:{x:.2,y:.5,tilt:12}},duration:85,transitionDuration:0},{expression:"excited",duration:300,transitionDuration:100},{expression:"neutral",duration:0,transitionDuration:200}]},crazyEyes:{id:"crazyEyes",name:"Crazy Eyes",loop:!1,frames:[{state:{eyes:{scaleY:1.2,position:{x:-.5,y:-.3}},mouth:{shape:"closed"},face:{x:-.2,y:0,tilt:0}},duration:100,transitionDuration:40},{state:{eyes:{scaleY:1.2,position:{x:.5,y:.3}},mouth:{shape:"closed"},face:{x:.2,y:0,tilt:0}},duration:100,transitionDuration:40},{state:{eyes:{scaleY:1.2,position:{x:-.4,y:.4}},mouth:{shape:"closed"},face:{x:-.1,y:.1,tilt:0}},duration:100,transitionDuration:40},{state:{eyes:{scaleY:1.2,position:{x:.4,y:-.4}},mouth:{shape:"closed"},face:{x:.1,y:-.1,tilt:0}},duration:100,transitionDuration:40},{state:{eyes:{scaleY:1.2,position:{x:0,y:.5}},mouth:{shape:"closed"},face:{x:0,y:.2,tilt:0}},duration:100,transitionDuration:40},{state:{eyes:{scaleY:1.2,position:{x:0,y:-.5}},mouth:{shape:"closed"},face:{x:0,y:-.2,tilt:0}},duration:100,transitionDuration:40},{expression:"surprised",duration:400,transitionDuration:80},{expression:"neutral",duration:0,transitionDuration:200}]}},X=Object.values(q),b=r=>q[r],w={happy:{type:"expression",id:"happy"},cheerful:{type:"expression",id:"cheerful"},focused:{type:"expression",id:"focused"},dramatic:{type:"expression",id:"dramatic"},tired:{type:"expression",id:"tired"},sleepy:{type:"expression",id:"sleepy"},sneaky:{type:"expression",id:"sneaky"},hyper:{type:"expression",id:"hyper"},crazy:{type:"expression",id:"crazy"},wink:{type:"expression",id:"wink"},surprised:{type:"expression",id:"surprised"},curious:{type:"expression",id:"curious"},skeptical:{type:"expression",id:"skeptical"},shy:{type:"expression",id:"shy"},excited:{type:"expression",id:"excited"},shocked:{type:"expression",id:"shocked"},straining:{type:"expression",id:"straining"},flirty:{type:"expression",id:"flirty"},listening:{type:"expression",id:"listening"},bouncing:{type:"sequence",id:"excitedBounce"},recoiling:{type:"sequence",id:"recoilBack"},leaning:{type:"sequence",id:"leanInCurious"},squinting:{type:"sequence",id:"suspiciousSquint"},shying:{type:"sequence",id:"shyReaction"},agreeing:{type:"sequence",id:"headNodYes"},disagreeing:{type:"sequence",id:"headShakeNo"},thinking:{type:"sequence",id:"thinking"},confused:{type:"sequence",id:"headTiltConfused"},playful:{type:"sequence",id:"winkSequence"},wonder:{type:"sequence",id:"wideEyedWonder"},nervous:{type:"sequence",id:"nervousGlance"},sassy:{type:"sequence",id:"sideEye"},suspicious:{type:"sequence",id:"shiftyEyes"},mischievous:{type:"sequence",id:"eyeRoll"},greeting:{type:"sequence",id:"greeting"},scanning:{type:"sequence",id:"lookAroundScan"},doubletake:{type:"sequence",id:"doubleTake"},glitching:{type:"sequence",id:"quirkyGlitch"},awakening:{type:"sequence",id:"digitalAwaken"},cheerfulSeq:{type:"sequence",id:"cheerful"},curiousScan:{type:"sequence",id:"curiousScan"},crazyEyes:{type:"sequence",id:"crazyEyes"},blink:{type:"sequence",id:"blink"},doubleBlink:{type:"sequence",id:"doubleBlink"},slowBlink:{type:"sequence",id:"slowBlink"},wakeUp:{type:"sequence",id:"wakeUp"},talking:{type:"sequence",id:"talking"},idle:{type:"sequence",id:"idle"},glitchMood:{type:"sequence",id:"glitchMood"},quickNod:{type:"sequence",id:"quickNod"},strongNo:{type:"sequence",id:"strongNo"}},I={sad:"shy",neutral:"focused",warm:"happy",friendly:"cheerful",serious:"focused",amused:"playful",concerned:"curious",empathetic:"shy",confident:"agreeing",enthusiastic:"excited",thoughtful:"thinking",impressed:"wonder",calm:"focused",angry:"disagreeing",frustrated:"skeptical",supportive:"agreeing",gentle:"shy",hopeful:"cheerful",proud:"excited",nostalgic:"thinking",relieved:"happy",anxious:"nervous",sarcastic:"sassy",devious:"sneaky",energetic:"hyper",wild:"crazy",exhausted:"sleepy",bored:"tired",cunning:"suspicious",judging:"mischievous",welcoming:"greeting",searching:"scanning",startled:"shocked",concentrated:"straining",amazed:"doubletake",glitchy:"glitching",glitch:"glitching"};function v(r){return w[r]?r:I[r]??null}class F extends W{constructor(e={}){super();a(this,"_state");a(this,"_currentExpression",null);a(this,"_isPlaying",!1);a(this,"_isAutoAnimating",!1);a(this,"_isIdleMode",!1);a(this,"_mood","normal");a(this,"timeouts",new Set);a(this,"_loopingSeqId",null);a(this,"_idleFidgetActive",!1);a(this,"_idleFidgetTimer",null);a(this,"_idleFidgetOptions",{sequences:["slowBlink","curiousScan","lookAroundScan","shiftyEyes","shyReaction","winkSequence","headTiltConfused","sideEye","doubleTake","leanInCurious","doubleBlink","nervousGlance"],glitchSequences:["glitchMood","quirkyGlitch"],glitchChance:.15,minInterval:3e3,maxInterval:8e3});const i=e.initialExpression??"neutral",s=D(i);this._state=s?s.state:this.getDefaultState(),this._currentExpression=i,this._mood=e.initialMood??"normal",e.autoAnimate&&this.setAutoAnimate(!0),(e.idleMode??!0)&&this.setIdleMode(!0)}get state(){return Object.freeze({...this._state})}get currentExpression(){return this._currentExpression}get isPlaying(){return this._isPlaying}get isAutoAnimating(){return this._isAutoAnimating}get isIdleMode(){return this._isIdleMode}get mood(){return this._mood}setExpression(e,i){const s=D(e);if(!s)throw new Error(`Expression "${e}" not found`);const o={...s.state};if(o.face){const c=(Math.random()-.5)*.1,l=(Math.random()-.5)*.1,p=(Math.random()-.5)*4;o.face={x:o.face.x+c,y:o.face.y+l,tilt:(o.face.tilt??0)+p}}else o.face={x:(Math.random()-.5)*.12,y:(Math.random()-.5)*.12,tilt:(Math.random()-.5)*5};this._state=o,this._currentExpression=e,this.emit("expressionChange",e),this.emit("stateChange",this._state)}setState(e,i){this._state={eyes:{...this._state.eyes,...e.eyes},mouth:{...this._state.mouth,...e.mouth},face:e.face?{...this._state.face,...e.face}:this._state.face},this._currentExpression=null,this.emit("stateChange",this._state)}async blink(e=150){if(this._isPlaying)return;const i={...this._state},s=this._currentExpression;this.setState({eyes:{scaleY:.08}}),await this.wait(e),this._state=i,this._currentExpression=s,this.emit("stateChange",this._state)}async playSequence(e){const i=b(e);if(!i)throw new Error(`Sequence "${e}" not found`);this.stopSequence(),this._isPlaying=!0,this.emit("sequenceStart",e);try{await this.runSequence(i),this.emit("sequenceEnd",e)}finally{this._isPlaying=!1}}stopSequence(){this.timeouts.forEach(clearTimeout),this.timeouts.clear(),this._isPlaying=!1}setAutoAnimate(e){this._isAutoAnimating=e,this.emit("autoAnimateChange",e),e?(this.scheduleRandomBlink(),this.scheduleRandomCheerful()):(this.stopSequence(),this.setExpression("neutral"))}setMood(e){this._mood=e,this.emit("moodChange",e)}setIdleMode(e){this._isIdleMode=e,this.emit("idleModeChange",e),e&&(this.scheduleRandomExpression(),this.scheduleRandomMood())}getState(){return Object.freeze({...this._state})}getCurrentExpression(){return this._currentExpression}getExpressions(){return T}getSequences(){return X}isAnimating(){return this._isPlaying||this._isAutoAnimating}loopSequence(e){this._loopingSeqId=e,this.setAutoAnimate(!1),this.setIdleMode(!1);const i=()=>{this._loopingSeqId===e&&this.playSequence(e).then(()=>{this._loopingSeqId===e&&i()}).catch(()=>{})};i()}stopLoop(){this._loopingSeqId=null,this.stopSequence()}applyEmotion(e){const i=v(e)??e,s=w[i];if(!s)return null;if(this.stopSequence(),b(s.id))this.playSequence(s.id).catch(()=>{});else if(D(s.id))this.setExpression(s.id);else if(D(i))this.setExpression(i);else return null;return this.emit("emotionApplied",i),i}setIdleFidget(e,i){if(this._idleFidgetActive=!1,this._idleFidgetTimer&&(clearTimeout(this._idleFidgetTimer),this._idleFidgetTimer=null),!e)return;i&&(this._idleFidgetOptions={...this._idleFidgetOptions,...i}),this._idleFidgetActive=!0;const s=this._idleFidgetOptions,o=()=>{if(!this._idleFidgetActive)return;const c=s.minInterval+Math.random()*(s.maxInterval-s.minInterval);this._idleFidgetTimer=setTimeout(()=>{if(!this._idleFidgetActive)return;const l=Math.random()<s.glitchChance?s.glitchSequences:s.sequences,p=l[Math.floor(Math.random()*l.length)];this.emit("idleFidgetPlay",p),this.playSequence(p).then(()=>{this._idleFidgetActive&&o()}).catch(()=>{this._idleFidgetActive&&o()})},c)};o()}destroy(){this.stopSequence(),this.stopLoop(),this.setIdleFidget(!1),this.setAutoAnimate(!1),this.removeAllListeners()}async runSequence(e){const i=async()=>{for(const s of e.frames){if(!this._isPlaying)break;s.expression?this.setExpression(s.expression):s.state&&this.setState(s.state);const o=(s.transitionDuration??0)+s.duration;await this.wait(o)}e.loop&&this._isPlaying&&await i()};await i()}scheduleRandomBlink(){if(!this._isAutoAnimating)return;const i=(2500+Math.random()*4e3)*S[this._mood],s=setTimeout(async()=>{if(!this._isPlaying){const o=Math.random()<.3;await this.playSequence(o?"doubleBlink":"blink")}this.scheduleRandomBlink()},i);this.timeouts.add(s)}scheduleRandomCheerful(){if(!this._isAutoAnimating)return;const i=(6e3+Math.random()*6e3)*S[this._mood],s=setTimeout(async()=>{this._isPlaying||await this.playSequence("cheerful"),this.scheduleRandomCheerful()},i);this.timeouts.add(s)}scheduleRandomExpression(){if(!this._isIdleMode)return;const e=8e3+Math.random()*7e3,i=setTimeout(()=>{if(!this._isPlaying&&this._isIdleMode){const s=["neutral","happy","cheerful","curious","skeptical","shy","squintLight","squintMedium","focused","surprised"],o=s[Math.floor(Math.random()*s.length)];this.setExpression(o)}this.scheduleRandomExpression()},e);this.timeouts.add(i)}scheduleRandomMood(){if(!this._isIdleMode)return;const e=2e4+Math.random()*2e4,i=setTimeout(()=>{if(!this._isPlaying&&this._isIdleMode){const s=["normal","energized","tired"],o=s[Math.floor(Math.random()*s.length)];this.setMood(o)}this.scheduleRandomMood()},e);this.timeouts.add(i)}wait(e){const i=e*S[this._mood];return new Promise(s=>{const o=setTimeout(()=>{this.timeouts.delete(o),s()},i);this.timeouts.add(o)})}getDefaultState(){return{eyes:{scaleY:1},mouth:{visible:!1},face:{x:0,y:0,tilt:0}}}}const z=(r={})=>{const t=y.useRef(null),[e,i]=y.useState(()=>({eyes:{scaleY:1},mouth:{visible:!1}})),[s,o]=y.useState(r.initialExpression??"neutral"),[c,l]=y.useState(!1),[p,x]=y.useState(r.autoAnimate??!1),[f,m]=y.useState(r.idleMode??!0),[g,u]=y.useState(r.initialMood??"normal");t.current||(t.current=new F(r));const n=t.current;return y.useEffect(()=>{const d=h=>i(h),k=h=>o(h),A=()=>l(!0),E=()=>l(!1),C=h=>x(h),_=h=>m(h),M=h=>u(h);return n.on("stateChange",d),n.on("expressionChange",k),n.on("sequenceStart",A),n.on("sequenceEnd",E),n.on("autoAnimateChange",C),n.on("idleModeChange",_),n.on("moodChange",M),i(n.getState()),o(n.getCurrentExpression()),m(n.isIdleMode),u(n.mood),()=>{n.off("stateChange",d),n.off("expressionChange",k),n.off("sequenceStart",A),n.off("sequenceEnd",E),n.off("autoAnimateChange",C),n.off("idleModeChange",_),n.off("moodChange",M)}},[n]),y.useEffect(()=>()=>n.destroy(),[n]),{state:e,currentExpression:s,isPlaying:c,isAutoAnimating:p,isIdleMode:f,mood:g,setExpression:n.setExpression.bind(n),setState:n.setState.bind(n),blink:n.blink.bind(n),playSequence:n.playSequence.bind(n),stopSequence:n.stopSequence.bind(n),setAutoAnimate:n.setAutoAnimate.bind(n),setIdleMode:n.setIdleMode.bind(n),setMood:n.setMood.bind(n),getExpressions:n.getExpressions.bind(n),getSequences:n.getSequences.bind(n)}};function B(r){const t=r.toLowerCase().trim();if(!t)return"closed";const e=t[0],i=t.slice(0,2);return"mbp".includes(e)?"M":"fv".includes(e)?"F":e==="w"||i==="oo"?"W":e==="o"?"O":e==="a"?"A":"ei".includes(e)?"E":e==="u"?"U":"A"}class N{constructor(t,e){a(this,"controller");a(this,"options");a(this,"_isSpeaking",!1);a(this,"timingOrigin",0);a(this,"scheduledTimeouts",new Set);a(this,"audioContext",null);a(this,"analyser",null);a(this,"sourceNode",null);a(this,"amplitudeFrame",null);a(this,"amplitudeData",null);a(this,"ownsAudioContext",!1);a(this,"connectedElement",null);this.controller=t,this.options={sensitivity:(e==null?void 0:e.sensitivity)??.5,smoothing:(e==null?void 0:e.smoothing)??.3,idleExpression:(e==null?void 0:e.idleExpression)??"neutral"}}get isSpeaking(){return this._isSpeaking}feedTimestamps(t){const e=performance.now(),i=this.timingOrigin||e;for(const s of t){const o=s.start*1e3,c=s.end*1e3,l=e-i,p=Math.max(0,o-l),x=setTimeout(()=>{if(this.scheduledTimeouts.delete(x),!this._isSpeaking)return;const g=B(s.word);this.controller.setState({mouth:{shape:g,visible:!0}})},p);this.scheduledTimeouts.add(x);const f=Math.max(0,c-l),m=setTimeout(()=>{this.scheduledTimeouts.delete(m),this._isSpeaking&&this.controller.setState({mouth:{shape:"closed",openness:0}})},f);this.scheduledTimeouts.add(m)}}connectElement(t){if(this.connectedElement===t&&this.analyser)return;this.disconnectAudio(),this.connectedElement=t,this.ownsAudioContext=!0,this.audioContext=new AudioContext;const e=this.audioContext.createMediaElementSource(t);this.setupAnalyser(e,this.audioContext),e.connect(this.audioContext.destination),this.sourceNode=e}connectSource(t,e){this.disconnectAudio(),this.ownsAudioContext=!1,this.audioContext=e,this.setupAnalyser(t,e),this.sourceNode=t}start(){var t;this._isSpeaking=!0,this.timingOrigin=performance.now(),((t=this.audioContext)==null?void 0:t.state)==="suspended"&&this.audioContext.resume(),this.analyser&&this.startAmplitudeLoop()}stop(){this._isSpeaking=!1;for(const t of this.scheduledTimeouts)clearTimeout(t);this.scheduledTimeouts.clear(),this.amplitudeFrame!==null&&(cancelAnimationFrame(this.amplitudeFrame),this.amplitudeFrame=null),this.controller.setState({mouth:{shape:"closed",openness:0,visible:!1}})}destroy(){this.stop(),this.disconnectAudio()}setupAnalyser(t,e){this.analyser=e.createAnalyser(),this.analyser.fftSize=256,this.analyser.smoothingTimeConstant=this.options.smoothing,t.connect(this.analyser),this.amplitudeData=new Uint8Array(this.analyser.frequencyBinCount)}startAmplitudeLoop(){if(this.amplitudeFrame!==null)return;const t=()=>{if(!this._isSpeaking||!this.analyser||!this.amplitudeData){this.amplitudeFrame=null;return}this.analyser.getByteTimeDomainData(this.amplitudeData);let e=0;for(let c=0;c<this.amplitudeData.length;c++){const l=(this.amplitudeData[c]-128)/128;e+=l*l}const i=Math.sqrt(e/this.amplitudeData.length),s=Math.min(1,i*(4+this.options.sensitivity*12)),o=s<.08?0:s;this.controller.setState({mouth:{openness:o,visible:o>0}}),this.amplitudeFrame=requestAnimationFrame(t)};this.amplitudeFrame=requestAnimationFrame(t)}disconnectAudio(){this.amplitudeFrame!==null&&(cancelAnimationFrame(this.amplitudeFrame),this.amplitudeFrame=null),this.analyser&&(this.analyser.disconnect(),this.analyser=null),this.ownsAudioContext&&this.audioContext&&this.audioContext.close().catch(()=>{}),this.audioContext=null,this.sourceNode=null,this.connectedElement=null,this.amplitudeData=null}}class R{constructor(t){a(this,"words",[]);a(this,"processedCount",0);a(this,"groups",[]);a(this,"minWords");a(this,"maxWords");this.minWords=(t==null?void 0:t.minWords)??2,this.maxWords=(t==null?void 0:t.maxWords)??5}feed(t){this.words.push(...t),this.process()}flush(){if(this.processedCount<this.words.length){const t=this.words.slice(this.processedCount);this.groups.push({text:t.map(e=>e.word).join(" "),startTime:t[0].start,endTime:t[t.length-1].end}),this.processedCount=this.words.length}}getGroups(){return this.groups}getWords(){return this.words}reset(){this.words=[],this.processedCount=0,this.groups=[]}process(){for(;this.processedCount<this.words.length;){const t=this.processedCount;let e=t;for(;e<this.words.length;){e++;const s=e-t,o=this.words[e-1].word;if(/[.!?;]$/.test(o)&&s>=this.minWords||s>=this.maxWords)break}if(e-t<this.minWords&&e<this.words.length||e===this.words.length&&e-t<this.minWords)break;const i=this.words.slice(t,e);this.groups.push({text:i.map(s=>s.word).join(" "),startTime:i[0].start,endTime:i[i.length-1].end}),this.processedCount=e}}}function G(r){const t=r.toLowerCase().replace(/[^a-z]/g,"");if(!t)return"closed";const e=t[0];return"mbp".includes(e)?"M":"fv".includes(e)?"F":e==="w"||t.startsWith("oo")?"W":e==="o"?"O":e==="a"?"A":"ei".includes(e)?"E":e==="u"?"U":"A"}class U{constructor(t,e,i,s,o){a(this,"controller");a(this,"bubbleGrouper");a(this,"getPlaybackPosition");a(this,"callbacks");a(this,"rafId",0);a(this,"active",!1);a(this,"lastBubbleIdx",-1);a(this,"lastVisemeWordIdx",-1);a(this,"exprQueue",[]);a(this,"lastAppliedExprQueueIdx",-1);a(this,"flushTimer",null);a(this,"tick",()=>{var c,l,p,x,f,m,g;if(!this.active)return;const t=this.getPlaybackPosition(),e=this.bubbleGrouper.getWords();let i=-1;for(let u=e.length-1;u>=0;u--)if(e[u].start<=t){i=u;break}if(i>=0&&i!==this.lastVisemeWordIdx){this.lastVisemeWordIdx=i;const u=e[i];t<=u.end?this.controller.setState({mouth:{shape:G(u.word)}}):this.controller.setState({mouth:{shape:"closed"}})}else if(i>=0){const u=e[i];t>u.end&&this.controller.setState({mouth:{shape:"closed"}})}const s=this.bubbleGrouper.getGroups();let o=-1;for(let u=s.length-1;u>=0;u--)if(s[u].startTime<=t){o=u;break}if(o>=0&&o!==this.lastBubbleIdx&&(this.lastBubbleIdx=o,(l=(c=this.callbacks).onBubbleChange)==null||l.call(c,s[o].text,!0)),o>=0&&t>s[o].endTime&&((x=(p=this.callbacks).onBubbleChange)==null||x.call(p,"",!1)),this.exprQueue.length>0&&i>=0){let u=0;for(let d=0;d<=i;d++)u+=e[d].word.length;let n=-1;for(let d=this.exprQueue.length-1;d>=0;d--)if(this.exprQueue[d].nwsCharIdx<=u){n=d;break}if(n>=0&&n!==this.lastAppliedExprQueueIdx){this.lastAppliedExprQueueIdx=n;const d=this.exprQueue[n],k=((f=e[i])==null?void 0:f.word)??"?";console.log("[PlaybackSync] Apply expression:",d.key,"| word #"+i,"("+k+")","| spokenNwsChars:",u,"| expr nwsCharIdx:",d.nwsCharIdx),(g=(m=this.callbacks).onExpressionChange)==null||g.call(m,d.key)}}this.rafId=requestAnimationFrame(this.tick)});this.controller=t,this.bubbleGrouper=e,this.getPlaybackPosition=i,this.callbacks=s??{}}queueExpression(t,e){console.log("[PlaybackSync] Queue expression:",t,"nwsCharIdx:",e),this.exprQueue.push({key:t,nwsCharIdx:e})}feedTimestamps(t){this.bubbleGrouper.getWords().length;const i=[];for(let s=0;s<t.words.length;s++)i.push({word:t.words[s],start:t.start[s],end:t.end[s]});this.bubbleGrouper.feed(i),this.flushTimer&&clearTimeout(this.flushTimer),this.flushTimer=setTimeout(()=>this.bubbleGrouper.flush(),500)}start(){this.active||(this.active=!0,this.lastBubbleIdx=-1,this.lastVisemeWordIdx=-1,this.lastAppliedExprQueueIdx=-1,this.tick())}stop(){var t,e;this.active=!1,cancelAnimationFrame(this.rafId),this.flushTimer&&(clearTimeout(this.flushTimer),this.flushTimer=null),this.exprQueue=[],this.lastAppliedExprQueueIdx=-1,this.lastBubbleIdx=-1,this.lastVisemeWordIdx=-1,this.bubbleGrouper.reset(),(e=(t=this.callbacks).onBubbleChange)==null||e.call(t,"",!1)}get isActive(){return this.active}}exports.AvatarController=F;exports.EMOTION_ACTIONS=w;exports.FALLBACK_MAP=I;exports.PlaybackSync=U;exports.SpeechBubbleGrouper=R;exports.SpeechController=N;exports.expressionList=T;exports.expressions=Y;exports.getDefaultState=P;exports.getExpression=D;exports.getSequence=b;exports.resolveEmotionKey=v;exports.sequenceList=X;exports.sequences=q;exports.useAvatarController=z;exports.wordToViseme=B;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Avatar React Entry Point
3
+ * Re-exports everything needed for React consumers
4
+ */
5
+ export * from './lib/avatar';
6
+ export { default as Avatar } from './components/Avatar';
7
+ export { useCursorTracking } from './hooks/useCursorTracking';
8
+ export { useGlitchEffect } from './hooks/useGlitchEffect';
9
+ export { useSpeech } from './hooks/useSpeech';
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Avatar Component
3
+ * The visual representation of the avatar with eye tracking and glitch effects
4
+ */
5
+ import { AvatarProps } from "@/lib/avatar/types";
6
+ interface EnhancedAvatarProps extends AvatarProps {
7
+ /** Enable cursor eye tracking */
8
+ cursorTracking?: boolean;
9
+ /** Enable glitch effects on expression changes */
10
+ enableGlitch?: boolean;
11
+ /** Speech text to display in bubble */
12
+ speechText?: string;
13
+ /**
14
+ * Controls the intro sequence:
15
+ * - omitted/undefined: no intro, show avatar immediately
16
+ * - false: intro pending (show pixel, wait for true)
17
+ * - true: play intro animation now
18
+ */
19
+ playIntro?: boolean;
20
+ /** Called when intro sequence completes */
21
+ onIntroComplete?: () => void;
22
+ }
23
+ declare const Avatar: ({ controller, state: propState, expression, autoAnimate, className, eyeSize, eyeGap, mouthSize, glowColor, glowIntensity, cursorTracking, enableGlitch, speechText, playIntro, onIntroComplete, }: EnhancedAvatarProps) => import("react/jsx-runtime").JSX.Element;
24
+ export default Avatar;
package/dist/core.cjs ADDED
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./PlaybackSync-DwFiX-W4.cjs");exports.AvatarControllerClass=e.AvatarController;exports.EMOTION_ACTIONS=e.EMOTION_ACTIONS;exports.FALLBACK_MAP=e.FALLBACK_MAP;exports.PlaybackSync=e.PlaybackSync;exports.SpeechBubbleGrouper=e.SpeechBubbleGrouper;exports.SpeechController=e.SpeechController;exports.expressionList=e.expressionList;exports.expressions=e.expressions;exports.getDefaultState=e.getDefaultState;exports.getExpression=e.getExpression;exports.getSequence=e.getSequence;exports.resolveEmotionKey=e.resolveEmotionKey;exports.sequenceList=e.sequenceList;exports.sequences=e.sequences;exports.useAvatarController=e.useAvatarController;exports.useAvatarControllerDefault=e.useAvatarController;exports.wordToViseme=e.wordToViseme;
package/dist/core.js ADDED
@@ -0,0 +1,20 @@
1
+ import { A as a, E as r, F as o, P as t, S as l, a as n, e as u, b as c, g as A, c as i, d as p, r as C, s as S, f as b, u as f, u as g, w as v } from "./PlaybackSync-CZsM--xy.js";
2
+ export {
3
+ a as AvatarControllerClass,
4
+ r as EMOTION_ACTIONS,
5
+ o as FALLBACK_MAP,
6
+ t as PlaybackSync,
7
+ l as SpeechBubbleGrouper,
8
+ n as SpeechController,
9
+ u as expressionList,
10
+ c as expressions,
11
+ A as getDefaultState,
12
+ i as getExpression,
13
+ p as getSequence,
14
+ C as resolveEmotionKey,
15
+ S as sequenceList,
16
+ b as sequences,
17
+ f as useAvatarController,
18
+ g as useAvatarControllerDefault,
19
+ v as wordToViseme
20
+ };
Binary file
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Cursor Tracking Hook
3
+ * Tracks mouse position and converts to eye position offsets
4
+ */
5
+ import { EyePosition } from "@/lib/avatar/types";
6
+ interface CursorTrackingOptions {
7
+ /** Enable/disable tracking */
8
+ enabled?: boolean;
9
+ /** Max offset range (0-1, how far eyes can move) */
10
+ maxOffset?: number;
11
+ /** Smoothing factor (0-1, lower = smoother but slower) */
12
+ smoothing?: number;
13
+ /** Container element ref for relative positioning */
14
+ containerRef?: React.RefObject<HTMLElement>;
15
+ /** Dead zone in center (0-1) where eyes don't move */
16
+ deadZone?: number;
17
+ }
18
+ export declare const useCursorTracking: (options?: CursorTrackingOptions) => {
19
+ eyePosition: EyePosition;
20
+ resetPosition: () => void;
21
+ setPosition: (position: EyePosition) => void;
22
+ isTracking: boolean;
23
+ };
24
+ export default useCursorTracking;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Glitch Effect Hook
3
+ * Creates erratic, digital glitch transitions for mood changes
4
+ */
5
+ interface GlitchState {
6
+ /** Horizontal shake intensity */
7
+ shakeX: number;
8
+ /** Vertical shake intensity */
9
+ shakeY: number;
10
+ /** Scale distortion */
11
+ scaleDistort: number;
12
+ /** Is currently glitching */
13
+ isGlitching: boolean;
14
+ /** Glitch opacity flicker */
15
+ opacity: number;
16
+ }
17
+ interface GlitchOptions {
18
+ /** Duration of glitch in ms */
19
+ duration?: number;
20
+ /** Intensity (0-1) */
21
+ intensity?: number;
22
+ /** Number of shake frames */
23
+ frames?: number;
24
+ }
25
+ export declare const useGlitchEffect: () => {
26
+ glitchState: GlitchState;
27
+ triggerGlitch: (options?: GlitchOptions) => Promise<void>;
28
+ microGlitch: () => Promise<void>;
29
+ heavyGlitch: () => Promise<void>;
30
+ stutterGlitch: () => Promise<void>;
31
+ getGlitchTransform: (baseTransform?: string) => string;
32
+ isGlitching: boolean;
33
+ };
34
+ export default useGlitchEffect;
@@ -0,0 +1,31 @@
1
+ /**
2
+ * React hook for speech-driven avatar animation.
3
+ * Wraps SpeechController for easy use in React components.
4
+ */
5
+ import { WordTimestamp, SpeechOptions } from '@/lib/avatar/SpeechController';
6
+ import { AvatarController } from '@/lib/avatar/AvatarController';
7
+ /**
8
+ * Hook that creates and manages a SpeechController for avatar mouth animation.
9
+ *
10
+ * @param controller - The AvatarController instance (from useAvatarController's internal ref,
11
+ * or a standalone AvatarControllerClass instance)
12
+ * @param options - Speech configuration options
13
+ *
14
+ * @example
15
+ * ```tsx
16
+ * const avatarController = useAvatarController({ autoAnimate: true });
17
+ * const speech = useSpeech(avatarControllerRef, { sensitivity: 0.6 });
18
+ *
19
+ * // Feed word timestamps from Cartesia TTS
20
+ * speech.feedTimestamps(timestamps);
21
+ * speech.start();
22
+ * ```
23
+ */
24
+ export declare function useSpeech(controller: AvatarController, options?: SpeechOptions): {
25
+ feedTimestamps: (timestamps: WordTimestamp[]) => void;
26
+ connectElement: (el: HTMLAudioElement | HTMLMediaElement) => void;
27
+ connectSource: (node: AudioNode, ctx: AudioContext) => void;
28
+ start: () => void;
29
+ stop: () => void;
30
+ isSpeaking: boolean;
31
+ };
@@ -0,0 +1,203 @@
1
+ /**
2
+ * Avatar Controller Class
3
+ * Framework-agnostic controller for avatar animation system
4
+ * Uses EventEmitter for reactive state updates
5
+ */
6
+ import { EventEmitter } from '../utils/EventEmitter';
7
+ import { AvatarState, AvatarControllerOptions, ExpressionConfig, AnimationSequence, IAvatarController, Mood } from './types';
8
+ export interface IdleFidgetOptions {
9
+ sequences?: string[];
10
+ glitchSequences?: string[];
11
+ glitchChance?: number;
12
+ minInterval?: number;
13
+ maxInterval?: number;
14
+ }
15
+ /**
16
+ * Core avatar controller class - framework-agnostic.
17
+ *
18
+ * @example
19
+ * ```typescript
20
+ * const controller = new AvatarController({ autoAnimate: true });
21
+ * controller.setExpression('happy');
22
+ * await controller.playSequence('greeting');
23
+ * ```
24
+ */
25
+ export declare class AvatarController extends EventEmitter implements IAvatarController {
26
+ private _state;
27
+ private _currentExpression;
28
+ private _isPlaying;
29
+ private _isAutoAnimating;
30
+ private _isIdleMode;
31
+ private _mood;
32
+ private timeouts;
33
+ private _loopingSeqId;
34
+ private _idleFidgetActive;
35
+ private _idleFidgetTimer;
36
+ private _idleFidgetOptions;
37
+ constructor(options?: AvatarControllerOptions);
38
+ get state(): AvatarState;
39
+ get currentExpression(): string | null;
40
+ get isPlaying(): boolean;
41
+ get isAutoAnimating(): boolean;
42
+ get isIdleMode(): boolean;
43
+ get mood(): Mood;
44
+ /**
45
+ * Set the avatar's facial expression.
46
+ *
47
+ * @param expressionId - The ID of the expression to set
48
+ * @param transitionMs - Optional transition duration (not used in MVP)
49
+ * @throws {Error} If the expression ID is not found
50
+ *
51
+ * @example
52
+ * ```typescript
53
+ * controller.setExpression('happy');
54
+ * controller.setExpression('surprised');
55
+ * ```
56
+ */
57
+ setExpression(expressionId: string, transitionMs?: number): void;
58
+ /**
59
+ * Set avatar state directly with partial updates.
60
+ *
61
+ * @param partialState - Partial state to merge with current state
62
+ * @param transitionMs - Optional transition duration (not used in MVP)
63
+ *
64
+ * @example
65
+ * ```typescript
66
+ * controller.setState({ eyes: { scaleY: 0.5 } });
67
+ * ```
68
+ */
69
+ setState(partialState: Partial<AvatarState>, transitionMs?: number): void;
70
+ /**
71
+ * Trigger a blink animation.
72
+ *
73
+ * @param durationMs - Duration of the blink in milliseconds (default: 150)
74
+ * @returns Promise that resolves when blink completes
75
+ *
76
+ * @example
77
+ * ```typescript
78
+ * await controller.blink();
79
+ * await controller.blink(200); // Slower blink
80
+ * ```
81
+ */
82
+ blink(durationMs?: number): Promise<void>;
83
+ /**
84
+ * Play an animation sequence.
85
+ *
86
+ * @param sequenceId - The ID of the sequence to play
87
+ * @returns Promise that resolves when sequence completes
88
+ * @throws {Error} If the sequence ID is not found
89
+ *
90
+ * @example
91
+ * ```typescript
92
+ * await controller.playSequence('greeting');
93
+ * await controller.playSequence('cheerful');
94
+ * ```
95
+ */
96
+ playSequence(sequenceId: string): Promise<void>;
97
+ /**
98
+ * Stop the currently playing sequence.
99
+ *
100
+ * @example
101
+ * ```typescript
102
+ * controller.stopSequence();
103
+ * ```
104
+ */
105
+ stopSequence(): void;
106
+ /**
107
+ * Enable or disable auto-animation mode.
108
+ *
109
+ * @param enabled - Whether to enable auto-animation
110
+ *
111
+ * @example
112
+ * ```typescript
113
+ * controller.setAutoAnimate(true); // Start auto-animations
114
+ * controller.setAutoAnimate(false); // Stop auto-animations
115
+ * ```
116
+ */
117
+ setAutoAnimate(enabled: boolean): void;
118
+ /**
119
+ * Set the avatar's mood (affects animation speed).
120
+ *
121
+ * @param mood - The mood to set ('normal', 'energized', or 'tired')
122
+ *
123
+ * @example
124
+ * ```typescript
125
+ * controller.setMood('energized'); // Faster animations
126
+ * controller.setMood('tired'); // Slower animations
127
+ * controller.setMood('normal'); // Default speed
128
+ * ```
129
+ */
130
+ setMood(mood: Mood): void;
131
+ /**
132
+ * Enable or disable idle mode (random expressions and moods).
133
+ *
134
+ * @param enabled - Whether to enable idle mode
135
+ *
136
+ * @example
137
+ * ```typescript
138
+ * controller.setIdleMode(true); // Start random variations
139
+ * controller.setIdleMode(false); // Stop random variations
140
+ * ```
141
+ */
142
+ setIdleMode(enabled: boolean): void;
143
+ /**
144
+ * Get the current avatar state (read-only).
145
+ *
146
+ * @returns Frozen copy of current state
147
+ */
148
+ getState(): Readonly<AvatarState>;
149
+ /**
150
+ * Get the current expression ID.
151
+ *
152
+ * @returns Current expression ID or null if state was set directly
153
+ */
154
+ getCurrentExpression(): string | null;
155
+ /**
156
+ * Get all available expressions.
157
+ *
158
+ * @returns Array of expression configurations
159
+ */
160
+ getExpressions(): ExpressionConfig[];
161
+ /**
162
+ * Get all available sequences.
163
+ *
164
+ * @returns Array of sequence configurations
165
+ */
166
+ getSequences(): AnimationSequence[];
167
+ /**
168
+ * Check if any animation is currently playing.
169
+ *
170
+ * @returns True if sequence is playing or auto-animation is enabled
171
+ */
172
+ isAnimating(): boolean;
173
+ /**
174
+ * Play a sequence in a loop until stopLoop() is called.
175
+ * Disables autoAnimate and idleMode while looping.
176
+ */
177
+ loopSequence(seqId: string): void;
178
+ /**
179
+ * Stop the currently looping sequence.
180
+ */
181
+ stopLoop(): void;
182
+ /**
183
+ * Apply an emotion by key — resolves to expression or sequence via EMOTION_ACTIONS.
184
+ * Returns the resolved key, or null if not found.
185
+ */
186
+ applyEmotion(emotionKey: string): string | null;
187
+ /**
188
+ * Enable/disable idle fidget — plays random sequences at random intervals.
189
+ */
190
+ setIdleFidget(enabled: boolean, options?: IdleFidgetOptions): void;
191
+ /**
192
+ * Clean up resources and stop all animations.
193
+ * Call this when disposing of the controller.
194
+ */
195
+ destroy(): void;
196
+ private runSequence;
197
+ private scheduleRandomBlink;
198
+ private scheduleRandomCheerful;
199
+ private scheduleRandomExpression;
200
+ private scheduleRandomMood;
201
+ private wait;
202
+ private getDefaultState;
203
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * PlaybackSync — unified rAF loop that syncs visemes, speech bubbles,
3
+ * and expression marks to a playback position.
4
+ *
5
+ * Coordinates timing between word-level mouth shapes, subtitle groups,
6
+ * and emotion/expression changes based on a single clock source.
7
+ */
8
+ import type { AvatarController as IAvatarController, MouthShape } from './types';
9
+ import type { SpeechBubbleGrouper } from './SpeechBubbleGrouper';
10
+ /** Map a word's first character(s) to a mouth shape viseme */
11
+ export declare function wordToViseme(word: string): MouthShape;
12
+ export interface ExpressionMark {
13
+ key: string;
14
+ startTime: number;
15
+ }
16
+ export interface PlaybackSyncCallbacks {
17
+ onBubbleChange?: (text: string, visible: boolean) => void;
18
+ onExpressionChange?: (key: string) => void;
19
+ }
20
+ export interface PlaybackSyncOptions {
21
+ }
22
+ export declare class PlaybackSync {
23
+ private controller;
24
+ private bubbleGrouper;
25
+ private getPlaybackPosition;
26
+ private callbacks;
27
+ private rafId;
28
+ private active;
29
+ private lastBubbleIdx;
30
+ private lastVisemeWordIdx;
31
+ private exprQueue;
32
+ private lastAppliedExprQueueIdx;
33
+ private flushTimer;
34
+ constructor(controller: IAvatarController, bubbleGrouper: SpeechBubbleGrouper, getPlaybackPosition: () => number, callbacks?: PlaybackSyncCallbacks, _options?: PlaybackSyncOptions);
35
+ /** Queue an expression key with the non-whitespace char index it should activate at. */
36
+ queueExpression(key: string, nwsCharIdx: number): void;
37
+ /** Feed word timestamps — delegates to bubbleGrouper and detects expression breaks. */
38
+ feedTimestamps(ts: {
39
+ words: string[];
40
+ start: number[];
41
+ end: number[];
42
+ }): void;
43
+ /** Start the rAF sync loop. */
44
+ start(): void;
45
+ /** Stop the sync loop and reset state. */
46
+ stop(): void;
47
+ /** Whether the sync loop is currently active. */
48
+ get isActive(): boolean;
49
+ private tick;
50
+ }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * SpeechBubbleGrouper — groups word timestamps into display-friendly bubble chunks.
3
+ *
4
+ * Feed word timestamps as they arrive from TTS, then read grouped bubbles
5
+ * for subtitle/caption display synced to playback position.
6
+ */
7
+ export interface BubbleGroup {
8
+ text: string;
9
+ startTime: number;
10
+ endTime: number;
11
+ }
12
+ export interface SpeechBubbleGrouperOptions {
13
+ minWords?: number;
14
+ maxWords?: number;
15
+ }
16
+ export declare class SpeechBubbleGrouper {
17
+ private words;
18
+ private processedCount;
19
+ private groups;
20
+ private minWords;
21
+ private maxWords;
22
+ constructor(options?: SpeechBubbleGrouperOptions);
23
+ /** Feed new word timestamps (accumulates). */
24
+ feed(timestamps: {
25
+ word: string;
26
+ start: number;
27
+ end: number;
28
+ }[]): void;
29
+ /** Flush any remaining un-grouped words into a final group. */
30
+ flush(): void;
31
+ /** Get all bubble groups computed so far. */
32
+ getGroups(): BubbleGroup[];
33
+ /** Get accumulated words. */
34
+ getWords(): {
35
+ word: string;
36
+ start: number;
37
+ end: number;
38
+ }[];
39
+ /** Reset all state for a new utterance. */
40
+ reset(): void;
41
+ private process;
42
+ }