react-ai-avatar 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/LICENSE +21 -0
- package/README.md +310 -0
- package/dist/lib/GlbArkitAvatar-CcPWCsQV.cjs +1 -0
- package/dist/lib/GlbArkitAvatar-Dm9STiyR.js +232 -0
- package/dist/lib/VrmAvatar-CehRzj0J.js +224 -0
- package/dist/lib/VrmAvatar-D_jr2TOG.cjs +1 -0
- package/dist/lib/components/AudioVisualizer.d.ts +17 -0
- package/dist/lib/components/ContractAvatar.d.ts +25 -0
- package/dist/lib/components/DefaultAvatar.d.ts +37 -0
- package/dist/lib/components/DiceBearAvatar.d.ts +48 -0
- package/dist/lib/components/DiceBearThumb.d.ts +15 -0
- package/dist/lib/components/DoodleAvatar.d.ts +21 -0
- package/dist/lib/components/GeometricAvatar.d.ts +22 -0
- package/dist/lib/components/GlbArkitAvatar.d.ts +7 -0
- package/dist/lib/components/MemojiAvatar.d.ts +19 -0
- package/dist/lib/components/PixelArtAvatar.d.ts +23 -0
- package/dist/lib/components/RealtimeAvatar.d.ts +74 -0
- package/dist/lib/components/SquirrelAvatar.d.ts +29 -0
- package/dist/lib/components/VrmAvatar.d.ts +6 -0
- package/dist/lib/index.cjs +6 -0
- package/dist/lib/index.js +1231 -0
- package/dist/lib/lib/color.d.ts +6 -0
- package/dist/lib/lib/dicebear.d.ts +110 -0
- package/dist/lib/lib/index.d.ts +34 -0
- package/dist/lib/lib/mouthEngine.d.ts +37 -0
- package/dist/lib/lib/speechActivity.d.ts +51 -0
- package/dist/lib/lib/types.d.ts +22 -0
- package/dist/lib/lib/useAudioMouth.d.ts +20 -0
- package/dist/lib/lib/useAvatarRuntime.d.ts +39 -0
- package/dist/lib/lib/useReducedMotion.d.ts +5 -0
- package/dist/lib/lib/useStreamingTextActivity.d.ts +46 -0
- package/dist/lib/lib/vrm.d.ts +9 -0
- package/dist/lib/react-ai-avatar.css +1 -0
- package/dist/lib/useReducedMotion-BDcEizfP.js +104 -0
- package/dist/lib/useReducedMotion-BRDEmRNI.cjs +1 -0
- package/dist/lib/vrm.cjs +1 -0
- package/dist/lib/vrm.js +4 -0
- package/package.json +127 -0
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { jsxs as w, jsx as a } from "react/jsx-runtime";
|
|
2
|
+
import te, { useState as Q, useEffect as C, Suspense as ne, useRef as c } from "react";
|
|
3
|
+
import { Canvas as ae, useLoader as ie, useFrame as oe } from "@react-three/fiber";
|
|
4
|
+
import { GLTFLoader as se } from "three/addons/loaders/GLTFLoader.js";
|
|
5
|
+
import { VRMLoaderPlugin as ce } from "@pixiv/three-vrm";
|
|
6
|
+
import { OrbitControls as le } from "@react-three/drei";
|
|
7
|
+
import * as n from "three";
|
|
8
|
+
import { u as ue, c as de } from "./useReducedMotion-BDcEizfP.js";
|
|
9
|
+
class pe extends te.Component {
|
|
10
|
+
constructor(t) {
|
|
11
|
+
super(t), this.state = { hasError: !1 };
|
|
12
|
+
}
|
|
13
|
+
static getDerivedStateFromError() {
|
|
14
|
+
return { hasError: !0 };
|
|
15
|
+
}
|
|
16
|
+
componentDidCatch(t) {
|
|
17
|
+
this.props.onError((t == null ? void 0 : t.message) || String(t));
|
|
18
|
+
}
|
|
19
|
+
render() {
|
|
20
|
+
return this.state.hasError ? null : this.props.children;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function d(l, t, p) {
|
|
24
|
+
if (!l.expressionManager) return;
|
|
25
|
+
const k = l.expressionManager.expressionMap || {}, U = Object.keys(k);
|
|
26
|
+
let i = [];
|
|
27
|
+
switch (t) {
|
|
28
|
+
case "blink":
|
|
29
|
+
i = ["blink", "Blink", "BLINK"];
|
|
30
|
+
break;
|
|
31
|
+
case "aa":
|
|
32
|
+
i = ["aa", "Aa", "a", "A", "AA", "mouth_a", "mouth_A"];
|
|
33
|
+
break;
|
|
34
|
+
case "ee":
|
|
35
|
+
i = ["ee", "Ee", "e", "E", "EE", "mouth_e", "mouth_E"];
|
|
36
|
+
break;
|
|
37
|
+
case "oo":
|
|
38
|
+
i = ["oh", "Oh", "oo", "Oo", "o", "O", "OO", "mouth_o", "mouth_O"];
|
|
39
|
+
break;
|
|
40
|
+
case "happy":
|
|
41
|
+
i = ["happy", "Happy", "joy", "Joy", "JOY", "fun", "Fun", "FUN", "HAPPY"];
|
|
42
|
+
break;
|
|
43
|
+
case "sad":
|
|
44
|
+
i = ["sad", "Sad", "sorrow", "Sorrow", "SORROW", "sadness", "SAD"];
|
|
45
|
+
break;
|
|
46
|
+
case "relaxed":
|
|
47
|
+
i = ["relaxed", "Relaxed", "fun", "Fun", "FUN", "neutral", "Neutral", "RELAXED"];
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
const E = i.find((g) => k[g] !== void 0 || U.includes(g));
|
|
51
|
+
if (E)
|
|
52
|
+
l.expressionManager.setValue(E, p);
|
|
53
|
+
else
|
|
54
|
+
try {
|
|
55
|
+
l.expressionManager.setValue(i[0], p);
|
|
56
|
+
} catch {
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function me({
|
|
60
|
+
url: l,
|
|
61
|
+
state: t,
|
|
62
|
+
analyser: p,
|
|
63
|
+
maxMouthOpening: k = 30,
|
|
64
|
+
mouseTrackingIntensity: U = 1,
|
|
65
|
+
blinkIntervalMin: i = 2e3,
|
|
66
|
+
blinkIntervalMax: E = 6e3,
|
|
67
|
+
blinkDuration: g = 100,
|
|
68
|
+
reducedMotion: L = !1,
|
|
69
|
+
onLoaded: O
|
|
70
|
+
}) {
|
|
71
|
+
const e = ie(se, l, (f) => {
|
|
72
|
+
f.register((h) => new ce(h));
|
|
73
|
+
}).userData.vrm;
|
|
74
|
+
C(() => {
|
|
75
|
+
var f, h;
|
|
76
|
+
if (e) {
|
|
77
|
+
O(!0), console.log(
|
|
78
|
+
"[VRM] Model loaded successfully. Available expressions:",
|
|
79
|
+
Object.keys(((f = e.expressionManager) == null ? void 0 : f.expressionMap) || {})
|
|
80
|
+
), e.scene.traverse((y) => {
|
|
81
|
+
y.frustumCulled = !1;
|
|
82
|
+
});
|
|
83
|
+
const o = ((h = e.meta) == null ? void 0 : h.metaVersion) === "0";
|
|
84
|
+
e.scene.rotation.y = o ? Math.PI : 0;
|
|
85
|
+
}
|
|
86
|
+
}, [e, O]);
|
|
87
|
+
const x = c(0), m = c(0), u = c(0), A = c(0), z = c(0), v = c(0), M = c(Math.random() * 3 + 2), b = c(0), V = c(!1), P = c(null), S = c(null);
|
|
88
|
+
return oe((f, h) => {
|
|
89
|
+
var D, _, H, K, Y, T, X, G, J;
|
|
90
|
+
if (!e) return;
|
|
91
|
+
e.update(h);
|
|
92
|
+
const o = (D = e.humanoid) == null ? void 0 : D.getNormalizedBoneNode("neck"), y = (_ = e.humanoid) == null ? void 0 : _.getNormalizedBoneNode("head");
|
|
93
|
+
if (((H = e.meta) == null ? void 0 : H.metaVersion) === "0") {
|
|
94
|
+
const s = (K = e.humanoid) == null ? void 0 : K.getNormalizedBoneNode("leftUpperArm"), N = (Y = e.humanoid) == null ? void 0 : Y.getNormalizedBoneNode("rightUpperArm");
|
|
95
|
+
s && (s.rotation.z = Math.PI / 2.6), N && (N.rotation.z = -Math.PI / 2.6);
|
|
96
|
+
}
|
|
97
|
+
const ee = ((T = f.pointer) == null ? void 0 : T.x) ?? ((X = f.mouse) == null ? void 0 : X.x) ?? 0, re = ((G = f.pointer) == null ? void 0 : G.y) ?? ((J = f.mouse) == null ? void 0 : J.y) ?? 0, B = L ? 0 : U, I = ee * 0.35 * B, F = -re * 0.2 * B;
|
|
98
|
+
if (o && (o.rotation.y = n.MathUtils.lerp(o.rotation.y, I, 0.1), o.rotation.x = n.MathUtils.lerp(o.rotation.x, F, 0.1)), y && (y.rotation.y = n.MathUtils.lerp(y.rotation.y, I * 0.2, 0.1), y.rotation.x = n.MathUtils.lerp(y.rotation.x, F * 0.2, 0.1)), !L)
|
|
99
|
+
if (!V.current)
|
|
100
|
+
M.current -= h, M.current <= 0 && (V.current = !0);
|
|
101
|
+
else {
|
|
102
|
+
const s = 1e3 / (g || 100);
|
|
103
|
+
b.current += h * s * 2, b.current >= 1 && (b.current = 1, V.current = !1, M.current = Math.random() * ((E - i) / 1e3) + i / 1e3);
|
|
104
|
+
}
|
|
105
|
+
if (!V.current && b.current > 0) {
|
|
106
|
+
const s = 1e3 / (g || 100);
|
|
107
|
+
b.current -= h * s * 2, b.current < 0 && (b.current = 0);
|
|
108
|
+
}
|
|
109
|
+
if (e.expressionManager) {
|
|
110
|
+
d(e, "blink", b.current);
|
|
111
|
+
let s = 0, N = 0, W = 0;
|
|
112
|
+
if (t === "listening" ? (s = 0.35, N = 0.2) : t === "thinking" ? (W = 0.25, N = 0.15, o && (o.rotation.y = n.MathUtils.lerp(o.rotation.y, -0.18, 0.05), o.rotation.x = n.MathUtils.lerp(o.rotation.x, 0.12, 0.05))) : t === "speaking" ? s = 0.15 : s = 0.05, A.current = n.MathUtils.lerp(A.current, s, 0.1), z.current = n.MathUtils.lerp(z.current, N, 0.1), v.current = n.MathUtils.lerp(v.current, W, 0.1), d(e, "happy", A.current), d(e, "relaxed", z.current), d(e, "sad", v.current), t === "speaking") {
|
|
113
|
+
(!P.current || S.current !== p) && (P.current = de(p), S.current = p);
|
|
114
|
+
const R = P.current.read(), j = k / 30;
|
|
115
|
+
let Z = 0, $ = 0, q = 0;
|
|
116
|
+
R.shape === "e" ? $ = R.level * 0.8 * j : R.shape === "o" ? q = R.level * 0.8 * j : R.shape === "a" && (Z = R.level * 0.95 * j), x.current = n.MathUtils.lerp(x.current, Z, 0.25), m.current = n.MathUtils.lerp(m.current, $, 0.25), u.current = n.MathUtils.lerp(u.current, q, 0.25), d(e, "aa", x.current), d(e, "ee", m.current), d(e, "oo", u.current);
|
|
117
|
+
} else
|
|
118
|
+
x.current = n.MathUtils.lerp(x.current, 0, 0.2), m.current = n.MathUtils.lerp(m.current, 0, 0.2), u.current = n.MathUtils.lerp(u.current, 0, 0.2), d(e, "aa", x.current), d(e, "ee", m.current), d(e, "oo", u.current);
|
|
119
|
+
e.expressionManager.update();
|
|
120
|
+
}
|
|
121
|
+
}), e ? /* @__PURE__ */ a("primitive", { object: e.scene }) : null;
|
|
122
|
+
}
|
|
123
|
+
function Ee({
|
|
124
|
+
state: l,
|
|
125
|
+
analyser: t,
|
|
126
|
+
size: p = 300,
|
|
127
|
+
className: k = "",
|
|
128
|
+
style: U,
|
|
129
|
+
maxMouthOpening: i,
|
|
130
|
+
blinkIntervalMin: E,
|
|
131
|
+
blinkIntervalMax: g,
|
|
132
|
+
blinkDuration: L,
|
|
133
|
+
mouseTrackingIntensity: O,
|
|
134
|
+
stateColors: r,
|
|
135
|
+
vrmUrl: e
|
|
136
|
+
}) {
|
|
137
|
+
const [x, m] = Q(!1), [u, A] = Q(null), z = ue();
|
|
138
|
+
C(() => {
|
|
139
|
+
m(!1), A(null);
|
|
140
|
+
}, [e]);
|
|
141
|
+
const v = {
|
|
142
|
+
idle: (r == null ? void 0 : r.idle) ?? "#4b5563",
|
|
143
|
+
listening: (r == null ? void 0 : r.listening) ?? "#3b82f6",
|
|
144
|
+
thinking: (r == null ? void 0 : r.thinking) ?? "#8b5cf6",
|
|
145
|
+
speaking: (r == null ? void 0 : r.speaking) ?? "#10b981",
|
|
146
|
+
working: (r == null ? void 0 : r.working) ?? "#f59e0b"
|
|
147
|
+
};
|
|
148
|
+
return /* @__PURE__ */ w(
|
|
149
|
+
"div",
|
|
150
|
+
{
|
|
151
|
+
className: `relative flex items-center justify-center rounded-3xl overflow-hidden border border-zinc-800/40 bg-zinc-950/40 ${k}`,
|
|
152
|
+
style: { width: p, height: p, ...U },
|
|
153
|
+
children: [
|
|
154
|
+
/* @__PURE__ */ w(
|
|
155
|
+
ae,
|
|
156
|
+
{
|
|
157
|
+
camera: { position: [0, 1.43, 0.88], fov: 44 },
|
|
158
|
+
shadows: !0,
|
|
159
|
+
gl: { antialias: !0, alpha: !0, preserveDrawingBuffer: !0 },
|
|
160
|
+
style: { width: "100%", height: "100%", background: "transparent" },
|
|
161
|
+
children: [
|
|
162
|
+
/* @__PURE__ */ a("ambientLight", { intensity: 1.5 }),
|
|
163
|
+
/* @__PURE__ */ a(
|
|
164
|
+
"spotLight",
|
|
165
|
+
{
|
|
166
|
+
position: [0, 3, 2],
|
|
167
|
+
angle: 0.6,
|
|
168
|
+
penumbra: 1,
|
|
169
|
+
intensity: 3,
|
|
170
|
+
color: v[l],
|
|
171
|
+
castShadow: !0
|
|
172
|
+
}
|
|
173
|
+
),
|
|
174
|
+
/* @__PURE__ */ a("directionalLight", { position: [-2, 2, -2], intensity: 1.8, color: "#ffffff" }),
|
|
175
|
+
/* @__PURE__ */ a("directionalLight", { position: [2, 2, 2], intensity: 2.2, color: "#ffffff" }),
|
|
176
|
+
/* @__PURE__ */ a(pe, { onError: (M) => A(M), children: e && /* @__PURE__ */ a(ne, { fallback: null, children: /* @__PURE__ */ a(
|
|
177
|
+
me,
|
|
178
|
+
{
|
|
179
|
+
url: e,
|
|
180
|
+
state: l,
|
|
181
|
+
analyser: t,
|
|
182
|
+
maxMouthOpening: i,
|
|
183
|
+
mouseTrackingIntensity: O,
|
|
184
|
+
blinkIntervalMin: E,
|
|
185
|
+
blinkIntervalMax: g,
|
|
186
|
+
blinkDuration: L,
|
|
187
|
+
reducedMotion: z,
|
|
188
|
+
onLoaded: (M) => m(M)
|
|
189
|
+
}
|
|
190
|
+
) }) }),
|
|
191
|
+
/* @__PURE__ */ a(
|
|
192
|
+
le,
|
|
193
|
+
{
|
|
194
|
+
enableZoom: !1,
|
|
195
|
+
enablePan: !1,
|
|
196
|
+
minPolarAngle: Math.PI / 2.6,
|
|
197
|
+
maxPolarAngle: Math.PI / 1.7,
|
|
198
|
+
minAzimuthAngle: -Math.PI / 4,
|
|
199
|
+
maxAzimuthAngle: Math.PI / 4,
|
|
200
|
+
target: [0, 1.38, 0]
|
|
201
|
+
}
|
|
202
|
+
)
|
|
203
|
+
]
|
|
204
|
+
}
|
|
205
|
+
),
|
|
206
|
+
!e && /* @__PURE__ */ w("div", { className: "absolute inset-0 flex flex-col items-center justify-center bg-zinc-950/90 backdrop-blur-md z-20 p-4 text-center", children: [
|
|
207
|
+
/* @__PURE__ */ a("span", { className: "text-xs font-mono font-bold text-amber-400 uppercase tracking-wider mb-2", children: "Missing vrmUrl" }),
|
|
208
|
+
/* @__PURE__ */ a("p", { className: "text-[10px] text-zinc-500 max-w-[200px] leading-relaxed", children: "Pass a CORS-enabled .vrm URL via the vrmUrl prop." })
|
|
209
|
+
] }),
|
|
210
|
+
e && !x && !u && /* @__PURE__ */ w("div", { className: "absolute inset-0 flex flex-col items-center justify-center bg-zinc-950/80 backdrop-blur-md z-20", children: [
|
|
211
|
+
/* @__PURE__ */ a("div", { className: "w-10 h-10 border-4 border-t-emerald-500 border-emerald-500/20 rounded-full animate-spin mb-3" }),
|
|
212
|
+
/* @__PURE__ */ a("span", { className: "text-[10px] font-mono font-bold tracking-widest text-zinc-400 animate-pulse", children: "LOADING NEURAL VRM MODEL..." })
|
|
213
|
+
] }),
|
|
214
|
+
u && /* @__PURE__ */ w("div", { className: "absolute inset-0 flex flex-col items-center justify-center bg-zinc-950/90 backdrop-blur-md z-20 p-4 text-center", children: [
|
|
215
|
+
/* @__PURE__ */ a("span", { className: "text-xs font-mono font-bold text-red-400 uppercase tracking-wider mb-2", children: "Failed to load VRM" }),
|
|
216
|
+
/* @__PURE__ */ a("p", { className: "text-[10px] text-zinc-500 max-w-[200px] leading-relaxed break-all", children: u })
|
|
217
|
+
] })
|
|
218
|
+
]
|
|
219
|
+
}
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
export {
|
|
223
|
+
Ee as VrmAvatar
|
|
224
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("react/jsx-runtime"),n=require("react"),P=require("@react-three/fiber"),te=require("three/addons/loaders/GLTFLoader.js"),re=require("@pixiv/three-vrm"),ne=require("@react-three/drei"),ae=require("three"),Q=require("./useReducedMotion-BRDEmRNI.cjs");function ie(a){const r=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(a){for(const o in a)if(o!=="default"){const p=Object.getOwnPropertyDescriptor(a,o);Object.defineProperty(r,o,p.get?p:{enumerable:!0,get:()=>a[o]})}}return r.default=a,Object.freeze(r)}const s=ie(ae);class se extends n.Component{constructor(r){super(r),this.state={hasError:!1}}static getDerivedStateFromError(){return{hasError:!0}}componentDidCatch(r){this.props.onError((r==null?void 0:r.message)||String(r))}render(){return this.state.hasError?null:this.props.children}}function f(a,r,o){if(!a.expressionManager)return;const p=a.expressionManager.expressionMap||{},N=Object.keys(p);let c=[];switch(r){case"blink":c=["blink","Blink","BLINK"];break;case"aa":c=["aa","Aa","a","A","AA","mouth_a","mouth_A"];break;case"ee":c=["ee","Ee","e","E","EE","mouth_e","mouth_E"];break;case"oo":c=["oh","Oh","oo","Oo","o","O","OO","mouth_o","mouth_O"];break;case"happy":c=["happy","Happy","joy","Joy","JOY","fun","Fun","FUN","HAPPY"];break;case"sad":c=["sad","Sad","sorrow","Sorrow","SORROW","sadness","SAD"];break;case"relaxed":c=["relaxed","Relaxed","fun","Fun","FUN","neutral","Neutral","RELAXED"];break}const R=c.find(g=>p[g]!==void 0||N.includes(g));if(R)a.expressionManager.setValue(R,o);else try{a.expressionManager.setValue(c[0],o)}catch{}}function oe({url:a,state:r,analyser:o,maxMouthOpening:p=30,mouseTrackingIntensity:N=1,blinkIntervalMin:c=2e3,blinkIntervalMax:R=6e3,blinkDuration:g=100,reducedMotion:U=!1,onLoaded:z}){const e=P.useLoader(te.GLTFLoader,a,m=>{m.register(x=>new re.VRMLoaderPlugin(x))}).userData.vrm;n.useEffect(()=>{var m,x;if(e){z(!0),console.log("[VRM] Model loaded successfully. Available expressions:",Object.keys(((m=e.expressionManager)==null?void 0:m.expressionMap)||{})),e.scene.traverse(j=>{j.frustumCulled=!1});const l=((x=e.meta)==null?void 0:x.metaVersion)==="0";e.scene.rotation.y=l?Math.PI:0}},[e,z]);const b=n.useRef(0),h=n.useRef(0),d=n.useRef(0),k=n.useRef(0),O=n.useRef(0),v=n.useRef(0),y=n.useRef(Math.random()*3+2),M=n.useRef(0),w=n.useRef(!1),L=n.useRef(null),S=n.useRef(null);return P.useFrame((m,x)=>{var F,I,q,T,H,K,Y,G,X;if(!e)return;e.update(x);const l=(F=e.humanoid)==null?void 0:F.getNormalizedBoneNode("neck"),j=(I=e.humanoid)==null?void 0:I.getNormalizedBoneNode("head");if(((q=e.meta)==null?void 0:q.metaVersion)==="0"){const u=(T=e.humanoid)==null?void 0:T.getNormalizedBoneNode("leftUpperArm"),E=(H=e.humanoid)==null?void 0:H.getNormalizedBoneNode("rightUpperArm");u&&(u.rotation.z=Math.PI/2.6),E&&(E.rotation.z=-Math.PI/2.6)}const C=((K=m.pointer)==null?void 0:K.x)??((Y=m.mouse)==null?void 0:Y.x)??0,ee=((G=m.pointer)==null?void 0:G.y)??((X=m.mouse)==null?void 0:X.y)??0,_=U?0:N,B=C*.35*_,D=-ee*.2*_;if(l&&(l.rotation.y=s.MathUtils.lerp(l.rotation.y,B,.1),l.rotation.x=s.MathUtils.lerp(l.rotation.x,D,.1)),j&&(j.rotation.y=s.MathUtils.lerp(j.rotation.y,B*.2,.1),j.rotation.x=s.MathUtils.lerp(j.rotation.x,D*.2,.1)),!U)if(!w.current)y.current-=x,y.current<=0&&(w.current=!0);else{const u=1e3/(g||100);M.current+=x*u*2,M.current>=1&&(M.current=1,w.current=!1,y.current=Math.random()*((R-c)/1e3)+c/1e3)}if(!w.current&&M.current>0){const u=1e3/(g||100);M.current-=x*u*2,M.current<0&&(M.current=0)}if(e.expressionManager){f(e,"blink",M.current);let u=0,E=0,J=0;if(r==="listening"?(u=.35,E=.2):r==="thinking"?(J=.25,E=.15,l&&(l.rotation.y=s.MathUtils.lerp(l.rotation.y,-.18,.05),l.rotation.x=s.MathUtils.lerp(l.rotation.x,.12,.05))):r==="speaking"?u=.15:u=.05,k.current=s.MathUtils.lerp(k.current,u,.1),O.current=s.MathUtils.lerp(O.current,E,.1),v.current=s.MathUtils.lerp(v.current,J,.1),f(e,"happy",k.current),f(e,"relaxed",O.current),f(e,"sad",v.current),r==="speaking"){(!L.current||S.current!==o)&&(L.current=Q.createMouthEngine(o),S.current=o);const A=L.current.read(),V=p/30;let W=0,Z=0,$=0;A.shape==="e"?Z=A.level*.8*V:A.shape==="o"?$=A.level*.8*V:A.shape==="a"&&(W=A.level*.95*V),b.current=s.MathUtils.lerp(b.current,W,.25),h.current=s.MathUtils.lerp(h.current,Z,.25),d.current=s.MathUtils.lerp(d.current,$,.25),f(e,"aa",b.current),f(e,"ee",h.current),f(e,"oo",d.current)}else b.current=s.MathUtils.lerp(b.current,0,.2),h.current=s.MathUtils.lerp(h.current,0,.2),d.current=s.MathUtils.lerp(d.current,0,.2),f(e,"aa",b.current),f(e,"ee",h.current),f(e,"oo",d.current);e.expressionManager.update()}}),e?t.jsx("primitive",{object:e.scene}):null}function ce({state:a,analyser:r,size:o=300,className:p="",style:N,maxMouthOpening:c,blinkIntervalMin:R,blinkIntervalMax:g,blinkDuration:U,mouseTrackingIntensity:z,stateColors:i,vrmUrl:e}){const[b,h]=n.useState(!1),[d,k]=n.useState(null),O=Q.useReducedMotion();n.useEffect(()=>{h(!1),k(null)},[e]);const v={idle:(i==null?void 0:i.idle)??"#4b5563",listening:(i==null?void 0:i.listening)??"#3b82f6",thinking:(i==null?void 0:i.thinking)??"#8b5cf6",speaking:(i==null?void 0:i.speaking)??"#10b981",working:(i==null?void 0:i.working)??"#f59e0b"};return t.jsxs("div",{className:`relative flex items-center justify-center rounded-3xl overflow-hidden border border-zinc-800/40 bg-zinc-950/40 ${p}`,style:{width:o,height:o,...N},children:[t.jsxs(P.Canvas,{camera:{position:[0,1.43,.88],fov:44},shadows:!0,gl:{antialias:!0,alpha:!0,preserveDrawingBuffer:!0},style:{width:"100%",height:"100%",background:"transparent"},children:[t.jsx("ambientLight",{intensity:1.5}),t.jsx("spotLight",{position:[0,3,2],angle:.6,penumbra:1,intensity:3,color:v[a],castShadow:!0}),t.jsx("directionalLight",{position:[-2,2,-2],intensity:1.8,color:"#ffffff"}),t.jsx("directionalLight",{position:[2,2,2],intensity:2.2,color:"#ffffff"}),t.jsx(se,{onError:y=>k(y),children:e&&t.jsx(n.Suspense,{fallback:null,children:t.jsx(oe,{url:e,state:a,analyser:r,maxMouthOpening:c,mouseTrackingIntensity:z,blinkIntervalMin:R,blinkIntervalMax:g,blinkDuration:U,reducedMotion:O,onLoaded:y=>h(y)})})}),t.jsx(ne.OrbitControls,{enableZoom:!1,enablePan:!1,minPolarAngle:Math.PI/2.6,maxPolarAngle:Math.PI/1.7,minAzimuthAngle:-Math.PI/4,maxAzimuthAngle:Math.PI/4,target:[0,1.38,0]})]}),!e&&t.jsxs("div",{className:"absolute inset-0 flex flex-col items-center justify-center bg-zinc-950/90 backdrop-blur-md z-20 p-4 text-center",children:[t.jsx("span",{className:"text-xs font-mono font-bold text-amber-400 uppercase tracking-wider mb-2",children:"Missing vrmUrl"}),t.jsx("p",{className:"text-[10px] text-zinc-500 max-w-[200px] leading-relaxed",children:"Pass a CORS-enabled .vrm URL via the vrmUrl prop."})]}),e&&!b&&!d&&t.jsxs("div",{className:"absolute inset-0 flex flex-col items-center justify-center bg-zinc-950/80 backdrop-blur-md z-20",children:[t.jsx("div",{className:"w-10 h-10 border-4 border-t-emerald-500 border-emerald-500/20 rounded-full animate-spin mb-3"}),t.jsx("span",{className:"text-[10px] font-mono font-bold tracking-widest text-zinc-400 animate-pulse",children:"LOADING NEURAL VRM MODEL..."})]}),d&&t.jsxs("div",{className:"absolute inset-0 flex flex-col items-center justify-center bg-zinc-950/90 backdrop-blur-md z-20 p-4 text-center",children:[t.jsx("span",{className:"text-xs font-mono font-bold text-red-400 uppercase tracking-wider mb-2",children:"Failed to load VRM"}),t.jsx("p",{className:"text-[10px] text-zinc-500 max-w-[200px] leading-relaxed break-all",children:d})]})]})}exports.VrmAvatar=ce;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { AvatarState } from '../lib/types';
|
|
3
|
+
export interface AudioVisualizerProps {
|
|
4
|
+
analyser: AnalyserNode | null;
|
|
5
|
+
state: AvatarState;
|
|
6
|
+
height?: number;
|
|
7
|
+
className?: string;
|
|
8
|
+
style?: React.CSSProperties;
|
|
9
|
+
stateColors?: {
|
|
10
|
+
idle?: string;
|
|
11
|
+
listening?: string;
|
|
12
|
+
thinking?: string;
|
|
13
|
+
speaking?: string;
|
|
14
|
+
working?: string;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export declare function AudioVisualizer({ analyser, state, height, className, style, stateColors }: AudioVisualizerProps): React.JSX.Element;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { AvatarState, StateColors } from '../lib/types';
|
|
3
|
+
import type { MouthSource } from '../lib/mouthEngine';
|
|
4
|
+
/**
|
|
5
|
+
* Wraps any SVG implementing the layer contract (`#rra-*` hooks) and runs
|
|
6
|
+
* the animation runtime over it. Used by the built-in contract presets
|
|
7
|
+
* (geometric, …) and by `variant="byos"` where the children are the
|
|
8
|
+
* developer's own SVG.
|
|
9
|
+
*/
|
|
10
|
+
export interface ContractAvatarProps {
|
|
11
|
+
state: AvatarState;
|
|
12
|
+
/** Mouth source: AnalyserNode (audio), SpeechActivitySource (text), or null. */
|
|
13
|
+
analyser: MouthSource;
|
|
14
|
+
size?: number;
|
|
15
|
+
className?: string;
|
|
16
|
+
style?: React.CSSProperties;
|
|
17
|
+
maxMouthOpening?: number;
|
|
18
|
+
mouseTrackingIntensity?: number;
|
|
19
|
+
blinkIntervalMin?: number;
|
|
20
|
+
blinkIntervalMax?: number;
|
|
21
|
+
blinkDuration?: number;
|
|
22
|
+
stateColors?: StateColors;
|
|
23
|
+
children: React.ReactNode;
|
|
24
|
+
}
|
|
25
|
+
export declare function ContractAvatar({ state, analyser, size, className, style, maxMouthOpening, mouseTrackingIntensity, blinkIntervalMin, blinkIntervalMax, blinkDuration, stateColors, children, }: ContractAvatarProps): React.JSX.Element;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { AvatarState } from '../lib/types';
|
|
3
|
+
import type { MouthSource } from '../lib/mouthEngine';
|
|
4
|
+
export interface AvatarCustomization {
|
|
5
|
+
skinColor: string;
|
|
6
|
+
hairColor: string;
|
|
7
|
+
clothingColor: string;
|
|
8
|
+
hoodieColor: string;
|
|
9
|
+
bgColor: string;
|
|
10
|
+
glasses: boolean;
|
|
11
|
+
glassesColor: string;
|
|
12
|
+
headphones: boolean;
|
|
13
|
+
headphonesColor: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function darkenColor(hex: string, percent: number): string;
|
|
16
|
+
export interface AvatarProps {
|
|
17
|
+
state: AvatarState;
|
|
18
|
+
/** Mouth source: AnalyserNode (audio), SpeechActivitySource (text), or null. */
|
|
19
|
+
analyser: MouthSource;
|
|
20
|
+
size?: number;
|
|
21
|
+
className?: string;
|
|
22
|
+
style?: React.CSSProperties;
|
|
23
|
+
maxMouthOpening?: number;
|
|
24
|
+
blinkIntervalMin?: number;
|
|
25
|
+
blinkIntervalMax?: number;
|
|
26
|
+
blinkDuration?: number;
|
|
27
|
+
mouseTrackingIntensity?: number;
|
|
28
|
+
stateColors?: {
|
|
29
|
+
idle?: string;
|
|
30
|
+
listening?: string;
|
|
31
|
+
thinking?: string;
|
|
32
|
+
speaking?: string;
|
|
33
|
+
working?: string;
|
|
34
|
+
};
|
|
35
|
+
customization?: AvatarCustomization;
|
|
36
|
+
}
|
|
37
|
+
export declare function DefaultAvatar({ state, analyser, size, className, style, maxMouthOpening, blinkIntervalMin, blinkIntervalMax, blinkDuration, stateColors, customization }: AvatarProps): React.JSX.Element;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { AvatarState, StateColors } from '../lib/types';
|
|
3
|
+
import { MouthSource } from '../lib/mouthEngine';
|
|
4
|
+
import { DiceBearCollection } from '../lib/dicebear';
|
|
5
|
+
/**
|
|
6
|
+
* DiceBearAvatar — renders a DiceBear (https://www.dicebear.com) avatar and
|
|
7
|
+
* makes it talk.
|
|
8
|
+
*
|
|
9
|
+
* Two animation strategies, picked per style:
|
|
10
|
+
*
|
|
11
|
+
* 1. **Viseme swapping** (styles with a face: pixel-art, lorelei, notionists,
|
|
12
|
+
* thumbs, open-peeps). DiceBear has no `#rra-*` hooks, but its option API
|
|
13
|
+
* lets us pick which mouth/eyes variant to render. So we pre-generate a few
|
|
14
|
+
* frames of the SAME avatar (same seed ⇒ identical hair/skin/etc.) with
|
|
15
|
+
* closed / mid / open mouths (+ optional blink) and swap which one is shown
|
|
16
|
+
* per audio frame. Real articulation, via the supported API — no fragile
|
|
17
|
+
* path heuristics. A subtle bounce rides on top for liveliness. The per-style
|
|
18
|
+
* variant choices live in `DICEBEAR_RIGS`.
|
|
19
|
+
*
|
|
20
|
+
* 2. **Audio-reactive bounce** — fallback for any non-rigged style id a host
|
|
21
|
+
* passes itself (e.g. a faceless abstract DiceBear style). The whole avatar
|
|
22
|
+
* squashes & lifts with amplitude. The curated catalog has none of these.
|
|
23
|
+
*
|
|
24
|
+
* Generation is client-side and lazy: `@dicebear/core` + `@dicebear/collection`
|
|
25
|
+
* are optional peer deps, dynamically imported only when this variant renders.
|
|
26
|
+
* Deterministic per `seed`, no network call. The curated catalog is CC0-only
|
|
27
|
+
* (see ../lib/dicebear.ts) so the library keeps its no-attribution promise.
|
|
28
|
+
*/
|
|
29
|
+
export interface DiceBearAvatarProps {
|
|
30
|
+
state: AvatarState;
|
|
31
|
+
/** Mouth source: AnalyserNode (audio), SpeechActivitySource (text), or null. */
|
|
32
|
+
analyser: MouthSource;
|
|
33
|
+
size?: number;
|
|
34
|
+
/** Curated CC0 style; any DiceBear style id also works at your own licensing discretion. */
|
|
35
|
+
collection?: DiceBearCollection | string;
|
|
36
|
+
/** Deterministic seed — same seed + style => same face. */
|
|
37
|
+
seed?: string;
|
|
38
|
+
/** DiceBear background colors (hex without `#`, e.g. ['b6e3f4']). */
|
|
39
|
+
backgroundColor?: string[];
|
|
40
|
+
/** DiceBear background corner radius, 0–50. */
|
|
41
|
+
radius?: number;
|
|
42
|
+
className?: string;
|
|
43
|
+
style?: React.CSSProperties;
|
|
44
|
+
/** Reused as bounce/mouth intensity (same slider as the SVG presets). */
|
|
45
|
+
maxMouthOpening?: number;
|
|
46
|
+
stateColors?: StateColors;
|
|
47
|
+
}
|
|
48
|
+
export declare function DiceBearAvatar({ state, analyser, size, collection, seed, backgroundColor, radius, className, style, maxMouthOpening, stateColors, }: DiceBearAvatarProps): React.JSX.Element;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { DiceBearCollection } from '../lib/dicebear';
|
|
2
|
+
/**
|
|
3
|
+
* Static, non-animated DiceBear face — a single SVG generated client-side for a
|
|
4
|
+
* given style + seed. Used by the face-picker gallery so users see the actual
|
|
5
|
+
* faces instead of guessing seed strings. Shares the lazy package load + module
|
|
6
|
+
* cache with `DiceBearAvatar` (see `loadDiceBear`), so a grid of thumbnails only
|
|
7
|
+
* pays for one package import.
|
|
8
|
+
*/
|
|
9
|
+
export interface DiceBearThumbProps {
|
|
10
|
+
collection: DiceBearCollection | string;
|
|
11
|
+
seed: string;
|
|
12
|
+
size?: number;
|
|
13
|
+
className?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function DiceBearThumb({ collection, seed, size, className }: DiceBearThumbProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { AvatarCustomization } from './DefaultAvatar';
|
|
3
|
+
import { AvatarState } from '../lib/types';
|
|
4
|
+
/**
|
|
5
|
+
* DoodleAvatar — hand-drawn ink-on-paper sketch style: wobbly outlines,
|
|
6
|
+
* scribbled hair, slightly imperfect strokes. The "imperfection" is drawn
|
|
7
|
+
* into the paths; the runtime adds the life (blink, gaze, mouth).
|
|
8
|
+
*
|
|
9
|
+
* Implements the layer contract (see useAvatarRuntime).
|
|
10
|
+
* License: MIT. Own design (no third-party assets).
|
|
11
|
+
*/
|
|
12
|
+
export interface DoodleAvatarProps {
|
|
13
|
+
size?: number;
|
|
14
|
+
customization?: Partial<AvatarCustomization>;
|
|
15
|
+
inkColor?: string;
|
|
16
|
+
/** Accepted for a uniform preset API; this head-only preset doesn't use it. */
|
|
17
|
+
state?: AvatarState;
|
|
18
|
+
className?: string;
|
|
19
|
+
style?: React.CSSProperties;
|
|
20
|
+
}
|
|
21
|
+
export declare function DoodleAvatar({ size, customization, inkColor, className, style, }: DoodleAvatarProps): React.JSX.Element;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { AvatarCustomization } from './DefaultAvatar';
|
|
3
|
+
import { AvatarState } from '../lib/types';
|
|
4
|
+
/**
|
|
5
|
+
* GeometricAvatar — minimalist geometric SVG avatar (head only).
|
|
6
|
+
*
|
|
7
|
+
* Purpose: the library's default preset AND the canonical example of the
|
|
8
|
+
* layer contract (see useAvatarRuntime). Purely presentational: it does not
|
|
9
|
+
* animate by itself — it exposes stable ids/classes the runtime drives.
|
|
10
|
+
*
|
|
11
|
+
* License: MIT. Own design (no third-party assets, no attribution needed).
|
|
12
|
+
*/
|
|
13
|
+
export interface GeometricAvatarProps {
|
|
14
|
+
size?: number;
|
|
15
|
+
customization?: Partial<AvatarCustomization>;
|
|
16
|
+
mouthColor?: string;
|
|
17
|
+
/** Accepted for a uniform preset API; this head-only preset doesn't use it. */
|
|
18
|
+
state?: AvatarState;
|
|
19
|
+
className?: string;
|
|
20
|
+
style?: React.CSSProperties;
|
|
21
|
+
}
|
|
22
|
+
export declare function GeometricAvatar({ size, customization, mouthColor, className, style, }: GeometricAvatarProps): React.JSX.Element;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { AvatarProps } from './DefaultAvatar';
|
|
3
|
+
export interface GlbArkitAvatarProps extends AvatarProps {
|
|
4
|
+
/** CORS-enabled .glb URL with ARKit blendshapes (e.g. a converted Rocketbox avatar). */
|
|
5
|
+
glbUrl?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function GlbArkitAvatar({ state, analyser, size, className, style, maxMouthOpening, blinkIntervalMin, blinkIntervalMax, blinkDuration, mouseTrackingIntensity, stateColors, glbUrl, }: GlbArkitAvatarProps): React.JSX.Element;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { AvatarCustomization } from './DefaultAvatar';
|
|
3
|
+
import { AvatarState } from '../lib/types';
|
|
4
|
+
/**
|
|
5
|
+
* MemojiAvatar — soft, volumetric SVG head in the spirit of Apple's memoji:
|
|
6
|
+
* radial gradients for skin volume, glossy eyes with highlights, blush.
|
|
7
|
+
*
|
|
8
|
+
* Implements the layer contract (see useAvatarRuntime).
|
|
9
|
+
* License: MIT. Own design (no third-party assets).
|
|
10
|
+
*/
|
|
11
|
+
export interface MemojiAvatarProps {
|
|
12
|
+
size?: number;
|
|
13
|
+
customization?: Partial<AvatarCustomization>;
|
|
14
|
+
/** Accepted for a uniform preset API; this head-only preset doesn't use it. */
|
|
15
|
+
state?: AvatarState;
|
|
16
|
+
className?: string;
|
|
17
|
+
style?: React.CSSProperties;
|
|
18
|
+
}
|
|
19
|
+
export declare function MemojiAvatar({ size, customization, className, style, }: MemojiAvatarProps): React.JSX.Element;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { AvatarCustomization } from './DefaultAvatar';
|
|
3
|
+
import { AvatarState } from '../lib/types';
|
|
4
|
+
/**
|
|
5
|
+
* PixelArtAvatar — retro avatar on a logical 32x32 grid.
|
|
6
|
+
*
|
|
7
|
+
* Everything renders with crisp edges, and motion is intentionally chunky:
|
|
8
|
+
* the runtime snaps the mouth and pupils to whole pixels (`data-quantize`),
|
|
9
|
+
* and the eyelids close in two frames worth of pixels. That quantized look
|
|
10
|
+
* IS the aesthetic.
|
|
11
|
+
*
|
|
12
|
+
* Implements the layer contract (see useAvatarRuntime).
|
|
13
|
+
* License: MIT. Own design (no third-party assets).
|
|
14
|
+
*/
|
|
15
|
+
export interface PixelArtAvatarProps {
|
|
16
|
+
size?: number;
|
|
17
|
+
customization?: Partial<AvatarCustomization>;
|
|
18
|
+
/** Accepted for a uniform preset API; this head-only preset doesn't use it. */
|
|
19
|
+
state?: AvatarState;
|
|
20
|
+
className?: string;
|
|
21
|
+
style?: React.CSSProperties;
|
|
22
|
+
}
|
|
23
|
+
export declare function PixelArtAvatar({ size, customization, className, style, }: PixelArtAvatarProps): React.JSX.Element;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { AvatarCustomization } from './DefaultAvatar';
|
|
3
|
+
import { AvatarState } from '../lib/types';
|
|
4
|
+
import type { SpeechActivitySource } from '../lib/speechActivity';
|
|
5
|
+
import type { DiceBearCollection } from '../lib/dicebear';
|
|
6
|
+
export interface RealtimeAvatarProps {
|
|
7
|
+
state: AvatarState;
|
|
8
|
+
/**
|
|
9
|
+
* WebAudio AnalyserNode for the audio-reactive mouth (voice pipelines).
|
|
10
|
+
* Optional: omit it (or pass `null`) and `speaking` falls back to a
|
|
11
|
+
* synthetic speech-like pattern — so the minimal usage is just
|
|
12
|
+
* `<RealtimeAvatar state={state} />`.
|
|
13
|
+
*/
|
|
14
|
+
analyser?: AnalyserNode | null;
|
|
15
|
+
/**
|
|
16
|
+
* Token-rate mouth driver for text-streaming LLMs (OpenAI-style
|
|
17
|
+
* `/chat/completions` or `/responses` with `stream: true`). Create one with
|
|
18
|
+
* `createSpeechActivity()` and `push()` each streamed chunk. When provided,
|
|
19
|
+
* it drives the mouth instead of `analyser` — so a text-only assistant still
|
|
20
|
+
* gets a face that tracks the stream. See `createSpeechActivity`.
|
|
21
|
+
*/
|
|
22
|
+
speechActivity?: SpeechActivitySource;
|
|
23
|
+
/**
|
|
24
|
+
* Declarative mouth driver for text-streaming chats. Pass the *accumulated*
|
|
25
|
+
* assistant text (the kind a hook like the Vercel AI SDK's `useChat` hands
|
|
26
|
+
* you — it grows each render); the avatar diffs its growth internally and
|
|
27
|
+
* drives the mouth from token cadence. No `createSpeechActivity`, no reader
|
|
28
|
+
* loop. Ignored when `speechActivity` is set; takes precedence over
|
|
29
|
+
* `analyser`. See `useStreamingTextActivity`.
|
|
30
|
+
*/
|
|
31
|
+
streamingText?: string;
|
|
32
|
+
size?: number;
|
|
33
|
+
variant?: 'geometric' | 'memoji' | 'pixelart' | 'doodle' | 'vrm' | 'glb' | 'dicebear' | 'byos';
|
|
34
|
+
/** Your own contract-compliant SVG, rendered when variant="byos". */
|
|
35
|
+
children?: React.ReactNode;
|
|
36
|
+
vrmUrl?: string;
|
|
37
|
+
/** CORS-enabled .glb URL with ARKit blendshapes, for variant="glb". */
|
|
38
|
+
glbUrl?: string;
|
|
39
|
+
/** DiceBear style id (curated CC0 set), for variant="dicebear". */
|
|
40
|
+
dicebearCollection?: DiceBearCollection | string;
|
|
41
|
+
/** Deterministic DiceBear seed, for variant="dicebear". */
|
|
42
|
+
dicebearSeed?: string;
|
|
43
|
+
subtitle?: string;
|
|
44
|
+
thought?: string;
|
|
45
|
+
tool?: string;
|
|
46
|
+
/** HUD satellites — all on by default; set false to hide individually. */
|
|
47
|
+
showGlow?: boolean;
|
|
48
|
+
showStatePill?: boolean;
|
|
49
|
+
showThought?: boolean;
|
|
50
|
+
showSubtitle?: boolean;
|
|
51
|
+
className?: string;
|
|
52
|
+
style?: React.CSSProperties;
|
|
53
|
+
maxMouthOpening?: number;
|
|
54
|
+
blinkIntervalMin?: number;
|
|
55
|
+
blinkIntervalMax?: number;
|
|
56
|
+
blinkDuration?: number;
|
|
57
|
+
mouseTrackingIntensity?: number;
|
|
58
|
+
stateColors?: {
|
|
59
|
+
idle?: string;
|
|
60
|
+
listening?: string;
|
|
61
|
+
thinking?: string;
|
|
62
|
+
speaking?: string;
|
|
63
|
+
working?: string;
|
|
64
|
+
};
|
|
65
|
+
stateLabels?: {
|
|
66
|
+
idle?: string;
|
|
67
|
+
listening?: string;
|
|
68
|
+
thinking?: string;
|
|
69
|
+
speaking?: string;
|
|
70
|
+
working?: string;
|
|
71
|
+
};
|
|
72
|
+
customization?: AvatarCustomization;
|
|
73
|
+
}
|
|
74
|
+
export declare function RealtimeAvatar({ state, analyser, speechActivity, streamingText, size, variant, children, vrmUrl, glbUrl, subtitle, thought, tool, showGlow, showStatePill, showThought, showSubtitle, className, style, dicebearCollection, dicebearSeed, maxMouthOpening, blinkIntervalMin, blinkIntervalMax, blinkDuration, mouseTrackingIntensity, stateColors, stateLabels, customization }: RealtimeAvatarProps): React.JSX.Element;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { AvatarCustomization } from './DefaultAvatar';
|
|
3
|
+
/**
|
|
4
|
+
* SquirrelAvatar — a full branded character (red-squirrel developer) drawn as a
|
|
5
|
+
* flat-vector face: tufted ears, bushy tail, round glasses, brown quiff, hoodie +
|
|
6
|
+
* circuit tee, and a neck bridging head and body. Own design (MIT, no third-party
|
|
7
|
+
* assets).
|
|
8
|
+
*
|
|
9
|
+
* It implements the layer contract (see useAvatarRuntime) exactly like the built-in
|
|
10
|
+
* presets, so the runtime drives blink / gaze / mouth for free. No state ring —
|
|
11
|
+
* matches the other presets, which dropped theirs. The fur color is reused for BOTH
|
|
12
|
+
* eyelids on purpose — recolor it and a blink still reads as the face coming down
|
|
13
|
+
* over the eye.
|
|
14
|
+
*
|
|
15
|
+
* In the demo it's rendered through `variant="byos"`; it's also the worked example
|
|
16
|
+
* behind the `rra-character-avatar` skill.
|
|
17
|
+
*/
|
|
18
|
+
import type { AvatarState } from '../lib/types';
|
|
19
|
+
export interface SquirrelAvatarProps {
|
|
20
|
+
/** SVG width/height. Defaults to `'100%'` so the squirrel fills its (sized)
|
|
21
|
+
* container — e.g. the box `ContractAvatar`/`RealtimeAvatar` already reserves.
|
|
22
|
+
* Pass a number for a fixed pixel size. */
|
|
23
|
+
size?: number | string;
|
|
24
|
+
customization?: Partial<AvatarCustomization>;
|
|
25
|
+
state?: AvatarState;
|
|
26
|
+
className?: string;
|
|
27
|
+
style?: React.CSSProperties;
|
|
28
|
+
}
|
|
29
|
+
export declare function SquirrelAvatar({ size, customization, state, className, style, }: SquirrelAvatarProps): React.JSX.Element;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { AvatarProps } from './DefaultAvatar';
|
|
3
|
+
export interface VrmAvatarProps extends AvatarProps {
|
|
4
|
+
vrmUrl?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function VrmAvatar({ state, analyser, size, className, style, maxMouthOpening, blinkIntervalMin, blinkIntervalMax, blinkDuration, mouseTrackingIntensity, stateColors, vrmUrl, }: VrmAvatarProps): React.JSX.Element;
|