const { chromium } = require('C:/Users/phenom/.cache/codex-runtimes/codex-primary-runtime/dependencies/node/node_modules/playwright'); const fs = require('node:fs'); const path = require('node:path'); // Isolated asset review: real GLB/KTX2 loading and production material preparation, // with the runtime palettes. This does not simulate combat, navigation or a full clear. const output = path.resolve('artifacts/playtest/rom-environment-quality'); const requested = new Set(process.argv.slice(2)); const recipes = fs.readdirSync('scripts/runewaker-pipeline/recipes') .filter((name) => name.endsWith('.json') && !name.endsWith('-population.json')) .map((name) => JSON.parse(fs.readFileSync(path.join('scripts/runewaker-pipeline/recipes', name), 'utf8'))) .filter((recipe) => recipe.source?.wdb && (!requested.size || requested.has(recipe.slug))) .sort((a, b) => a.slug.localeCompare(b.slug)); fs.mkdirSync(output, { recursive: true }); (async () => { const browser = await chromium.launch({ channel: 'msedge', headless: true }); const resultsFile = path.join(output, 'results.json'); const results = requested.size && fs.existsSync(resultsFile) ? JSON.parse(fs.readFileSync(resultsFile, 'utf8')).results.filter((entry) => !requested.has(entry.slug)) : []; try { for (const recipe of recipes) { const context = await browser.newContext({ viewport: { width: 1280, height: 800 } }); const page = await context.newPage(); const errors = []; page.on('pageerror', (error) => errors.push(error.message)); page.on('console', (message) => { if (message.type() === 'error') errors.push(message.text()); }); try { await page.goto(`http://127.0.0.1:4207/scripts/runewaker-pipeline/environment-preview.html?dungeon=${recipe.slug}`, { waitUntil: 'domcontentloaded' }); await page.waitForFunction(() => window.romEnvironmentReview?.ready, null, { timeout: 180_000 }); const data = await page.evaluate(() => ({ viewpoints: window.romEnvironmentReview.viewpoints, presentation: window.romEnvironmentReview.presentation })); await page.waitForTimeout(500); await page.evaluate(() => window.romEnvironmentReview.lighting(true)); await page.waitForTimeout(250); await page.screenshot({ path: path.join(output, `${recipe.slug}-before.png`) }); await page.evaluate(() => window.romEnvironmentReview.lighting(false)); const views = [0, Math.floor((data.viewpoints.length - 1) / 2), data.viewpoints.length - 1]; for (const [index, viewpoint] of views.entries()) { await page.evaluate((value) => window.romEnvironmentReview.view(value), viewpoint); await page.waitForTimeout(300); await page.screenshot({ path: path.join(output, `${recipe.slug}-view-${index}.png`) }); } await page.evaluate(() => window.romEnvironmentReview.view(0, Math.PI)); await page.waitForTimeout(300); await page.screenshot({ path: path.join(output, `${recipe.slug}-entrance-reverse.png`) }); const drawCalls = await page.evaluate(() => window.romEnvironmentReview.drawCalls()); await page.evaluate(() => window.romEnvironmentReview.resetFrameSample()); await page.waitForTimeout(1000); const frameSample = await page.evaluate(() => window.romEnvironmentReview.frameSample()); results.push({ slug: recipe.slug, status: errors.length ? 'error' : 'loaded', drawCalls, frameSample, errors, ...data }); console.log(`${recipe.slug}: ${errors.length ? 'ERROR' : 'loaded'}; ${data.viewpoints.length} available viewpoints`); } catch (error) { results.push({ slug: recipe.slug, status: 'error', errors: [...errors, error.message] }); console.error(`${recipe.slug}: ${error.message}`); await page.screenshot({ path: path.join(output, `${recipe.slug}-failure.png`) }).catch(() => {}); } finally { await context.close(); results.sort((a, b) => a.slug.localeCompare(b.slug)); fs.writeFileSync(resultsFile, `${JSON.stringify({ scope: 'isolated environment asset review; entrance, midpoint boss, final boss and reverse entrance; no navigation or combat certification', results }, null, 2)}\n`); } } } finally { await browser.close(); } if (results.some((result) => result.status === 'error')) process.exitCode = 1; })().catch((error) => { console.error(error); process.exitCode = 1; });