← back to Quadrille Showroom
scripts/diag-probe.mjs
105 lines
// Diagnostic probe (NOT proof) — measure, via REAL yaw only, two things:
// (A) HOLE-2: after selecting a board, how wide is the hero on screen vs a closed
// sliver neighbour? (project the hero face corners + a neighbour face corners).
// (B) HOLE-1: yaw to the +72 / -72 clamp via real ArrowRight/ArrowLeft keydowns and
// measure how many screen pixels of clad SIDE/BACK wall are visible (raycast a grid
// of screen points into the scene; count hits on a roomWall mesh that carries a clad
// material map). NO setMode('room'), NO park(), NO camera move.
import pw from '/Users/macstudio3/.npm-global/lib/node_modules/playwright/index.js';
const { chromium } = pw;
const browser = await chromium.launch({ args: ['--use-gl=angle','--use-angle=swiftshader','--enable-webgl','--ignore-gpu-blocklist'] });
const page = await browser.newPage({ viewport: { width: 1440, height: 900 } });
const errors = [];
page.on('console', m => { if (m.type()==='error') errors.push(m.text()); });
page.on('pageerror', e => errors.push('PAGEERROR: '+e.message));
await page.goto('http://localhost:7690/', { waitUntil: 'networkidle' });
await page.waitForFunction(() => window._qh && window._qh.wingBoards && window._qh.wingBoards.length>0, { timeout:20000 });
await page.waitForTimeout(2500);
// Expose a raycast-based "clad wall pixels visible" sampler into the page.
await page.addScriptTag({ content: `
window.__measureCladWall = function() {
const qh = window._qh, THREE = qh.THREE, cam = qh.camera, scene = qh.scene;
const W = window.innerWidth, H = window.innerHeight;
const rc = new THREE.Raycaster();
// collect all room-wall meshes that currently carry a clad texture map
const cladMeshes = [];
scene.traverse(o => {
if (o.isMesh && o.material && o.material.map && o.geometry && o.geometry.type==='PlaneGeometry') {
// wall planes are large; wings are PlaneGeometry too but smaller — tag by size
const g = o.geometry.parameters || {};
if (g.width >= 1.0 && g.height >= 2.0) cladMeshes.push(o);
}
});
// sample a 40x24 screen grid
let cladHits=0, total=0, wingHits=0, otherHits=0;
const targets = [];
scene.traverse(o => { if (o.isMesh) targets.push(o); });
for (let yi=0; yi<24; yi++) for (let xi=0; xi<40; xi++) {
const nx = (xi+0.5)/40*2-1, ny = -((yi+0.5)/24*2-1);
rc.setFromCamera({x:nx,y:ny}, cam);
const hit = rc.intersectObjects(targets, false)[0];
total++;
if (!hit) continue;
if (cladMeshes.includes(hit.object)) cladHits++;
else if (hit.object.userData && hit.object.userData.isWingFace) wingHits++;
else otherHits++;
}
return { cladHits, wingHits, otherHits, total, cladMeshCount: cladMeshes.length, yawDeg:+(qh.spinYaw*180/Math.PI).toFixed(1) };
};
// hero vs neighbour on-screen width (projected face X-extent in px)
window.__measureHeroWidth = function() {
const qh = window._qh, THREE = qh.THREE, cam = qh.camera;
const f = qh.focusedWing; if (!f) return null;
const wb = qh.wingBoards;
function faceWidthPx(pivot) {
const ud = pivot.userData; const face = ud.face; if (!face) return 0;
const g = face.geometry.parameters; const hw = g.width/2, hh=g.height/2;
const corners = [[-hw,-hh],[hw,-hh],[hw,hh],[-hw,hh]];
let minx=1e9,maxx=-1e9;
for (const [cx,cy] of corners) {
const v = new THREE.Vector3(cx,cy,0);
face.localToWorld(v); v.project(cam);
const px=(v.x*0.5+0.5)*window.innerWidth;
minx=Math.min(minx,px); maxx=Math.max(maxx,px);
}
return maxx-minx;
}
const heroW = faceWidthPx(f);
// nearest closed neighbour (index +/-2 from hero, whichever exists)
const hi = f.userData.index;
const nb = wb[hi+3] || wb[hi-3] || wb[hi+1] || wb[hi-1];
const nbW = nb ? faceWidthPx(nb) : 0;
return { heroW:+heroW.toFixed(1), nbW:+nbW.toFixed(1), ratio:+(heroW/(nbW||1)).toFixed(2), heroFlip:+f.userData.flip.toFixed(3), heroIdx:hi };
};
`});
// --- select a board via the REAL focus path ---
await page.evaluate(() => {
const wb = window._qh.wingBoards;
const idx = Math.floor(wb.length/2) + 4;
window._qh.focusOnWing(wb[idx]);
});
// wait for carousel settle + flip + clad load
await page.waitForTimeout(4500);
const heroW = await page.evaluate(() => window.__measureHeroWidth());
const cladFront = await page.evaluate(() => window.__measureCladWall());
// --- REAL yaw to +72 (right) via held ArrowRight keydowns ---
async function holdYaw(key, ms) {
await page.evaluate((k)=>{ window.dispatchEvent(new KeyboardEvent('keydown',{key:k,code:k,bubbles:true})); }, key);
await page.waitForTimeout(ms);
await page.evaluate((k)=>{ window.dispatchEvent(new KeyboardEvent('keyup',{key:k,code:k,bubbles:true})); }, key);
await page.waitForTimeout(400);
}
await holdYaw('ArrowRight', 1400);
const cladRight = await page.evaluate(() => window.__measureCladWall());
// back to centre then full left
await holdYaw('ArrowLeft', 1400); // to ~0
await holdYaw('ArrowLeft', 1400); // to ~-72
const cladLeft = await page.evaluate(() => window.__measureCladWall());
console.log(JSON.stringify({ heroW, cladFront, cladRight, cladLeft, controlsLocked: await page.evaluate(()=>window._qh.controlsLocked), exploreMode: await page.evaluate(()=>window._qh.exploreMode), errors: errors.slice(0,5), errorCount: errors.length }, null, 2));
await browser.close();