-
Notifications
You must be signed in to change notification settings - Fork 6
Description
Hello!
I have a rather specific issue. I'm building my own dashboard for live2d and need to view the same model instance in multiple places.
This is mainly my dashboard with all the settings, and my overlay for streaming in OBS.
However when opening the overlay (or another dashboard instance) it initializes a completely new model instance. This makes it play different animations and doesn't represent the actual visible model.
My goal is to create a single model renderer and then simply being able to view the rendered output in multiple places. Is this possible?
P.S.: Considering there's no React example provided anywhere I kinda had to "interpret" the vue example. I would actually prefer to use @pixi/react but can't figure out how to use it at all.
P.P.S.:
Details
Here's my code
import { Live2DSprite } from "easy-live2d";
import { Application, Ticker } from "pixi.js";
import { type FC, useEffect, useId, useRef } from "react";
import styles from "./model.module.css";
type ModelProps = {
wsUrl?: string;
};
export const Model: FC<ModelProps> = () => {
const spriteRef = useRef<Live2DSprite>(null);
const canvasRef = useRef<HTMLCanvasElement>(null);
const canvasId = useId();
useEffect(() => {
if (!canvasRef || !canvasRef.current) return;
const canvas = canvasRef.current;
const parent = canvas.parentElement;
if (!parent) return;
let isCleaningUp = false;
const app = new Application();
const initPixi = async () => {
if (isCleaningUp) return;
await app.init({
backgroundAlpha: 0,
canvas: canvas,
width: parent.clientWidth,
height: parent.clientHeight,
resizeTo: parent, // Auto-resize to parent
});
const live2dSprite = new Live2DSprite({
modelPath: "/Cubism/Resources/Hiyori/Hiyori.model3.json",
ticker: Ticker.shared,
});
spriteRef.current = live2dSprite;
const sizeMultiplier = 1;
live2dSprite.anchor.set(0.5, 1);
live2dSprite.setSize(
canvas.width * window.devicePixelRatio * sizeMultiplier,
canvas.height * window.devicePixelRatio * sizeMultiplier,
);
live2dSprite.position.set(canvas.width / 32, 0);
app.stage.addChild(live2dSprite);
};
initPixi().catch(console.error);
return () => {
isCleaningUp = true;
// Destroy sprite first, before app
if (spriteRef.current) {
try {
spriteRef.current.destroy();
} catch (error) {
console.warn("Error destroying Live2D sprite:", error);
}
spriteRef.current = null;
}
// Then destroy the PIXI app
if (app) {
try {
app.destroy(true, {
children: true,
texture: true,
textureSource: true,
style: true,
context: true,
});
} catch (error) {
console.warn("Error destroying PIXI app:", error);
}
}
};
}, []);
return <canvas className={styles.model} ref={canvasRef} id={canvasId} />;
};