feat(@projects/@magic-civilization): add lab diagnostic scripts

Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
Natalie 2026-05-01 04:28:23 -04:00
parent 6a601209f6
commit 46a7865ce0
3 changed files with 184 additions and 0 deletions

View file

@ -0,0 +1,57 @@
#!/usr/bin/env node
// Diagnose /world-gen/lab — capture console, page errors, canvas presence.
// Uses playwright from the guide's node_modules (already installed).
import { chromium } from '../../../public/games/age-of-dwarves/guide/node_modules/@playwright/test/index.mjs';
const BASE = process.env.BASE_URL || 'http://localhost:7777';
const TARGET = process.argv[2] || '/world-gen/lab';
const URL = `${BASE}${TARGET}`;
const browser = await chromium.launch();
const page = await browser.newPage();
const errors = [];
const consoleErrors = [];
page.on('pageerror', (err) => errors.push(`PAGE_ERROR: ${err.message}\n${err.stack ?? ''}`));
page.on('console', (msg) => {
if (msg.type() === 'error' || msg.type() === 'warning') {
consoleErrors.push(`${msg.type().toUpperCase()}: ${msg.text()}`);
}
});
console.log(`navigating to ${URL}`);
await page.goto(URL, { waitUntil: 'networkidle', timeout: 30_000 });
// Give React a moment to render
await page.waitForTimeout(1500);
// Snapshot
const title = await page.title();
const rootHTML = await page.locator('#root').innerHTML();
const canvasCount = await page.locator('canvas').count();
const errorOverlay = await page.locator('vite-error-overlay').count();
const sliderCount = await page.locator('input[type="range"]').count();
const buttonCount = await page.locator('button').count();
const bodyText = (await page.locator('body').innerText()).slice(0, 600);
console.log(`\n=== ${URL} ===`);
console.log(`title: ${title}`);
console.log(`root.innerHTML length: ${rootHTML.length}`);
console.log(`canvas count: ${canvasCount}`);
console.log(`vite-error-overlay: ${errorOverlay > 0 ? 'PRESENT' : 'absent'}`);
console.log(`<input type="range">: ${sliderCount}`);
console.log(`<button>: ${buttonCount}`);
console.log(`\n=== body text (first 600 chars) ===`);
console.log(bodyText);
if (errors.length > 0) {
console.log(`\n=== PAGE ERRORS (${errors.length}) ===`);
errors.forEach((e) => console.log(e));
}
if (consoleErrors.length > 0) {
console.log(`\n=== CONSOLE (${consoleErrors.length}) ===`);
consoleErrors.slice(0, 20).forEach((e) => console.log(e));
}
await browser.close();
process.exit(errors.length > 0 || errorOverlay > 0 ? 1 : 0);

View file

