← snapshot
4067 bytes
/**
* Screenshots the live orb, large, via Playwright. The in-editor browser
* pane composites unreliably at small sizes; this renders the real page and
* captures it faithfully.
*
* Subjects are reached by actually walking the UI, so what is captured is
* what a visitor sees — not a synthetic harness.
*
* node tour/orb-shot.mjs
*/
import { mkdir, rm } from "node:fs/promises";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { chromium } from "@playwright/test";
const HERE = path.dirname(fileURLToPath(import.meta.url));
const OUT = path.join(HERE, "orbs");
const BASE = process.env.TOUR_BASE ?? "http://localhost:3000";
async function main() {
await rm(OUT, { recursive: true, force: true });
await mkdir(OUT, { recursive: true });
const browser = await chromium.launch();
const page = await browser.newPage({
viewport: { width: 900, height: 760 },
deviceScaleFactor: 2,
colorScheme: "dark",
});
await page.goto(BASE, { waitUntil: "networkidle" });
await page.waitForSelector(".jac-orb-canvas", { timeout: 20000 });
const hideChrome = () =>
page.evaluate(() => {
for (const sel of [
".jac-stage-say",
".jac-stage-card",
".jac-offers",
".jac-stage-controls",
".jac-seen",
".jac-alert",
".jac-stage-switch",
".jac-stage-top",
]) {
for (const el of document.querySelectorAll(sel)) {
el.style.visibility = "hidden";
}
}
const orb = document.querySelector(".jac-orb");
if (orb) {
orb.style.setProperty(
"transform",
"translate(var(--orb-drift-x,0), var(--orb-drift-y,0)) scale(3.0)",
"important",
);
orb.style.margin = "180px auto";
}
});
const showChrome = () =>
page.evaluate(() => {
for (const sel of [
".jac-stage-say",
".jac-stage-card",
".jac-offers",
".jac-stage-controls",
".jac-seen",
".jac-alert",
".jac-stage-switch",
".jac-stage-top",
]) {
for (const el of document.querySelectorAll(sel)) {
el.style.visibility = "";
}
}
const orb = document.querySelector(".jac-orb");
if (orb) {
orb.style.removeProperty("transform");
orb.style.margin = "";
}
});
const shot = async (name, opts = {}) => {
await hideChrome();
if (opts.hoverAt) {
await page.mouse.move(opts.hoverAt[0], opts.hoverAt[1]);
await page.waitForTimeout(750);
} else {
await page.mouse.move(450, 380);
await page.waitForTimeout(600);
}
await page.waitForTimeout(700);
const subject = await page.evaluate(
() => document.querySelector(".jac-orb")?.dataset.subject ?? "?",
);
await page.screenshot({
path: path.join(OUT, `${name}.png`),
clip: { x: 200, y: 130, width: 500, height: 500 },
});
console.log(` ${name.padEnd(18)} subject=${subject}`);
await showChrome();
};
const goPlace = async (needle) => {
const t = page
.locator(".jac-offer, .jac-seen-chip")
.filter({ hasText: needle })
.first();
await t.waitFor({ state: "visible", timeout: 15000 });
await t.click();
await page.waitForTimeout(900);
};
await shot("1-lobby");
// Lean: pointer parked in the top-right corner.
await shot("1-lobby-lean", { hoverAt: [830, 150] });
const meridian = page.locator(".jac-seg button", { hasText: "Meridian" });
if (await meridian.count()) {
await meridian.first().click();
await page.waitForTimeout(1100);
}
await goPlace("blocked promotion");
await shot("2-gate");
await goPlace("session.rs");
await shot("3-file");
await goPlace("session cache");
await shot("4-decision");
await goPlace("cloth so far");
await shot("5-cloth");
await goPlace("latest pick");
await shot("6-snapshot");
await browser.close();
console.log(`-> ${OUT}`);
}
main().catch((e) => {
console.error(e);
process.exit(1);
});