plum
git clone https://git.pyrossh.dev/plum
A statically typed, imperative programming language inspired by rust, python
908c08d
— Peter John
2026-11-02T14:08:35+05:30
T7: incidental files
- plum-game/web/screenshot.mjs +29 -0
plum-game/web/screenshot.mjs
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
// Headless Chrome screenshot after a real-time wait (Chrome's --screenshot fires before the frame loop has drawn).
|
|
4
|
+
// usage: node screenshot.mjs <url> <out.png> <seconds> <chrome-profile-dir>
|
|
5
|
+
const [url, out, secs = "12", prof] = process.argv.slice(2);
|
|
6
|
+
const chrome = spawn("/Applications/Google Chrome.app/Contents/MacOS/Google Chrome", [
|
|
7
|
+
"--headless=new", "--use-angle=swiftshader", "--enable-unsafe-swiftshader", "--window-size=1024,768",
|
|
8
|
+
"--remote-debugging-port=9333", `--user-data-dir=${prof}`, "about:blank"], { stdio: "ignore" });
|
|
9
|
+
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
10
|
+
let tabs;
|
|
11
|
+
for (let i = 0; i < 50; i++) { try { tabs = await (await fetch("http://127.0.0.1:9333/json")).json(); if (tabs.length) break; } catch {} await sleep(200); }
|
|
12
|
+
const ws = new WebSocket(tabs.find((t) => t.type === "page").webSocketDebuggerUrl);
|
|
13
|
+
await new Promise((r) => (ws.onopen = r));
|
|
14
|
+
let id = 0; const pend = new Map();
|
|
15
|
+
const send = (method, params = {}) => new Promise((r) => { pend.set(++id, r); ws.send(JSON.stringify({ id, method, params })); });
|
|
16
|
+
ws.onmessage = (m) => {
|
|
17
|
+
const d = JSON.parse(m.data);
|
|
18
|
+
if (d.id && pend.has(d.id)) return pend.get(d.id)(d.result);
|
|
19
|
+
if (d.method === "Runtime.consoleAPICalled") console.log("CONSOLE", d.params.type, d.params.args.map((a) => a.value ?? a.description).join(" ").slice(0, 200));
|
|
20
|
+
if (d.method === "Runtime.exceptionThrown") console.log("EXC", JSON.stringify(d.params.exceptionDetails.exception?.description ?? d.params.exceptionDetails.text).slice(0, 300));
|
|
21
|
+
};
|
|
22
|
+
await send("Runtime.enable");
|
|
23
|
+
await send("Page.enable");
|
|
24
|
+
await send("Page.navigate", { url });
|
|
25
|
+
await sleep(Number(secs) * 1000);
|
|
26
|
+
const shot = await send("Page.captureScreenshot", { format: "png" });
|
|
27
|
+
fs.writeFileSync(out, Buffer.from(shot.data, "base64"));
|
|
28
|
+
chrome.kill();
|
|
29
|
+
process.exit(0);
|