@ -0,0 +1,74 @@
#!/usr/bin/env node
// Detailed probe — lab + substrate. Uses page.evaluate() with serializable functions.
import { chromium } from '../../../public/games/age-of-dwarves/guide/node_modules/@playwright/test/index.mjs';
const URL = `${process.env.BASE_URL || 'http://localhost:7777'}/world-gen/lab`;
const browser = await chromium.launch();
const page = await browser.newPage();
const consoleLogs = [];
page.on('console', (msg) => consoleLogs.push(`${msg.type()}: ${msg.text()}`));
page.on('pageerror', (err) => consoleLogs.push(`PAGEERROR: ${err.message}`));
await page.goto(URL, { waitUntil: 'networkidle', timeout: 30_000 });
await page.waitForTimeout(2500);
const summary = await page.evaluate(() => {
const sliders = Array.from(document.querySelectorAll('input[type="range"]')).map((el) => ({
name: el.name || el.getAttribute('aria-label') || el.parentElement?.previousElementSibling?.textContent?.slice(0, 40) || '?',
value: el.value,
min: el.min,
max: el.max,
visible: !!(el.offsetParent),
}));
const buttons = Array.from(document.querySelectorAll('button'))
.map((el) => el.textContent?.trim().slice(0, 50))
.filter(Boolean);
const selects = Array.from(document.querySelectorAll('select')).map((el) => ({
name: el.name || '?',
value: el.value,
optionCount: el.options.length,
}));
const canvases = Array.from(document.querySelectorAll('canvas')).map((el) => ({
width: el.width,
height: el.height,
dataLen: el.toDataURL().length,
}));
const fullText = document.body.innerText;
return {
sliders,
buttons: buttons.slice(0, 30),
selects,
canvases,
hasWasmText: /WASM|wasm/i.test(fullText),
hasSpeciesNames: /european_beech|grey_wolf|saguaro|scots_pine|brown_bear|red_deer/i.test(fullText),
bodySnippet: fullText.slice(600, 2400),
};
});
console.log('=== sliders ===');
console.log(JSON.stringify(summary.sliders, null, 2));
console.log('=== selects ===');
console.log(JSON.stringify(summary.selects, null, 2));
console.log('=== buttons (first 25) ===');
console.log(summary.buttons.slice(0, 25).join(' | '));
console.log('=== canvases ===');
console.log(JSON.stringify(summary.canvases, null, 2));
console.log('=== wasm/species ===');
console.log({ hasWasmText: summary.hasWasmText, hasSpeciesNames: summary.hasSpeciesNames });
console.log('=== body 600-2400 ===');
console.log(summary.bodySnippet);
console.log('=== console (last 12) ===');
consoleLogs.slice(-12).forEach((l) => console.log(l));
// Substrate page
await page.goto(`${process.env.BASE_URL || 'http://localhost:7777'}/world-gen/substrate`, { waitUntil: 'networkidle' });
await page.waitForTimeout(2000);
const substrateInfo = await page.evaluate(() => ({
canvases: document.querySelectorAll('canvas').length,
bodySnippet: document.body.innerText.slice(0, 400),
hasWasmText: /WASM|wasm|Generating/i.test(document.body.innerText),
}));
console.log('\n=== /world-gen/substrate ===');
console.log(JSON.stringify(substrateInfo, null, 2));
await browser.close();

View file

@ -0,0 +1,53 @@
#!/usr/bin/env node
import { chromium } from '../../../public/games/age-of-dwarves/guide/node_modules/@playwright/test/index.mjs';
const URL = `${process.env.BASE_URL || 'http://localhost:7777'}/world-gen/lab`;
const browser = await chromium.launch();
const page = await browser.newPage();
const consoleLogs = [];
page.on('console', (msg) => consoleLogs.push(`${msg.type()}: ${msg.text()}`));
page.on('pageerror', (err) => consoleLogs.push(`PAGEERROR: ${err.message}`));
await page.goto(URL, { waitUntil: 'networkidle' });
await page.waitForTimeout(2500);
// Click "Advanced" button
const advancedBtn = page.getByRole('button', { name: 'Advanced' });
await advancedBtn.click();
await page.waitForTimeout(800);
const after = await page.evaluate(() => {
const sliders = Array.from(document.querySelectorAll('input[type="range"]')).map((el) => ({
label: el.parentElement?.previousElementSibling?.textContent?.slice(0, 40) || el.previousElementSibling?.textContent?.slice(0, 40) || '?',
value: el.value,
}));
return {
sliderCount: sliders.length,
sliders,
bodyText: document.body.innerText,
};
});
console.log('=== After clicking Advanced ===');
console.log(`slider count: ${after.sliderCount}`);
console.log(JSON.stringify(after.sliders, null, 2));
// Look for species names
const speciesMatches = (after.bodyText.match(/european_beech|grey_wolf|saguaro|scots_pine|brown_bear|red_deer|pedunculate_oak|holly|hazel|moose|jaguar/gi) || []);
console.log(`\n=== species hits in body text ===`);
console.log(`count: ${speciesMatches.length}, samples: ${speciesMatches.slice(0, 10).join(', ')}`);
// Look for "Canopy" / "Understory" / "Ground" labels (info card)
const ecoSections = (after.bodyText.match(/Canopy|Understory|Ground|Fauna/gi) || []).slice(0, 10);
console.log(`\n=== ecology section labels in body ===`);
console.log(`hits: ${ecoSections.join(', ')}`);
// Find info card body
const cardSnippet = after.bodyText.match(/Forest[\s\S]{0,800}/)?.[0]?.slice(0, 800);
console.log(`\n=== info card snippet ===`);
console.log(cardSnippet ?? '(no Forest match)');
console.log(`\n=== console (errors only) ===`);
consoleLogs.filter((l) => /error|ERROR/.test(l)).slice(0, 10).forEach((l) => console.log(l));
await browser.close();