@gui-chat-plugin/avatar 0.0.1
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/README.md +98 -0
- package/dist/core/definition.d.ts +9 -0
- package/dist/core/index.d.ts +10 -0
- package/dist/core/plugin.d.ts +10 -0
- package/dist/core/samples.d.ts +5 -0
- package/dist/core/types.d.ts +24 -0
- package/dist/core.cjs +1 -0
- package/dist/core.js +72 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +9 -0
- package/dist/react/Preview.d.ts +9 -0
- package/dist/react/View.d.ts +9 -0
- package/dist/react/index.d.ts +24 -0
- package/dist/react.cjs +6 -0
- package/dist/react.js +387 -0
- package/dist/style.css +1 -0
- package/dist/three-vrm.module-DJ7DURJm.js +27282 -0
- package/dist/three-vrm.module-FTOSkzpf.cjs +4752 -0
- package/dist/vue/Preview.vue.d.ts +7 -0
- package/dist/vue/View.vue.d.ts +9 -0
- package/dist/vue/index.d.ts +24 -0
- package/dist/vue.cjs +1 -0
- package/dist/vue.js +207 -0
- package/package.json +98 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ToolResult } from "gui-chat-protocol";
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
result: ToolResult;
|
|
4
|
+
};
|
|
5
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
6
|
+
declare const _default: typeof __VLS_export;
|
|
7
|
+
export default _default;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ToolResult } from "gui-chat-protocol";
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
selectedResult: ToolResult;
|
|
4
|
+
sendTextMessage: (text?: string) => void;
|
|
5
|
+
isAudioPlaying?: boolean;
|
|
6
|
+
};
|
|
7
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
8
|
+
declare const _default: typeof __VLS_export;
|
|
9
|
+
export default _default;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Avatar Plugin - Vue Implementation
|
|
3
|
+
*
|
|
4
|
+
* Full Vue plugin with UI components.
|
|
5
|
+
* Import from "@gui-chat-plugin/avatar/vue"
|
|
6
|
+
*/
|
|
7
|
+
import "../style.css";
|
|
8
|
+
import type { ToolPlugin } from "gui-chat-protocol/vue";
|
|
9
|
+
import type { AvatarData, AvatarArgs } from "../core/types";
|
|
10
|
+
import View from "./View.vue";
|
|
11
|
+
import Preview from "./Preview.vue";
|
|
12
|
+
/**
|
|
13
|
+
* Avatar plugin instance with Vue components
|
|
14
|
+
*/
|
|
15
|
+
export declare const plugin: ToolPlugin<AvatarData, never, AvatarArgs>;
|
|
16
|
+
export type { AvatarEmotion, AvatarData, AvatarArgs } from "../core/types";
|
|
17
|
+
export { pluginCore, executeAvatar } from "../core/plugin";
|
|
18
|
+
export { TOOL_NAME, TOOL_DEFINITION } from "../core/definition";
|
|
19
|
+
export { SAMPLES } from "../core/samples";
|
|
20
|
+
export { View, Preview };
|
|
21
|
+
declare const _default: {
|
|
22
|
+
plugin: ToolPlugin<AvatarData, never, AvatarArgs, import("gui-chat-protocol/vue").InputHandler, Record<string, unknown>>;
|
|
23
|
+
};
|
|
24
|
+
export default _default;
|
package/dist/vue.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const a=require("./three-vrm.module-FTOSkzpf.cjs"),z=require("./core.cjs"),o=require("vue"),q={class:"size-full bg-gradient-to-b from-slate-800 to-slate-900 relative"},H={key:0,class:"absolute inset-0 flex items-center justify-center bg-slate-900/80"},G={key:1,class:"absolute inset-0 flex items-center justify-center bg-slate-900/80"},W={class:"text-red-400 text-lg text-center p-4"},J={key:2,class:"absolute top-4 right-4 px-3 py-1 bg-green-600 text-white text-sm rounded-full"},T=o.defineComponent({__name:"View",props:{selectedResult:{},sendTextMessage:{type:Function},isAudioPlaying:{type:Boolean}},setup(V){const v=V,p=o.ref(null),M=o.ref(!1),E=o.ref(null);let r=null,N=null,l=null,t=null,y=null,w=null,k=0,b="neutral",P="none",S=0,_=0,L="";const F={neutral:null,happy:a.VRMExpressionPresetName.Happy,sad:a.VRMExpressionPresetName.Sad,angry:a.VRMExpressionPresetName.Angry,surprised:a.VRMExpressionPresetName.Surprised};function j(){if(!p.value)return;const n=p.value,e=n.clientWidth,B=n.clientHeight;r=new a.Scene,N=new a.PerspectiveCamera(30,e/B,.1,100),N.position.set(0,1.3,1.5),N.lookAt(0,1.2,0),l=new a.WebGLRenderer({antialias:!0,alpha:!0}),l.setSize(e,B),l.setPixelRatio(window.devicePixelRatio),l.outputColorSpace=a.SRGBColorSpace,n.appendChild(l.domElement);const h=new a.AmbientLight(16777215,.6);r.add(h);const d=new a.DirectionalLight(16777215,.8);d.position.set(1,1,1),r.add(d),y=new a.Clock,window.addEventListener("resize",D),C()}function D(){if(!p.value||!N||!l)return;const n=p.value.clientWidth,e=p.value.clientHeight;N.aspect=n/e,N.updateProjectionMatrix(),l.setSize(n,e)}async function U(n){if(r){M.value=!0,E.value=null,t&&(r.remove(t.scene),t=null);try{const e=new a.GLTFLoader;e.register(d=>new a.VRMLoaderPlugin(d));const h=(await e.loadAsync(n)).userData.vrm;if(!h)throw new Error("Failed to load VRM data");r.add(h.scene),t=h,console.log("[Avatar Debug] VRM loaded successfully"),console.log("[Avatar Debug] VRM humanoid:",!!h.humanoid),console.log("[Avatar Debug] VRM expressionManager:",!!h.expressionManager),M.value=!1}catch(e){console.error("Failed to load VRM:",e),E.value=`Failed to load avatar: ${e instanceof Error?e.message:"Unknown error"}`,M.value=!1}}}let R=0;function C(){if(w=requestAnimationFrame(C),!y||!l||!r||!N)return;const n=y.getDelta(),e=y.getElapsedTime();if(R++,R%300===0&&console.log("[Avatar Debug] animate() running, frame:",R,"currentVrm:",!!t,"isAudioPlaying:",v.isAudioPlaying),t){if(t.update(n),v.isAudioPlaying){k+=n*10;const d=(Math.sin(k)+1)*.3;t.expressionManager?.setValue(a.VRMExpressionPresetName.Aa,d);const m=t.humanoid?.getNormalizedBoneNode("head"),c=t.humanoid?.getNormalizedBoneNode("neck"),i=t.humanoid?.getNormalizedBoneNode("spine");k<.2&&console.log("[Avatar Debug] Body animation - Bones found:",{head:!!m,neck:!!c,spine:!!i,humanoid:!!t.humanoid}),m&&(m.rotation.x=Math.sin(e*2)*.08,m.rotation.z=Math.sin(e*1.5)*.05),c&&(c.rotation.y=Math.sin(e*.8)*.05),i&&(i.rotation.z=Math.sin(e*.5)*.03);const s=t.humanoid?.getNormalizedBoneNode("leftShoulder"),g=t.humanoid?.getNormalizedBoneNode("rightShoulder"),f=t.humanoid?.getNormalizedBoneNode("leftUpperArm"),x=t.humanoid?.getNormalizedBoneNode("rightUpperArm"),u=t.humanoid?.getNormalizedBoneNode("leftLowerArm"),A=t.humanoid?.getNormalizedBoneNode("rightLowerArm");s&&(s.rotation.z=.1),g&&(g.rotation.z=-.1),f&&(f.rotation.z=-.8+Math.sin(e*1.2)*.1,f.rotation.x=.4+Math.sin(e*.9)*.15,f.rotation.y=Math.sin(e*.7)*.1),x&&(x.rotation.z=.8+Math.sin(e*1.3)*.1,x.rotation.x=.4+Math.sin(e*1)*.15,x.rotation.y=Math.sin(e*.8)*.1),u&&(u.rotation.y=-1-Math.sin(e*1.5)*.2,u.rotation.z=Math.sin(e*1.1)*.1),A&&(A.rotation.y=1+Math.sin(e*1.4)*.2,A.rotation.z=Math.sin(e*1.2)*.1)}else{k=0,t.expressionManager?.setValue(a.VRMExpressionPresetName.Aa,0);const d=t.humanoid?.getNormalizedBoneNode("spine"),m=t.humanoid?.getNormalizedBoneNode("head");Math.floor(e)%5===0&&e-Math.floor(e)<n&&console.log("[Avatar Debug] Idle animation - Bones found:",{head:!!m,neck:!!t.humanoid?.getNormalizedBoneNode("neck"),spine:!!d}),d&&(d.rotation.x=Math.sin(e*.8)*.02),m&&(m.rotation.x=Math.sin(e*.3)*.03,m.rotation.z=Math.sin(e*.2)*.02);const c=t.humanoid?.getNormalizedBoneNode("leftShoulder"),i=t.humanoid?.getNormalizedBoneNode("rightShoulder"),s=t.humanoid?.getNormalizedBoneNode("leftUpperArm"),g=t.humanoid?.getNormalizedBoneNode("rightUpperArm"),f=t.humanoid?.getNormalizedBoneNode("leftLowerArm"),x=t.humanoid?.getNormalizedBoneNode("rightLowerArm");c&&(c.rotation.z=.1),i&&(i.rotation.z=-.1),s&&(s.rotation.z=-.9,s.rotation.x=.2,s.rotation.y=0),g&&(g.rotation.z=.9,g.rotation.x=.2,g.rotation.y=0),f&&(f.rotation.y=-.8),x&&(x.rotation.y=.8)}e%4<.1?t.expressionManager?.setValue(a.VRMExpressionPresetName.Blink,1):t.expressionManager?.setValue(a.VRMExpressionPresetName.Blink,0);const h=F[b];if(t.expressionManager?.setValue(a.VRMExpressionPresetName.Happy,0),t.expressionManager?.setValue(a.VRMExpressionPresetName.Sad,0),t.expressionManager?.setValue(a.VRMExpressionPresetName.Angry,0),t.expressionManager?.setValue(a.VRMExpressionPresetName.Surprised,0),h&&t.expressionManager?.setValue(h,.8),P!=="none"){const d=e-S,m=1.5;if(d<m){const c=d/m,i=t.humanoid?.getNormalizedBoneNode("head"),s=t.humanoid?.getNormalizedBoneNode("rightUpperArm"),g=t.humanoid?.getNormalizedBoneNode("rightLowerArm"),f=t.humanoid?.getNormalizedBoneNode("spine"),u=(A=>A<.5?2*A*A:1-Math.pow(-2*A+2,2)/2)(c<.5?c*2:(1-c)*2);switch(P){case"nod":i&&(i.rotation.x=Math.sin(c*Math.PI*3)*.2);break;case"shake":i&&(i.rotation.y=Math.sin(c*Math.PI*4)*.3);break;case"wave":s&&(s.rotation.z=1.5*u,s.rotation.x=-.3*u),g&&(g.rotation.y=.5+Math.sin(c*Math.PI*6)*.3);break;case"think":i&&(i.rotation.x=.1*u,i.rotation.z=.1*u),s&&(s.rotation.z=.3*u,s.rotation.x=.8*u),g&&(g.rotation.y=1.5*u);break;case"bow":f&&(f.rotation.x=.4*u),i&&(i.rotation.x=.2*u);break}}else P="none"}}l.render(r,N)}function $(){w!==null&&(cancelAnimationFrame(w),w=null),window.removeEventListener("resize",D),l&&p.value&&(p.value.removeChild(l.domElement),l.dispose(),l=null),t&&(t=null),r=null,N=null,y=null}return o.watch(()=>v.selectedResult,n=>{if(n?.toolName===z.TOOL_NAME&&n.data){const e=n.data;if(e.avatarUrl&&e.avatarUrl!==L&&(console.log("[Avatar Debug] VRM URL changed:",e.avatarUrl),L=e.avatarUrl,U(e.avatarUrl)),e.emotion&&e.emotion!==b&&(console.log("[Avatar Debug] Emotion changed to:",e.emotion),b=e.emotion),e.action&&e.action!=="none"){const B=e.actionTimestamp||0;B>_&&(console.log("[Avatar Debug] Action triggered:",e.action),P=e.action,S=y?.getElapsedTime()||0,_=B)}}},{deep:!0}),o.watch(()=>v.isAudioPlaying,n=>{console.log("[Avatar Debug] Plugin received isAudioPlaying:",n)}),o.onMounted(()=>{if(console.log("[Avatar Debug] View component MOUNTED"),j(),v.selectedResult?.toolName===z.TOOL_NAME&&v.selectedResult.data){const n=v.selectedResult.data;n.avatarUrl&&(console.log("[Avatar Debug] Initial VRM load:",n.avatarUrl),L=n.avatarUrl,U(n.avatarUrl)),n.emotion&&(b=n.emotion)}}),o.onUnmounted(()=>{$()}),(n,e)=>(o.openBlock(),o.createElementBlock("div",q,[o.createElementVNode("div",{ref_key:"containerRef",ref:p,class:"size-full"},null,512),M.value?(o.openBlock(),o.createElementBlock("div",H,[...e[0]||(e[0]=[o.createElementVNode("div",{class:"text-white text-lg"},"Loading Avatar...",-1)])])):o.createCommentVNode("",!0),E.value?(o.openBlock(),o.createElementBlock("div",G,[o.createElementVNode("div",W,o.toDisplayString(E.value),1)])):o.createCommentVNode("",!0),V.isAudioPlaying?(o.openBlock(),o.createElementBlock("div",J," Speaking... ")):o.createCommentVNode("",!0)]))}}),K={class:"p-3 bg-gradient-to-br from-slate-700 to-slate-800 rounded-md"},Q={class:"flex flex-col items-center gap-2"},X={key:0,class:"text-xs px-2 py-0.5 bg-blue-500 text-white rounded-full"},O=o.defineComponent({__name:"Preview",props:{result:{}},setup(V){const v=V,p=o.computed(()=>v.result.data),M=o.computed(()=>p.value?.emotion||"neutral");return(E,r)=>(o.openBlock(),o.createElementBlock("div",K,[o.createElementVNode("div",Q,[r[0]||(r[0]=o.createElementVNode("div",{class:"size-12 bg-slate-600 rounded-full flex items-center justify-center"},[o.createElementVNode("svg",{class:"size-8 text-slate-300",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[o.createElementVNode("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"})])],-1)),r[1]||(r[1]=o.createElementVNode("div",{class:"text-sm font-semibold text-white text-center"}," 3D Avatar ",-1)),M.value&&M.value!=="neutral"?(o.openBlock(),o.createElementBlock("div",X,o.toDisplayString(M.value),1)):o.createCommentVNode("",!0)])]))}}),I={...z.pluginCore,viewComponent:T,previewComponent:O},Y={plugin:I};exports.SAMPLES=z.SAMPLES;exports.TOOL_DEFINITION=z.TOOL_DEFINITION;exports.TOOL_NAME=z.TOOL_NAME;exports.executeAvatar=z.executeAvatar;exports.pluginCore=z.pluginCore;exports.Preview=O;exports.View=T;exports.default=Y;exports.plugin=I;
|
package/dist/vue.js
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { S as K, P as Q, W as X, a as Y, A as Z, D as ee, G as te, V as oe, b as m, C as ne } from "./three-vrm.module-DJ7DURJm.js";
|
|
2
|
+
import { TOOL_NAME as O, pluginCore as ae } from "./core.js";
|
|
3
|
+
import { SAMPLES as ye, TOOL_DEFINITION as Be, executeAvatar as be } from "./core.js";
|
|
4
|
+
import { defineComponent as G, ref as R, watch as j, onMounted as ie, onUnmounted as re, openBlock as y, createElementBlock as B, createElementVNode as N, createCommentVNode as U, toDisplayString as H, computed as $ } from "vue";
|
|
5
|
+
const se = { class: "size-full bg-gradient-to-b from-slate-800 to-slate-900 relative" }, le = {
|
|
6
|
+
key: 0,
|
|
7
|
+
class: "absolute inset-0 flex items-center justify-center bg-slate-900/80"
|
|
8
|
+
}, de = {
|
|
9
|
+
key: 1,
|
|
10
|
+
class: "absolute inset-0 flex items-center justify-center bg-slate-900/80"
|
|
11
|
+
}, ce = { class: "text-red-400 text-lg text-center p-4" }, ue = {
|
|
12
|
+
key: 2,
|
|
13
|
+
class: "absolute top-4 right-4 px-3 py-1 bg-green-600 text-white text-sm rounded-full"
|
|
14
|
+
}, me = /* @__PURE__ */ G({
|
|
15
|
+
__name: "View",
|
|
16
|
+
props: {
|
|
17
|
+
selectedResult: {},
|
|
18
|
+
sendTextMessage: { type: Function },
|
|
19
|
+
isAudioPlaying: { type: Boolean }
|
|
20
|
+
},
|
|
21
|
+
setup(k) {
|
|
22
|
+
const f = k, g = R(null), x = R(!1), b = R(null);
|
|
23
|
+
let a = null, v = null, r = null, t = null, w = null, L = null, V = 0, S = "neutral", D = "none", E = 0, C = 0, _ = "";
|
|
24
|
+
const W = {
|
|
25
|
+
neutral: null,
|
|
26
|
+
happy: m.Happy,
|
|
27
|
+
sad: m.Sad,
|
|
28
|
+
angry: m.Angry,
|
|
29
|
+
surprised: m.Surprised
|
|
30
|
+
};
|
|
31
|
+
function q() {
|
|
32
|
+
if (!g.value) return;
|
|
33
|
+
const o = g.value, e = o.clientWidth, z = o.clientHeight;
|
|
34
|
+
a = new K(), v = new Q(30, e / z, 0.1, 100), v.position.set(0, 1.3, 1.5), v.lookAt(0, 1.2, 0), r = new X({ antialias: !0, alpha: !0 }), r.setSize(e, z), r.setPixelRatio(window.devicePixelRatio), r.outputColorSpace = Y, o.appendChild(r.domElement);
|
|
35
|
+
const h = new Z(16777215, 0.6);
|
|
36
|
+
a.add(h);
|
|
37
|
+
const s = new ee(16777215, 0.8);
|
|
38
|
+
s.position.set(1, 1, 1), a.add(s), w = new ne(), window.addEventListener("resize", T), I();
|
|
39
|
+
}
|
|
40
|
+
function T() {
|
|
41
|
+
if (!g.value || !v || !r) return;
|
|
42
|
+
const o = g.value.clientWidth, e = g.value.clientHeight;
|
|
43
|
+
v.aspect = o / e, v.updateProjectionMatrix(), r.setSize(o, e);
|
|
44
|
+
}
|
|
45
|
+
async function F(o) {
|
|
46
|
+
if (a) {
|
|
47
|
+
x.value = !0, b.value = null, t && (a.remove(t.scene), t = null);
|
|
48
|
+
try {
|
|
49
|
+
const e = new te();
|
|
50
|
+
e.register((s) => new oe(s));
|
|
51
|
+
const h = (await e.loadAsync(o)).userData.vrm;
|
|
52
|
+
if (!h)
|
|
53
|
+
throw new Error("Failed to load VRM data");
|
|
54
|
+
a.add(h.scene), t = h, console.log("[Avatar Debug] VRM loaded successfully"), console.log("[Avatar Debug] VRM humanoid:", !!h.humanoid), console.log("[Avatar Debug] VRM expressionManager:", !!h.expressionManager), x.value = !1;
|
|
55
|
+
} catch (e) {
|
|
56
|
+
console.error("Failed to load VRM:", e), b.value = `Failed to load avatar: ${e instanceof Error ? e.message : "Unknown error"}`, x.value = !1;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
let P = 0;
|
|
61
|
+
function I() {
|
|
62
|
+
if (L = requestAnimationFrame(I), !w || !r || !a || !v) return;
|
|
63
|
+
const o = w.getDelta(), e = w.getElapsedTime();
|
|
64
|
+
if (P++, P % 300 === 0 && console.log("[Avatar Debug] animate() running, frame:", P, "currentVrm:", !!t, "isAudioPlaying:", f.isAudioPlaying), t) {
|
|
65
|
+
if (t.update(o), f.isAudioPlaying) {
|
|
66
|
+
V += o * 10;
|
|
67
|
+
const s = (Math.sin(V) + 1) * 0.3;
|
|
68
|
+
t.expressionManager?.setValue(m.Aa, s);
|
|
69
|
+
const c = t.humanoid?.getNormalizedBoneNode("head"), l = t.humanoid?.getNormalizedBoneNode("neck"), n = t.humanoid?.getNormalizedBoneNode("spine");
|
|
70
|
+
V < 0.2 && console.log("[Avatar Debug] Body animation - Bones found:", {
|
|
71
|
+
head: !!c,
|
|
72
|
+
neck: !!l,
|
|
73
|
+
spine: !!n,
|
|
74
|
+
humanoid: !!t.humanoid
|
|
75
|
+
}), c && (c.rotation.x = Math.sin(e * 2) * 0.08, c.rotation.z = Math.sin(e * 1.5) * 0.05), l && (l.rotation.y = Math.sin(e * 0.8) * 0.05), n && (n.rotation.z = Math.sin(e * 0.5) * 0.03);
|
|
76
|
+
const i = t.humanoid?.getNormalizedBoneNode("leftShoulder"), u = t.humanoid?.getNormalizedBoneNode("rightShoulder"), p = t.humanoid?.getNormalizedBoneNode("leftUpperArm"), A = t.humanoid?.getNormalizedBoneNode("rightUpperArm"), d = t.humanoid?.getNormalizedBoneNode("leftLowerArm"), M = t.humanoid?.getNormalizedBoneNode("rightLowerArm");
|
|
77
|
+
i && (i.rotation.z = 0.1), u && (u.rotation.z = -0.1), p && (p.rotation.z = -0.8 + Math.sin(e * 1.2) * 0.1, p.rotation.x = 0.4 + Math.sin(e * 0.9) * 0.15, p.rotation.y = Math.sin(e * 0.7) * 0.1), A && (A.rotation.z = 0.8 + Math.sin(e * 1.3) * 0.1, A.rotation.x = 0.4 + Math.sin(e * 1) * 0.15, A.rotation.y = Math.sin(e * 0.8) * 0.1), d && (d.rotation.y = -1 - Math.sin(e * 1.5) * 0.2, d.rotation.z = Math.sin(e * 1.1) * 0.1), M && (M.rotation.y = 1 + Math.sin(e * 1.4) * 0.2, M.rotation.z = Math.sin(e * 1.2) * 0.1);
|
|
78
|
+
} else {
|
|
79
|
+
V = 0, t.expressionManager?.setValue(m.Aa, 0);
|
|
80
|
+
const s = t.humanoid?.getNormalizedBoneNode("spine"), c = t.humanoid?.getNormalizedBoneNode("head");
|
|
81
|
+
Math.floor(e) % 5 === 0 && e - Math.floor(e) < o && console.log("[Avatar Debug] Idle animation - Bones found:", {
|
|
82
|
+
head: !!c,
|
|
83
|
+
neck: !!t.humanoid?.getNormalizedBoneNode("neck"),
|
|
84
|
+
spine: !!s
|
|
85
|
+
}), s && (s.rotation.x = Math.sin(e * 0.8) * 0.02), c && (c.rotation.x = Math.sin(e * 0.3) * 0.03, c.rotation.z = Math.sin(e * 0.2) * 0.02);
|
|
86
|
+
const l = t.humanoid?.getNormalizedBoneNode("leftShoulder"), n = t.humanoid?.getNormalizedBoneNode("rightShoulder"), i = t.humanoid?.getNormalizedBoneNode("leftUpperArm"), u = t.humanoid?.getNormalizedBoneNode("rightUpperArm"), p = t.humanoid?.getNormalizedBoneNode("leftLowerArm"), A = t.humanoid?.getNormalizedBoneNode("rightLowerArm");
|
|
87
|
+
l && (l.rotation.z = 0.1), n && (n.rotation.z = -0.1), i && (i.rotation.z = -0.9, i.rotation.x = 0.2, i.rotation.y = 0), u && (u.rotation.z = 0.9, u.rotation.x = 0.2, u.rotation.y = 0), p && (p.rotation.y = -0.8), A && (A.rotation.y = 0.8);
|
|
88
|
+
}
|
|
89
|
+
e % 4 < 0.1 ? t.expressionManager?.setValue(m.Blink, 1) : t.expressionManager?.setValue(m.Blink, 0);
|
|
90
|
+
const h = W[S];
|
|
91
|
+
if (t.expressionManager?.setValue(m.Happy, 0), t.expressionManager?.setValue(m.Sad, 0), t.expressionManager?.setValue(m.Angry, 0), t.expressionManager?.setValue(m.Surprised, 0), h && t.expressionManager?.setValue(h, 0.8), D !== "none") {
|
|
92
|
+
const s = e - E, c = 1.5;
|
|
93
|
+
if (s < c) {
|
|
94
|
+
const l = s / c, n = t.humanoid?.getNormalizedBoneNode("head"), i = t.humanoid?.getNormalizedBoneNode("rightUpperArm"), u = t.humanoid?.getNormalizedBoneNode("rightLowerArm"), p = t.humanoid?.getNormalizedBoneNode("spine"), d = ((M) => M < 0.5 ? 2 * M * M : 1 - Math.pow(-2 * M + 2, 2) / 2)(l < 0.5 ? l * 2 : (1 - l) * 2);
|
|
95
|
+
switch (D) {
|
|
96
|
+
case "nod":
|
|
97
|
+
n && (n.rotation.x = Math.sin(l * Math.PI * 3) * 0.2);
|
|
98
|
+
break;
|
|
99
|
+
case "shake":
|
|
100
|
+
n && (n.rotation.y = Math.sin(l * Math.PI * 4) * 0.3);
|
|
101
|
+
break;
|
|
102
|
+
case "wave":
|
|
103
|
+
i && (i.rotation.z = 1.5 * d, i.rotation.x = -0.3 * d), u && (u.rotation.y = 0.5 + Math.sin(l * Math.PI * 6) * 0.3);
|
|
104
|
+
break;
|
|
105
|
+
case "think":
|
|
106
|
+
n && (n.rotation.x = 0.1 * d, n.rotation.z = 0.1 * d), i && (i.rotation.z = 0.3 * d, i.rotation.x = 0.8 * d), u && (u.rotation.y = 1.5 * d);
|
|
107
|
+
break;
|
|
108
|
+
case "bow":
|
|
109
|
+
p && (p.rotation.x = 0.4 * d), n && (n.rotation.x = 0.2 * d);
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
} else
|
|
113
|
+
D = "none";
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
r.render(a, v);
|
|
117
|
+
}
|
|
118
|
+
function J() {
|
|
119
|
+
L !== null && (cancelAnimationFrame(L), L = null), window.removeEventListener("resize", T), r && g.value && (g.value.removeChild(r.domElement), r.dispose(), r = null), t && (t = null), a = null, v = null, w = null;
|
|
120
|
+
}
|
|
121
|
+
return j(
|
|
122
|
+
() => f.selectedResult,
|
|
123
|
+
(o) => {
|
|
124
|
+
if (o?.toolName === O && o.data) {
|
|
125
|
+
const e = o.data;
|
|
126
|
+
if (e.avatarUrl && e.avatarUrl !== _ && (console.log("[Avatar Debug] VRM URL changed:", e.avatarUrl), _ = e.avatarUrl, F(e.avatarUrl)), e.emotion && e.emotion !== S && (console.log("[Avatar Debug] Emotion changed to:", e.emotion), S = e.emotion), e.action && e.action !== "none") {
|
|
127
|
+
const z = e.actionTimestamp || 0;
|
|
128
|
+
z > C && (console.log("[Avatar Debug] Action triggered:", e.action), D = e.action, E = w?.getElapsedTime() || 0, C = z);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
{ deep: !0 }
|
|
133
|
+
), j(
|
|
134
|
+
() => f.isAudioPlaying,
|
|
135
|
+
(o) => {
|
|
136
|
+
console.log("[Avatar Debug] Plugin received isAudioPlaying:", o);
|
|
137
|
+
}
|
|
138
|
+
), ie(() => {
|
|
139
|
+
if (console.log("[Avatar Debug] View component MOUNTED"), q(), f.selectedResult?.toolName === O && f.selectedResult.data) {
|
|
140
|
+
const o = f.selectedResult.data;
|
|
141
|
+
o.avatarUrl && (console.log("[Avatar Debug] Initial VRM load:", o.avatarUrl), _ = o.avatarUrl, F(o.avatarUrl)), o.emotion && (S = o.emotion);
|
|
142
|
+
}
|
|
143
|
+
}), re(() => {
|
|
144
|
+
J();
|
|
145
|
+
}), (o, e) => (y(), B("div", se, [
|
|
146
|
+
N("div", {
|
|
147
|
+
ref_key: "containerRef",
|
|
148
|
+
ref: g,
|
|
149
|
+
class: "size-full"
|
|
150
|
+
}, null, 512),
|
|
151
|
+
x.value ? (y(), B("div", le, [...e[0] || (e[0] = [
|
|
152
|
+
N("div", { class: "text-white text-lg" }, "Loading Avatar...", -1)
|
|
153
|
+
])])) : U("", !0),
|
|
154
|
+
b.value ? (y(), B("div", de, [
|
|
155
|
+
N("div", ce, H(b.value), 1)
|
|
156
|
+
])) : U("", !0),
|
|
157
|
+
k.isAudioPlaying ? (y(), B("div", ue, " Speaking... ")) : U("", !0)
|
|
158
|
+
]));
|
|
159
|
+
}
|
|
160
|
+
}), ge = { class: "p-3 bg-gradient-to-br from-slate-700 to-slate-800 rounded-md" }, he = { class: "flex flex-col items-center gap-2" }, pe = {
|
|
161
|
+
key: 0,
|
|
162
|
+
class: "text-xs px-2 py-0.5 bg-blue-500 text-white rounded-full"
|
|
163
|
+
}, fe = /* @__PURE__ */ G({
|
|
164
|
+
__name: "Preview",
|
|
165
|
+
props: {
|
|
166
|
+
result: {}
|
|
167
|
+
},
|
|
168
|
+
setup(k) {
|
|
169
|
+
const f = k, g = $(() => f.result.data), x = $(() => g.value?.emotion || "neutral");
|
|
170
|
+
return (b, a) => (y(), B("div", ge, [
|
|
171
|
+
N("div", he, [
|
|
172
|
+
a[0] || (a[0] = N("div", { class: "size-12 bg-slate-600 rounded-full flex items-center justify-center" }, [
|
|
173
|
+
N("svg", {
|
|
174
|
+
class: "size-8 text-slate-300",
|
|
175
|
+
fill: "none",
|
|
176
|
+
stroke: "currentColor",
|
|
177
|
+
viewBox: "0 0 24 24"
|
|
178
|
+
}, [
|
|
179
|
+
N("path", {
|
|
180
|
+
"stroke-linecap": "round",
|
|
181
|
+
"stroke-linejoin": "round",
|
|
182
|
+
"stroke-width": "2",
|
|
183
|
+
d: "M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"
|
|
184
|
+
})
|
|
185
|
+
])
|
|
186
|
+
], -1)),
|
|
187
|
+
a[1] || (a[1] = N("div", { class: "text-sm font-semibold text-white text-center" }, " 3D Avatar ", -1)),
|
|
188
|
+
x.value && x.value !== "neutral" ? (y(), B("div", pe, H(x.value), 1)) : U("", !0)
|
|
189
|
+
])
|
|
190
|
+
]));
|
|
191
|
+
}
|
|
192
|
+
}), ve = {
|
|
193
|
+
...ae,
|
|
194
|
+
viewComponent: me,
|
|
195
|
+
previewComponent: fe
|
|
196
|
+
}, Ne = { plugin: ve };
|
|
197
|
+
export {
|
|
198
|
+
fe as Preview,
|
|
199
|
+
ye as SAMPLES,
|
|
200
|
+
Be as TOOL_DEFINITION,
|
|
201
|
+
O as TOOL_NAME,
|
|
202
|
+
me as View,
|
|
203
|
+
Ne as default,
|
|
204
|
+
be as executeAvatar,
|
|
205
|
+
ve as plugin,
|
|
206
|
+
ae as pluginCore
|
|
207
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@gui-chat-plugin/avatar",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "3D Avatar Plugin for GUIChat - VRM avatar with lip-sync",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"require": "./dist/index.cjs"
|
|
14
|
+
},
|
|
15
|
+
"./core": {
|
|
16
|
+
"types": "./dist/core/index.d.ts",
|
|
17
|
+
"import": "./dist/core.js",
|
|
18
|
+
"require": "./dist/core.cjs"
|
|
19
|
+
},
|
|
20
|
+
"./vue": {
|
|
21
|
+
"types": "./dist/vue/index.d.ts",
|
|
22
|
+
"import": "./dist/vue.js",
|
|
23
|
+
"require": "./dist/vue.cjs"
|
|
24
|
+
},
|
|
25
|
+
"./react": {
|
|
26
|
+
"types": "./dist/react/index.d.ts",
|
|
27
|
+
"import": "./dist/react.js",
|
|
28
|
+
"require": "./dist/react.cjs"
|
|
29
|
+
},
|
|
30
|
+
"./style.css": "./dist/style.css"
|
|
31
|
+
},
|
|
32
|
+
"files": [
|
|
33
|
+
"dist"
|
|
34
|
+
],
|
|
35
|
+
"scripts": {
|
|
36
|
+
"dev": "vite",
|
|
37
|
+
"dev:react": "vite --config vite.config.react.ts",
|
|
38
|
+
"build": "vite build && vue-tsc -p tsconfig.build.json --emitDeclarationOnly && tsc -p tsconfig.react.json --emitDeclarationOnly",
|
|
39
|
+
"typecheck": "vue-tsc --noEmit && tsc -p tsconfig.react.json --noEmit",
|
|
40
|
+
"lint": "eslint src demo"
|
|
41
|
+
},
|
|
42
|
+
"peerDependencies": {
|
|
43
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
44
|
+
"react-dom": "^18.0.0 || ^19.0.0",
|
|
45
|
+
"vue": "^3.5.0"
|
|
46
|
+
},
|
|
47
|
+
"peerDependenciesMeta": {
|
|
48
|
+
"vue": {
|
|
49
|
+
"optional": true
|
|
50
|
+
},
|
|
51
|
+
"react": {
|
|
52
|
+
"optional": true
|
|
53
|
+
},
|
|
54
|
+
"react-dom": {
|
|
55
|
+
"optional": true
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
"devDependencies": {
|
|
59
|
+
"@tailwindcss/vite": "^4.1.18",
|
|
60
|
+
"@types/react": "^19.0.0",
|
|
61
|
+
"@types/react-dom": "^19.0.0",
|
|
62
|
+
"@types/three": "^0.174.0",
|
|
63
|
+
"@typescript-eslint/eslint-plugin": "^8.53.0",
|
|
64
|
+
"@typescript-eslint/parser": "^8.53.0",
|
|
65
|
+
"@vitejs/plugin-react": "^4.5.0",
|
|
66
|
+
"@vitejs/plugin-vue": "^6.0.3",
|
|
67
|
+
"eslint": "^9.39.2",
|
|
68
|
+
"eslint-plugin-vue": "^10.6.2",
|
|
69
|
+
"globals": "^17.0.0",
|
|
70
|
+
"openai": "^6.16.0",
|
|
71
|
+
"react": "^19.0.0",
|
|
72
|
+
"react-dom": "^19.0.0",
|
|
73
|
+
"tailwindcss": "^4.1.18",
|
|
74
|
+
"typescript": "~5.9.3",
|
|
75
|
+
"vite": "^7.3.1",
|
|
76
|
+
"vue": "^3.5.26",
|
|
77
|
+
"vue-eslint-parser": "^10.2.0",
|
|
78
|
+
"vue-tsc": "^3.2.2"
|
|
79
|
+
},
|
|
80
|
+
"keywords": [
|
|
81
|
+
"guichat",
|
|
82
|
+
"plugin",
|
|
83
|
+
"avatar",
|
|
84
|
+
"vrm",
|
|
85
|
+
"3d",
|
|
86
|
+
"lip-sync",
|
|
87
|
+
"react",
|
|
88
|
+
"vue",
|
|
89
|
+
"llm",
|
|
90
|
+
"chat"
|
|
91
|
+
],
|
|
92
|
+
"license": "MIT",
|
|
93
|
+
"dependencies": {
|
|
94
|
+
"@pixiv/three-vrm": "^3.3.3",
|
|
95
|
+
"gui-chat-protocol": "file:../gui-chat-protocol",
|
|
96
|
+
"three": "^0.174.0"
|
|
97
|
+
}
|
|
98
|
+
}
|