mirror of
https://github.com/samvallad33/vestige.git
synced 2026-07-24 23:41:01 +02:00
chore(launch): remove one-time verify scripts leaking private absolute paths
verify-launch.mjs / verify-launch-mobile.mjs were throwaway Playwright screenshot scripts hardcoding /Users/entity002/... paths (incl. a Desktop testimonial dir and the retired vestige-launch-main worktree). Nothing references them; they violate public-repo hygiene. Removed before publishing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
6e3cc4439a
commit
02746d4b91
2 changed files with 0 additions and 399 deletions
|
|
@ -1,182 +0,0 @@
|
|||
import pw from '/Users/entity002/vestige-launch-main/node_modules/.pnpm/playwright@1.58.2/node_modules/playwright/index.js';
|
||||
import { mkdirSync } from 'node:fs';
|
||||
|
||||
const { chromium } = pw;
|
||||
const URL = process.env.LAUNCH_URL || 'http://127.0.0.1:5180/dashboard/launch';
|
||||
const OUT_DIR = '/tmp/vestige-launch-mobile';
|
||||
mkdirSync(OUT_DIR, { recursive: true });
|
||||
|
||||
async function snapshot(page, label) {
|
||||
const facts = await page.evaluate((snapshotLabel) => {
|
||||
const engine = document.querySelector('.raw-vestige-engine');
|
||||
const gpu = document.querySelector('.gpu-canvas');
|
||||
const fallback = document.querySelector('.fallback-canvas');
|
||||
const instantCanvas = document.querySelector('.instant-canvas');
|
||||
const wordmarkBridge = document.querySelector('.wordmark-bridge');
|
||||
const signSvg = document.querySelector('.sign-svg');
|
||||
const input = document.querySelector('.email');
|
||||
const rectFor = (el) => {
|
||||
if (!el) return null;
|
||||
const r = el.getBoundingClientRect();
|
||||
const style = getComputedStyle(el);
|
||||
return {
|
||||
w: Math.round(r.width),
|
||||
h: Math.round(r.height),
|
||||
top: Math.round(r.top),
|
||||
left: Math.round(r.left),
|
||||
opacity: style.opacity,
|
||||
display: style.display,
|
||||
visibility: style.visibility
|
||||
};
|
||||
};
|
||||
return {
|
||||
label: snapshotLabel,
|
||||
mode: engine?.getAttribute('data-mode') ?? 'missing',
|
||||
engine: rectFor(engine),
|
||||
gpu: rectFor(gpu),
|
||||
fallback: rectFor(fallback),
|
||||
instantCanvas: rectFor(instantCanvas),
|
||||
wordmarkBridge: rectFor(wordmarkBridge),
|
||||
signSvg: rectFor(signSvg),
|
||||
signPathCount: document.querySelectorAll('.sign-svg path').length,
|
||||
input: rectFor(input),
|
||||
bodyText: document.body.innerText.trim().slice(0, 120),
|
||||
webgpu: Boolean(navigator.gpu),
|
||||
viewport: { w: window.innerWidth, h: window.innerHeight, dpr: window.devicePixelRatio }
|
||||
};
|
||||
}, label);
|
||||
|
||||
await page.screenshot({ path: `${OUT_DIR}/${label}.png`, fullPage: false });
|
||||
return facts;
|
||||
}
|
||||
|
||||
async function sampleFallbackPixels(page) {
|
||||
return page.evaluate(() => {
|
||||
const c = document.querySelector('.fallback-canvas');
|
||||
if (!c || c.width < 2 || c.height < 2) return { ok: false, reason: 'no sized fallback canvas' };
|
||||
const sample = document.createElement('canvas');
|
||||
sample.width = 120;
|
||||
sample.height = 180;
|
||||
const ctx = sample.getContext('2d');
|
||||
if (!ctx) return { ok: false, reason: 'no 2d context' };
|
||||
try {
|
||||
ctx.drawImage(c, 0, 0, sample.width, sample.height);
|
||||
const data = ctx.getImageData(0, 0, sample.width, sample.height).data;
|
||||
let lit = 0;
|
||||
let max = 0;
|
||||
for (let i = 0; i < data.length; i += 4) {
|
||||
const lum = (data[i] + data[i + 1] + data[i + 2]) / 3;
|
||||
if (lum > 18) lit += 1;
|
||||
max = Math.max(max, data[i], data[i + 1], data[i + 2]);
|
||||
}
|
||||
return {
|
||||
ok: true,
|
||||
width: c.width,
|
||||
height: c.height,
|
||||
litFraction: +(lit / (data.length / 4)).toFixed(3),
|
||||
maxChannel: max
|
||||
};
|
||||
} catch (error) {
|
||||
return { ok: false, reason: String(error).slice(0, 120) };
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const browser = await chromium.launch({
|
||||
headless: true,
|
||||
args: [
|
||||
'--enable-unsafe-webgpu',
|
||||
'--enable-features=Vulkan,WebGPU',
|
||||
'--ignore-gpu-blocklist',
|
||||
'--use-gl=angle'
|
||||
]
|
||||
});
|
||||
const context = await browser.newContext({
|
||||
viewport: { width: 390, height: 844 },
|
||||
deviceScaleFactor: 3,
|
||||
isMobile: true,
|
||||
hasTouch: true
|
||||
});
|
||||
const page = await context.newPage();
|
||||
const consoleIssues = [];
|
||||
page.on('console', (message) => {
|
||||
if (['error', 'warning'].includes(message.type())) {
|
||||
consoleIssues.push(`${message.type()}: ${message.text()}`);
|
||||
}
|
||||
});
|
||||
page.on('pageerror', (error) => consoleIssues.push(`pageerror: ${error.message}`));
|
||||
|
||||
const rounds = [];
|
||||
for (let i = 0; i < 4; i += 1) {
|
||||
const started = Date.now();
|
||||
await page.goto(URL, { waitUntil: 'domcontentloaded' });
|
||||
const domcontentloadedMs = Date.now() - started;
|
||||
await page.waitForTimeout(120);
|
||||
const t120 = await snapshot(page, `reload-${i}-120ms`);
|
||||
await page.waitForTimeout(480);
|
||||
const t600 = await snapshot(page, `reload-${i}-600ms`);
|
||||
const pixels600 = await sampleFallbackPixels(page);
|
||||
await page.waitForTimeout(900);
|
||||
const t1500 = await snapshot(page, `reload-${i}-1500ms`);
|
||||
await page.waitForTimeout(1300);
|
||||
const t2800 = await snapshot(page, `reload-${i}-2800ms`);
|
||||
rounds.push({ i, domcontentloadedMs, t120, t600, pixels600, t1500, t2800 });
|
||||
await page.reload({ waitUntil: 'domcontentloaded' });
|
||||
}
|
||||
|
||||
await context.close();
|
||||
await browser.close();
|
||||
|
||||
const failures = [];
|
||||
const opacityNumber = (value) => Number.parseFloat(value ?? '0') || 0;
|
||||
const bridgeVisible = (snap) =>
|
||||
Boolean(
|
||||
snap.instantCanvas &&
|
||||
snap.instantCanvas.w >= 350 &&
|
||||
snap.instantCanvas.h >= 760 &&
|
||||
opacityNumber(snap.instantCanvas.opacity) >= 0.9
|
||||
);
|
||||
for (const round of rounds) {
|
||||
for (const snap of [round.t120, round.t600, round.t1500, round.t2800]) {
|
||||
if (snap.mode === 'missing') {
|
||||
if (!bridgeVisible(snap)) {
|
||||
failures.push(`reload ${round.i} ${snap.label}: engine missing and instant 3D bridge not visible`);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (snap.webgpu) {
|
||||
if (snap.mode === 'fallback') {
|
||||
failures.push(`reload ${round.i} ${snap.label}: fallback appeared before WebGPU`);
|
||||
}
|
||||
if (opacityNumber(snap.fallback?.opacity) > 0.01) {
|
||||
failures.push(`reload ${round.i} ${snap.label}: fallback canvas is visible on WebGPU path`);
|
||||
}
|
||||
if (snap.mode === 'booting') {
|
||||
if (!bridgeVisible(snap)) {
|
||||
failures.push(`reload ${round.i} ${snap.label}: instant 3D bridge not visible during boot`);
|
||||
}
|
||||
}
|
||||
} else if (!snap.fallback || snap.fallback.w < 350 || snap.fallback.h < 760) {
|
||||
failures.push(`reload ${round.i} ${snap.label}: fallback canvas not viewport-sized without WebGPU`);
|
||||
}
|
||||
if (!snap.wordmarkBridge && !snap.signSvg) {
|
||||
failures.push(`reload ${round.i} ${snap.label}: no wordmark bridge/svg`);
|
||||
}
|
||||
if (!snap.input || snap.input.w < 250) {
|
||||
failures.push(`reload ${round.i} ${snap.label}: signup input not visible`);
|
||||
}
|
||||
}
|
||||
if (!round.t600.webgpu && (!round.pixels600.ok || round.pixels600.litFraction < 0.02)) {
|
||||
failures.push(`reload ${round.i}: fallback pixels not lit at 600ms`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(JSON.stringify({ url: URL, rounds, consoleIssues, failures, screenshotDir: OUT_DIR }, null, 2));
|
||||
if (failures.length) process.exit(1);
|
||||
}
|
||||
|
||||
main().catch((error) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
|
|
@ -1,217 +0,0 @@
|
|||
import pw from '/Users/entity002/vestige-launch-main/node_modules/.pnpm/playwright@1.58.2/node_modules/playwright/index.js';
|
||||
const { chromium } = pw;
|
||||
|
||||
const URL = 'http://127.0.0.1:5180/dashboard/launch';
|
||||
const OUT_DESKTOP = '/Users/entity002/Desktop/vestige-testimonial/vestige-launch-node-only-final-desktop.png';
|
||||
const OUT_MOBILE = '/Users/entity002/Desktop/vestige-testimonial/vestige-launch-node-only-final-mobile.png';
|
||||
|
||||
const consoleErrors = [];
|
||||
|
||||
async function run() {
|
||||
const browser = await chromium.launch({
|
||||
headless: true,
|
||||
args: [
|
||||
'--enable-unsafe-webgpu',
|
||||
'--enable-features=Vulkan,WebGPU',
|
||||
'--use-angle=metal',
|
||||
'--ignore-gpu-blocklist',
|
||||
'--use-gl=angle'
|
||||
]
|
||||
});
|
||||
|
||||
// ---- DESKTOP ----
|
||||
const ctx = await browser.newContext({
|
||||
viewport: { width: 1440, height: 900 },
|
||||
deviceScaleFactor: 2
|
||||
});
|
||||
const page = await ctx.newPage();
|
||||
page.on('console', (m) => {
|
||||
if (m.type() === 'error') consoleErrors.push('[console.error] ' + m.text());
|
||||
});
|
||||
page.on('pageerror', (e) => consoleErrors.push('[pageerror] ' + e.message));
|
||||
|
||||
await page.goto(URL, { waitUntil: 'networkidle' });
|
||||
// let WebGPU boot, then wait deep into the loop so we capture the HOLD beat
|
||||
// (formed, dense formation) rather than the sparse STREAM/DISSOLVE beats.
|
||||
// loop = 20s; phase ~0.5 (deep hold) lands around t=10s after start.
|
||||
await page.waitForTimeout(10000);
|
||||
|
||||
const checks = await page.evaluate(() => {
|
||||
const engine = document.querySelector('.raw-vestige-engine');
|
||||
const canvases = Array.from(document.querySelectorAll('canvas'));
|
||||
const banned = document.querySelectorAll('svg,line,path,circle,[stroke]');
|
||||
const cov = canvases.map((c) => {
|
||||
const r = c.getBoundingClientRect();
|
||||
return {
|
||||
cls: c.className,
|
||||
w: Math.round(r.width),
|
||||
h: Math.round(r.height),
|
||||
coversW: r.width >= window.innerWidth - 2,
|
||||
coversH: r.height >= window.innerHeight - 2,
|
||||
opacity: getComputedStyle(c).opacity
|
||||
};
|
||||
});
|
||||
return {
|
||||
innerTextEmpty: document.body.innerText.trim() === '',
|
||||
innerTextValue: JSON.stringify(document.body.innerText.trim()).slice(0, 80),
|
||||
bannedCount: banned.length,
|
||||
dataMode: engine ? engine.getAttribute('data-mode') : 'NO_ENGINE',
|
||||
canvasCount: canvases.length,
|
||||
coverage: cov,
|
||||
webgpuAvailable: !!navigator.gpu,
|
||||
viewport: { w: window.innerWidth, h: window.innerHeight }
|
||||
};
|
||||
});
|
||||
|
||||
// sample pixels off the visible canvas to confirm: not white, bright, dense, colorful
|
||||
const pixelStats = await page.evaluate(async () => {
|
||||
const engine = document.querySelector('.raw-vestige-engine');
|
||||
const mode = engine?.getAttribute('data-mode');
|
||||
const cls = mode === 'fallback' ? '.fallback-canvas' : '.gpu-canvas';
|
||||
const c = document.querySelector(cls);
|
||||
if (!c) return { error: 'no canvas for mode ' + mode };
|
||||
// draw the (possibly webgpu) canvas onto a 2d sampler canvas
|
||||
const s = document.createElement('canvas');
|
||||
s.width = 200;
|
||||
s.height = 120;
|
||||
const g = s.getContext('2d');
|
||||
try {
|
||||
g.drawImage(c, 0, 0, 200, 120);
|
||||
} catch (e) {
|
||||
return { error: 'drawImage failed: ' + e.message };
|
||||
}
|
||||
const data = g.getImageData(0, 0, 200, 120).data;
|
||||
let lit = 0;
|
||||
let white = 0;
|
||||
let rSum = 0;
|
||||
let gSum = 0;
|
||||
let bSum = 0;
|
||||
let maxChan = 0;
|
||||
const n = data.length / 4;
|
||||
for (let i = 0; i < data.length; i += 4) {
|
||||
const r = data[i];
|
||||
const gg = data[i + 1];
|
||||
const b = data[i + 2];
|
||||
const lum = (r + gg + b) / 3;
|
||||
if (lum > 18) lit++;
|
||||
if (r > 240 && gg > 240 && b > 240) white++;
|
||||
rSum += r;
|
||||
gSum += gg;
|
||||
bSum += b;
|
||||
maxChan = Math.max(maxChan, r, gg, b);
|
||||
}
|
||||
// color spread: difference between channel averages signals "colorful" not gray
|
||||
const ra = rSum / n;
|
||||
const ga = gSum / n;
|
||||
const ba = bSum / n;
|
||||
const spread = Math.max(ra, ga, ba) - Math.min(ra, ga, ba);
|
||||
return {
|
||||
litFraction: +(lit / n).toFixed(3),
|
||||
whiteFraction: +(white / n).toFixed(4),
|
||||
avg: { r: +ra.toFixed(1), g: +ga.toFixed(1), b: +ba.toFixed(1) },
|
||||
colorSpread: +spread.toFixed(1),
|
||||
brightestChannel: maxChan
|
||||
};
|
||||
});
|
||||
|
||||
await page.screenshot({ path: OUT_DESKTOP });
|
||||
|
||||
// brightness/coverage proof from the ACTUAL screenshot PNG (reliable, unlike
|
||||
// GPU-canvas drawImage readback which returns black for a webgpu context).
|
||||
const shotBuf = await page.screenshot({ type: 'png' });
|
||||
|
||||
// pointer interaction smoke: move mouse across center, ensure no crash
|
||||
await page.mouse.move(400, 400);
|
||||
await page.mouse.move(900, 500, { steps: 10 });
|
||||
await page.waitForTimeout(800);
|
||||
|
||||
// extra phase-spaced captures so we can see several formations cycle
|
||||
for (let k = 0; k < 3; k++) {
|
||||
await page.waitForTimeout(6500);
|
||||
await page.screenshot({ path: `/tmp/launch-phase-${k}.png` });
|
||||
}
|
||||
|
||||
await ctx.close();
|
||||
|
||||
// ---- MOBILE ----
|
||||
const mctx = await browser.newContext({
|
||||
viewport: { width: 390, height: 844 },
|
||||
deviceScaleFactor: 3,
|
||||
isMobile: true
|
||||
});
|
||||
const mpage = await mctx.newPage();
|
||||
mpage.on('pageerror', (e) => consoleErrors.push('[mobile pageerror] ' + e.message));
|
||||
await mpage.goto(URL, { waitUntil: 'networkidle' });
|
||||
await mpage.waitForTimeout(4000);
|
||||
const mMode = await mpage.evaluate(
|
||||
() => document.querySelector('.raw-vestige-engine')?.getAttribute('data-mode')
|
||||
);
|
||||
await mpage.screenshot({ path: OUT_MOBILE });
|
||||
await mctx.close();
|
||||
|
||||
await browser.close();
|
||||
|
||||
// decode the desktop screenshot PNG for honest brightness/colorfulness stats.
|
||||
const shotStats = await analyzePng(shotBuf);
|
||||
|
||||
console.log(
|
||||
JSON.stringify(
|
||||
{ checks, pixelStats, shotStats, mobileMode: mMode, consoleErrors },
|
||||
null,
|
||||
2
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Minimal PNG decoder via the platform's ImageDecoder is unavailable in node, so
|
||||
// use sharp if present; otherwise fall back to a coarse byte-histogram of the
|
||||
// raw PNG (good enough to confirm "not all black / has color").
|
||||
async function analyzePng(buf) {
|
||||
try {
|
||||
const sharpMod = await import(
|
||||
'/Users/entity002/vestige-launch-main/node_modules/.pnpm/node_modules/sharp/lib/index.js'
|
||||
).catch(() => null);
|
||||
if (sharpMod && sharpMod.default) {
|
||||
const sharp = sharpMod.default;
|
||||
const { data, info } = await sharp(buf)
|
||||
.resize(240, 150, { fit: 'fill' })
|
||||
.raw()
|
||||
.toBuffer({ resolveWithObject: true });
|
||||
const ch = info.channels;
|
||||
let lit = 0;
|
||||
let white = 0;
|
||||
let rS = 0;
|
||||
let gS = 0;
|
||||
let bS = 0;
|
||||
const n = info.width * info.height;
|
||||
for (let i = 0; i < data.length; i += ch) {
|
||||
const r = data[i];
|
||||
const g = data[i + 1];
|
||||
const b = data[i + 2];
|
||||
if ((r + g + b) / 3 > 16) lit++;
|
||||
if (r > 240 && g > 240 && b > 240) white++;
|
||||
rS += r;
|
||||
gS += g;
|
||||
bS += b;
|
||||
}
|
||||
const ra = rS / n;
|
||||
const ga = gS / n;
|
||||
const ba = bS / n;
|
||||
return {
|
||||
decoder: 'sharp',
|
||||
litFraction: +(lit / n).toFixed(3),
|
||||
whiteFraction: +(white / n).toFixed(4),
|
||||
avg: { r: +ra.toFixed(1), g: +ga.toFixed(1), b: +ba.toFixed(1) },
|
||||
colorSpread: +(Math.max(ra, ga, ba) - Math.min(ra, ga, ba)).toFixed(1)
|
||||
};
|
||||
}
|
||||
} catch (e) {
|
||||
return { decoder: 'failed', error: String(e).slice(0, 120) };
|
||||
}
|
||||
return { decoder: 'none', note: 'sharp unavailable; rely on screenshot file' };
|
||||
}
|
||||
|
||||
run().catch((e) => {
|
||||
console.error('VERIFY FAILED:', e);
|
||||
process.exit(1);
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue