fix(avatar): re-apply CSS 100% after Pixi resize(); use fitModel helper; 65% margin

Pixi renderer.resize() overwrites canvas inline width/height styles,
locking the canvas to the initial size and leaving empty space below.
Now we re-apply width:100%;height:100% after every resize so the canvas
always fills its container. Removed unused appRef.
This commit is contained in:
2026-06-05 09:47:51 -04:00
parent f2ff91730b
commit 13dbcdb7f5
+19 -10
View File
@@ -24,7 +24,6 @@ const OUTFIT_TEXTURES: Record<string, string> = {
export default function KiraAvatar(props: Props) { export default function KiraAvatar(props: Props) {
const canvasRef = useRef<HTMLDivElement>(null); const canvasRef = useRef<HTMLDivElement>(null);
const appRef = useRef<any>(null);
const modelRef = useRef<any>(null); const modelRef = useRef<any>(null);
const textureRef = useRef<any>(null); const textureRef = useRef<any>(null);
const lipSyncRef = useRef<number>(0); const lipSyncRef = useRef<number>(0);
@@ -41,6 +40,16 @@ export default function KiraAvatar(props: Props) {
let app: any = null; let app: any = null;
let model: any = null; let model: any = null;
let canvasEl: HTMLCanvasElement | null = null;
const fitModel = (crW: number, crH: number) => {
if (!model || !app) return;
const maxW = crW * 0.65;
const maxH = crH * 0.65;
const s = Math.min(maxW / model.width, maxH / model.height);
model.scale.set(s);
model.position.set(app.screen.width / 2, app.screen.height / 2);
};
const init = async () => { const init = async () => {
try { try {
@@ -73,6 +82,7 @@ export default function KiraAvatar(props: Props) {
canvas.style.height = '100%'; canvas.style.height = '100%';
canvas.style.display = 'block'; canvas.style.display = 'block';
container.appendChild(canvas); container.appendChild(canvas);
canvasEl = canvas;
model = await Live2DModel.from('/live2d/models/kira/kira.model3.json', { model = await Live2DModel.from('/live2d/models/kira/kira.model3.json', {
autoInteract: false, autoInteract: false,
@@ -80,8 +90,8 @@ export default function KiraAvatar(props: Props) {
modelRef.current = model; modelRef.current = model;
// Fit model with generous margin to avoid clipping // Fit model with generous margin to avoid clipping
const maxW = w * 0.68; const maxW = w * 0.65;
const maxH = h * 0.68; const maxH = h * 0.65;
const scale = Math.min(maxW / model.width, maxH / model.height); const scale = Math.min(maxW / model.width, maxH / model.height);
model.scale.set(scale); model.scale.set(scale);
model.anchor.set(0.5, 0.5); model.anchor.set(0.5, 0.5);
@@ -117,17 +127,16 @@ export default function KiraAvatar(props: Props) {
// Use ResizeObserver so we init with the real laid-out size // Use ResizeObserver so we init with the real laid-out size
const ro = new ResizeObserver((entries) => { const ro = new ResizeObserver((entries) => {
const cr = entries[0].contentRect;
if (app) { if (app) {
// Already init'd — handle resize // Already init'd — handle resize
const cr = entries[0].contentRect;
app.renderer.resize(Math.round(cr.width), Math.round(cr.height)); app.renderer.resize(Math.round(cr.width), Math.round(cr.height));
if (model) { // Re-apply CSS 100% because Pixi resize() overwrites inline styles
const maxW = cr.width * 0.68; if (canvasEl) {
const maxH = cr.height * 0.68; canvasEl.style.width = '100%';
const s = Math.min(maxW / model.width, maxH / model.height); canvasEl.style.height = '100%';
model.scale.set(s);
model.position.set(app.screen.width / 2, app.screen.height / 2);
} }
fitModel(cr.width, cr.height);
return; return;
} }
// First measurement — run init // First measurement — run init