Monorepo for Aesthetic.Computer
aesthetic.computer
1#!/usr/bin/env node
2// Render KidLisp pieces to PNG via self-contained WASM.
3
4import { readFileSync, mkdirSync } from "fs";
5import { basename } from "path";
6import sharp from "sharp";
7import { Compiler } from "./compiler.mjs";
8
9const OUT_DIR = new URL("./output/", import.meta.url).pathname;
10mkdirSync(OUT_DIR, { recursive: true });
11
12const pieces = process.argv.slice(2);
13if (pieces.length === 0) pieces.push("hello.lisp");
14
15const WIDTH = 256;
16const HEIGHT = 256;
17
18for (const input of pieces) {
19 const path = new URL(input, import.meta.url).pathname;
20 const source = readFileSync(path, "utf-8");
21 const name = basename(input, ".lisp");
22
23 const compiler = new Compiler();
24 const wasmBytes = compiler.compile(source);
25 const mathImports = {
26 math: {
27 sin: (x) => Math.fround(Math.sin(x)),
28 cos: (x) => Math.fround(Math.cos(x)),
29 random: () => Math.fround(Math.random()),
30 },
31 };
32 const { instance } = await WebAssembly.instantiate(wasmBytes, mathImports);
33 instance.exports.paint(WIDTH, HEIGHT, 0);
34
35 const mem = new Uint8Array(instance.exports.memory.buffer);
36 const pixels = mem.slice(0, WIDTH * HEIGHT * 4);
37
38 const png = await sharp(Buffer.from(pixels), {
39 raw: { width: WIDTH, height: HEIGHT, channels: 4 },
40 }).png().toBuffer();
41
42 const outPath = `${OUT_DIR}${name}.png`;
43 await sharp(png).toFile(outPath);
44 console.log(`${name}.png (${WIDTH}x${HEIGHT}, ${wasmBytes.length}B wasm → ${png.length}B png)`);
45}