Something went wrong. Try again.
Monorepo for Aesthetic.Computer aesthetic.computer
Something went wrong. Try again.
JavaScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293#!/usr/bin/env node// tezos/series/preview-shots.mjs//// Preview the series WITHOUT the Electron app or login: every piece runs on// production AC via an inline-source URL. Prints clickable links (live,// animated) and headlessly screenshots each (via chrome-shot) so we can verify// each one actually renders before minting.//// Usage:// node tezos/series/preview-shots.mjs # links + stills for all// node tezos/series/preview-shots.mjs --series clock// node tezos/series/preview-shots.mjs --no-shots # just print URLs// node tezos/series/preview-shots.mjs --one feedback/drift # single piece
import fs from "fs";import path from "path";import { spawnSync } from "child_process";import { fileURLToPath } from "url";
const __dirname = path.dirname(fileURLToPath(import.meta.url));const REPO = path.resolve(__dirname, "../..");const MANIFEST = path.join(__dirname, "manifest.json");const THUMBS = path.join(__dirname, "thumbs");const CHROME_SHOT = path.join(REPO, "toolchain/macos/chrome-shot.mjs");
const argv = process.argv.slice(2);const getArg = (k, d) => { const i = argv.indexOf(`--${k}`); return i >= 0 ? argv[i + 1] : d; };const ONLY = getArg("series", null);const ONE = getArg("one", null);const noShots = argv.includes("--no-shots");
// Inline copy of encodeKidlispForUrl (kidlisp.mjs:15041) — avoids importing the// giant browser module into node. Keep in sync if the encoder changes.function encodeKidlispForUrl(source) { return source .replace(/ /g, "_") .replace(/\n/g, "§") .replace(/%/g, "¤") .replace(/;/g, "¨") .replace(/#/g, "%23");}
// Comment lines (the `; series · title` marker) are noise in a preview URL —// strip them so the link is clean and starts at the first real expression.// The minted source keeps its comment; this only affects the preview link.function stripForUrl(source) { return source .split("\n") .filter((l) => l.trim() && !l.trim().startsWith(";")) .join("\n");}
const manifest = JSON.parse(fs.readFileSync(MANIFEST, "utf8"));if (!noShots) fs.mkdirSync(THUMBS, { recursive: true });
const pieces = [];for (const [name, list] of Object.entries(manifest.series)) { if (ONLY && name !== ONLY) continue; for (const it of list) { if (ONE && `${name}/${it.title}` !== ONE) continue; pieces.push({ name, ...it }); }}
console.log(`\n🔗 Live preview links (production — click to run, animated):\n`);for (const p of pieces) { const enc = encodeKidlispForUrl(stripForUrl(p.source)); p.url = `https://aesthetic.computer/${enc}`; console.log(` ${`${p.name}/${p.title}`.padEnd(18)} ${p.url}`);}
if (noShots) process.exit(0);
console.log(`\n📸 Rendering stills (headless, sequential) → ${path.relative(REPO, THUMBS)}/\n`);const results = [];for (const p of pieces) { const out = path.join(THUMBS, `${p.name}-${p.title}.png`); const r = spawnSync("node", [ CHROME_SHOT, `${p.url}?nogap=true`, out, "--size", "480x480", "--budget", "6000", "--wait", "40000", ], { stdio: ["ignore", "pipe", "pipe"], encoding: "utf8" }); let ok = r.status === 0 && fs.existsSync(out); let bytes = ok ? fs.statSync(out).size : 0; if (ok && bytes < 800) ok = false; // suspiciously tiny = blank/error results.push({ id: `${p.name}/${p.title}`, ok, bytes, out }); console.log(` ${ok ? "✅" : "❌"} ${`${p.name}/${p.title}`.padEnd(18)} ${ok ? (bytes + "b") : ("status " + r.status)}`);}
const okN = results.filter((r) => r.ok).length;console.log(`\n${okN}/${results.length} rendered. Stills in ${path.relative(REPO, THUMBS)}/`);const bad = results.filter((r) => !r.ok);if (bad.length) console.log(`Needs a look: ${bad.map((b) => b.id).join(", ")}`);