Something went wrong. Try again.
Monorepo for Aesthetic.Computer aesthetic.computer
Something went wrong. Try again.
JavaScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151// flair-fps.test, 2026.05.31// Compares the prompt attract-screen frame rate with "flair" on vs off.// Flair = the starfield, spinning cube, polychrome border, tap/touch/type hint,// version+notepat buttons, and the live product carousel — the last of which is// the dominant per-frame cost. Turning flair off should never *lower* the frame// rate (and on real hardware should raise it noticeably).//// AC_TEST_URL=https://localhost:8888 node tests/browser/flair-fps.test.mjs// AC_HEADED=1 AC_TEST_URL=https://localhost:8888 node tests/browser/flair-fps.test.mjs//// Flair is toggled deterministically via a URL colon param (`prompt:noflair`)// rather than a window hook — the prompt piece runs in a worker, so window// hooks don't bridge to the page. Two clean navigations, one FPS sample each.//// ⚠️ Headless Chrome renders WebGL in software (SwiftShader) and may throttle// requestAnimationFrame, so the GPU cost of the glaze won't show and the delta// can be muddy. For real numbers run with AC_HEADED=1 on a machine with a GPU.// By default the test only hard-fails on a clear regression (flair-off slower);// set FLAIR_FPS_STRICT=1 to require a measurable speedup.
import { ACSession, scenario, report, CONFIG } from "./ac-harness.mjs";
const SAMPLE_MS = parseInt(process.env.FLAIR_FPS_SAMPLE_MS || "5000", 10);const STRICT = process.env.FLAIR_FPS_STRICT === "1";
// Count real animation frames over `ms` and return the average FPS.async function sampleFps(page, ms) { return await page.evaluate( (dur) => new Promise((resolve) => { let frames = 0; const t0 = performance.now(); const tick = () => { frames += 1; const elapsed = performance.now() - t0; if (elapsed < dur) requestAnimationFrame(tick); else resolve((frames * 1000) / elapsed); }; requestAnimationFrame(tick); }), ms, );}
const ac = await ACSession.open();let fpsOn = null;let fpsOff = null;let fpsNoStars = null;
// Resilient navigation: the live Shopify carousel keeps connections open, so// puppeteer's networkidle2 (used by ACSession.boot) can time out. Wait for the// AC boot marker (which IS on the main window) instead, then settle.async function bootLoose(piece, settleMs = 3500) { const url = `${CONFIG.baseURL}/${piece}`; console.log(` → ${url}`); try { await ac.page.goto(url, { waitUntil: "domcontentloaded", timeout: 30000 }); } catch (e) { console.warn(` ⚠️ goto: ${e.message} (continuing)`); } try { await ac.page.waitForFunction(() => window.acBOOT_START_TIME, { timeout: 20000 }); } catch { console.warn(" ⚠️ no boot marker — continuing on timer"); } await ac.wait(settleMs);}
// Screenshots are diagnostic, not assertions — never let a CDP flake fail a run.async function safeShot(name) { try { await ac.shot(name); } catch (e) { console.warn(` ⚠️ screenshot ${name}: ${e.message} (skipped)`); }}
try { await scenario("fps with carousel ON (prompt:products)", async (expect) => { // The product carousel is off by default now, so explicitly enable it to // measure the heavy path. await bootLoose("prompt:products"); await safeShot("flair-on"); fpsOn = await sampleFps(ac.page, SAMPLE_MS); console.log(` 📊 carousel ON → ${fpsOn.toFixed(1)} fps`); expect(fpsOn > 0, "measured a frame rate with the carousel on"); });
await scenario("fps with starfield+cube OFF (prompt:nostars)", async (expect) => { await bootLoose("prompt:nostars"); await safeShot("flair-nostars"); fpsNoStars = await sampleFps(ac.page, SAMPLE_MS); console.log(` 📊 no stars → ${fpsNoStars.toFixed(1)} fps (products still on)`); expect(fpsNoStars > 0, "measured a frame rate with starfield+cube off"); });
await scenario("fps with flair OFF (prompt:noflair)", async (expect) => { await bootLoose("prompt:noflair"); await safeShot("flair-off"); fpsOff = await sampleFps(ac.page, SAMPLE_MS); console.log(` 📊 flair OFF → ${fpsOff.toFixed(1)} fps`); expect(fpsOff > 0, "measured a frame rate with flair off"); });
await scenario("frame-rate health + flair comparison", async (expect) => { if (fpsOn == null || fpsOff == null) { expect(false, "both samples present"); return; } const pct = ((fpsOff - fpsOn) / fpsOn) * 100; const ns = fpsNoStars != null ? ` nostars=${fpsNoStars.toFixed(1)}` : ""; console.log( ` 📊 on=${fpsOn.toFixed(1)}${ns} off=${fpsOff.toFixed(1)} Δ(on→off)=${pct.toFixed(1)}%`, );
// Default assertion: every flair state must render at a healthy rate. This // catches real regressions (flair breaking the render loop) while staying // green despite headless rAF noise. The on/off *ordering* is only asserted // in STRICT mode (meaningful on real hardware via test:flair-fps:headed), // because in headless the GPU/worker cost doesn't surface and run-to-run // jitter routinely exceeds the real delta. const FLOOR = parseFloat(process.env.FLAIR_FPS_FLOOR || "30"); expect(fpsOn >= FLOOR, `flair-on renders ≥ ${FLOOR}fps (${fpsOn.toFixed(1)})`); expect(fpsOff >= FLOOR, `flair-off renders ≥ ${FLOOR}fps (${fpsOff.toFixed(1)})`); if (fpsNoStars != null) { expect( fpsNoStars >= FLOOR, `nostars renders ≥ ${FLOOR}fps (${fpsNoStars.toFixed(1)})`, ); }
if (STRICT) { const noise = fpsOn * 0.05; expect( fpsOff > fpsOn + noise, `flair-off measurably faster than flair-on (strict): ` + `${fpsOff.toFixed(1)} > ${fpsOn.toFixed(1)}`, ); } else { console.log( " ℹ️ ordering not asserted (headless noise) — run " + "`npm run test:flair-fps:headed` with FLAIR_FPS_STRICT=1 on real hardware.", ); } });} finally { await ac.close();}
process.exit(report());