137 lines
4.5 KiB
JavaScript
137 lines
4.5 KiB
JavaScript
import { app } from "../../../scripts/app.js";
|
|
import { api } from '../../../scripts/api.js'
|
|
import { ComfyWidgets } from "../../../scripts/widgets.js"
|
|
|
|
function draggable(model) {
|
|
model.buttonMode = true;
|
|
model.on("pointerdown", (e) => {
|
|
model.dragging = true;
|
|
model._pointerX = e.data.global.x - model.x;
|
|
model._pointerY = e.data.global.y - model.y;
|
|
});
|
|
model.on("pointermove", (e) => {
|
|
if (model.dragging) {
|
|
model.position.x = e.data.global.x - model._pointerX;
|
|
model.position.y = e.data.global.y - model._pointerY;
|
|
}
|
|
});
|
|
model.on("pointerupoutside", () => (model.dragging = false));
|
|
model.on("pointerup", () => (model.dragging = false));
|
|
}
|
|
|
|
function talk(model,audio_link){
|
|
var volume = 1; // [Optional arg, can be null or empty] [0.0 - 1.0]
|
|
var expression = 8; // [Optional arg, can be null or empty] [index|name of expression]
|
|
var resetExpression = true; // [Optional arg, can be null or empty] [true|false] [default: true] [if true, expression will be reset to default after animation is over]
|
|
var crossOrigin = "anonymous"; // [Optional arg, to use not same-origin audios] [DEFAULT: null]
|
|
|
|
model.speak(audio_link, {volume: volume, expression:expression, resetExpression:resetExpression, crossOrigin: crossOrigin})
|
|
|
|
// Or if you want to keep some things default
|
|
model.speak(audio_link)
|
|
model.speak(audio_link, {volume: volume})
|
|
model.speak(audio_link, {expression:expression, resetExpression:resetExpression})
|
|
}
|
|
|
|
function showVtuber(node, audio_name,audio_type, vtuber) {
|
|
let params = {
|
|
"filename": audio_name,
|
|
"type": audio_type,
|
|
}
|
|
const audio_link = api.apiURL('/view?' + new URLSearchParams(params));
|
|
|
|
var element = document.createElement("div");
|
|
|
|
const previewNode = node;
|
|
var previewWidget = node.addDOMWidget("vtuberpreview", "preview", element, {
|
|
serialize: false,
|
|
hideOnZoom: false,
|
|
getValue() {
|
|
return element.value;
|
|
},
|
|
setValue(v) {
|
|
element.value = v;
|
|
},
|
|
});
|
|
|
|
previewWidget.computeSize = function(width) {
|
|
if (this.aspectRatio && !this.parentEl.hidden) {
|
|
let height = (previewNode.size[0]-20)/ this.aspectRatio + 10;
|
|
if (!(height > 0)) {
|
|
height = 0;
|
|
}
|
|
this.computedHeight = height + 10;
|
|
return [width, height];
|
|
}
|
|
return [width, -4];//no loaded src, widget should not display
|
|
}
|
|
// element.style['pointer-events'] = "none"
|
|
previewWidget.value = {hidden: false, paused: false, params: {}}
|
|
previewWidget.parentEl = document.createElement("canvas");
|
|
previewWidget.parentEl.id = "canvas";
|
|
previewWidget.parentEl.style['width'] = "100%"
|
|
element.appendChild(previewWidget.parentEl);
|
|
|
|
const cubism4Model = `extensions/ComfyUI-Live2DViewer/vtuber/${vtuber}/runtime/${vtuber}.model3.json`;
|
|
|
|
(async function main() {
|
|
|
|
const app = new PIXI.Application({
|
|
view: document.getElementById("canvas"),
|
|
autoStart: true,
|
|
resizeTo: window,
|
|
backgroundColor: 0x333333
|
|
});
|
|
|
|
const models = await Promise.all([
|
|
PIXI.live2d.Live2DModel.from(cubism4Model)
|
|
]);
|
|
|
|
models.forEach((model) => {
|
|
app.stage.addChild(model);
|
|
|
|
const scaleX = (innerWidth ) / model.width;
|
|
const scaleY = (innerHeight ) / model.height;
|
|
|
|
// fit the window
|
|
model.scale.set(Math.min(scaleX, scaleY));
|
|
|
|
model.y = innerHeight * 0.1;
|
|
draggable(model);
|
|
talk(model,audio_link);
|
|
});
|
|
|
|
const model4 = models[0];
|
|
|
|
|
|
model4.x = innerWidth / 2;
|
|
|
|
|
|
model4.on("hit", (hitAreas) => {
|
|
if (hitAreas.includes("Body")) {
|
|
model4.motion("Tap");
|
|
}
|
|
|
|
if (hitAreas.includes("Head")) {
|
|
model4.expression();
|
|
}
|
|
});
|
|
let btnWidget = node.addWidget("button", "RELOAD", "Audio", () => {
|
|
talk(model4,audio_link);
|
|
});
|
|
element.appendChild(btnWidget);
|
|
})();
|
|
return { widget: previewWidget };
|
|
}
|
|
|
|
app.registerExtension({
|
|
name: "Live2DViewer.ShowVtuber",
|
|
async beforeRegisterNodeDef(nodeType, nodeData, app) {
|
|
if (nodeData?.name == "Live2DViewer") {
|
|
nodeType.prototype.onExecuted = function (data) {
|
|
showVtuber(this, data.vtuber[0],data.vtuber[1],data.vtuber[2]);
|
|
console.log(data.vtuber);
|
|
}
|
|
}
|
|
},
|
|
}); |