Monorepo for Aesthetic.Computer aesthetic.computer
at main 58 lines 1.6 kB view raw
1import { readFileSync } from "fs"; 2import { basename } from "path"; 3import { Compiler } from "./compiler.mjs"; 4 5export function hashString(text) { 6 let hash = 0x811c9dc5; 7 for (let i = 0; i < text.length; i += 1) { 8 hash ^= text.charCodeAt(i); 9 hash = Math.imul(hash, 0x01000193); 10 } 11 return hash >>> 0; 12} 13 14export function createSeededRandom(seed) { 15 let state = (seed >>> 0) || 1; 16 return () => { 17 state ^= state << 13; 18 state ^= state >>> 17; 19 state ^= state << 5; 20 return (state >>> 0) / 0x100000000; 21 }; 22} 23 24export function createMathImports(random = Math.random) { 25 return { 26 math: { 27 sin: (x) => Math.fround(Math.sin(x)), 28 cos: (x) => Math.fround(Math.cos(x)), 29 random: () => Math.fround(random()), 30 }, 31 }; 32} 33 34export function loadPiece(input) { 35 const path = new URL(input, import.meta.url).pathname; 36 const source = readFileSync(path, "utf-8"); 37 return { 38 input, 39 path, 40 source, 41 name: basename(input, ".lisp"), 42 }; 43} 44 45export async function instantiatePiece(source, options = {}) { 46 const compiler = new Compiler(); 47 const wasmBytes = compiler.compile(source); 48 const seed = options.seed ?? hashString(source); 49 const random = options.random ?? createSeededRandom(seed); 50 const { instance } = await WebAssembly.instantiate(wasmBytes, createMathImports(random)); 51 return { instance, wasmBytes, seed }; 52} 53 54export function renderFrame(instance, width, height, frame) { 55 instance.exports.paint(width, height, frame); 56 const byteLength = width * height * 4; 57 return new Uint8Array(instance.exports.memory.buffer, 0, byteLength).slice(); 58}