// 서연 래스터 아바타 렌더링 스크린샷 캡처(시각 튜닝용). // 사용: node apps/web/scripts/avatar-shot.mjs // URL 환경변수로 대상 변경 가능(기본 /dev/avatar-preview). import { chromium } from "@playwright/test"; const BASE = process.env.BASE_URL || "http://localhost:5173"; const PATH = process.env.SHOT_PATH || "/dev/avatar-preview"; const OUT_DIR = process.env.OUT_DIR || "docs/avatar-art/seoyeon"; const browser = await chromium.launch(); const page = await browser.newPage({ viewport: { width: 1100, height: 1700 }, deviceScaleFactor: 2, }); page.on("pageerror", (e) => console.error("pageerror:", e.message)); page.on("console", (m) => { if (m.type() === "error") console.error("console:", m.text()); }); await page.goto(`${BASE}${PATH}`, { waitUntil: "domcontentloaded", timeout: 60000 }); // 이미지 로드 + 첫 호흡 사이클 대기 await page.waitForLoadState("networkidle", { timeout: 60000 }).catch(() => {}); await page.waitForTimeout(1800); // 1) hero(대형 애니메이션 2종) 캡처 const hero = page.locator(".ap__hero").first(); if (await hero.count()) { await hero.screenshot({ path: `${OUT_DIR}/render-hero.png` }); console.log("shot render-hero.png"); } // 2) 표정 그리드(정적) 전체 const grid = page.locator(".ap__grid").first(); if (await grid.count()) { await grid.screenshot({ path: `${OUT_DIR}/render-grid.png` }); console.log("shot render-grid.png"); } // 3) 개별 hero 아바타(단일) 캡처 — 데이터 속성으로 단일 .vg-avatar 격리 const avatars = page.locator(".ap__hero .vg-avatar"); const n = await avatars.count(); for (let i = 0; i < n; i++) { await avatars.nth(i).screenshot({ path: `${OUT_DIR}/render-hero-${i}.png` }); console.log(`shot render-hero-${i}.png`); } await browser.close(); console.log("done");