Monorepo for Aesthetic.Computer aesthetic.computer
4
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 79 lines 3.2 kB view raw
1#!/usr/bin/env node 2// KidLisp WASM Runner — Verifiable Visual Compute 3// 4// The WASM module contains everything: renderer + pixel buffer + piece code. 5// This host only provides memory and reads pixels out. Nothing to fake. 6 7import { readFileSync, writeFileSync } from "fs"; 8import { Compiler } from "./compiler.mjs"; 9 10const WIDTH = parseInt(process.argv[3]) || 128; 11const HEIGHT = parseInt(process.argv[4]) || 128; 12 13const input = process.argv[2] || "hello.lisp"; 14const source = readFileSync(new URL(input, import.meta.url).pathname, "utf-8"); 15 16console.log(`Compiling ${input}...`); 17const compiler = new Compiler(); 18const wasmBytes = compiler.compile(source); 19console.log(`WASM binary: ${wasmBytes.length} bytes (self-contained renderer)`); 20 21// Instantiate — math imports only, rendering is self-contained. 22const { instance } = await WebAssembly.instantiate(wasmBytes, { 23 math: { 24 sin: (x) => Math.fround(Math.sin(x)), 25 cos: (x) => Math.fround(Math.cos(x)), 26 random: () => Math.fround(Math.random()), 27 }, 28}); 29 30console.log(`Running paint(${WIDTH}, ${HEIGHT}, 0)...`); 31instance.exports.paint(WIDTH, HEIGHT, 0); 32 33// Read pixels directly from WASM linear memory 34const mem = new Uint8Array(instance.exports.memory.buffer); 35 36// ─── Output PPM ───────────────────────────────────────────────────── 37 38const header = `P6\n${WIDTH} ${HEIGHT}\n255\n`; 39const ppm = Buffer.alloc(header.length + WIDTH * HEIGHT * 3); 40ppm.write(header); 41let offset = header.length; 42for (let i = 0; i < WIDTH * HEIGHT * 4; i += 4) { 43 ppm[offset++] = mem[i]; 44 ppm[offset++] = mem[i + 1]; 45 ppm[offset++] = mem[i + 2]; 46} 47 48const outFile = input.replace(/\.lisp$/, ".ppm"); 49writeFileSync(new URL(outFile, import.meta.url).pathname, ppm.slice(0, offset)); 50console.log(`Wrote ${outFile} (${WIDTH}x${HEIGHT})`); 51 52// ─── Terminal Preview ─────────────────────────────────────────────── 53 54const PW = Math.min(WIDTH, 64); 55const sx = WIDTH / PW; 56const sy = (HEIGHT / PW) * 2; 57 58console.log(`\nPreview (${PW} cols):`); 59for (let row = 0; row < PW; row++) { 60 let line = ""; 61 for (let col = 0; col < PW; col++) { 62 const tx = Math.floor(col * sx); 63 const ty = Math.floor(row * sy); 64 const by = Math.min(Math.floor(row * sy + sy / 2), HEIGHT - 1); 65 const ti = (ty * WIDTH + tx) * 4; 66 const bi = (by * WIDTH + tx) * 4; 67 line += `\x1b[38;2;${mem[ti]};${mem[ti+1]};${mem[ti+2]};48;2;${mem[bi]};${mem[bi+1]};${mem[bi+2]}m\u2580`; 68 } 69 process.stdout.write(line + "\x1b[0m\n"); 70} 71 72// ─── Verify ───────────────────────────────────────────────────────── 73 74// Hash the pixel buffer for verifiability 75const { createHash } = await import("crypto"); 76const pixelData = mem.slice(0, WIDTH * HEIGHT * 4); 77const hash = createHash("sha256").update(pixelData).digest("hex").slice(0, 16); 78console.log(`\nPixel hash: ${hash}`); 79console.log(`Module size: ${wasmBytes.length} bytes | Buffer: ${WIDTH}x${HEIGHT} RGBA`);