Something went wrong. Try again.
Monorepo for Aesthetic.Computer aesthetic.computer
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113// runtimes.mjs — the piece languages Aesthetic Computer can run.//// A piece is JavaScript, KidLisp, or Lua, chosen by file extension. The blank// templates are the starting point for a session's piece: each one paints a// flat color on its own so a phone pointed at the QR code has an image// immediately, before the agent has written anything. The blank does not write// its own name — the system's corner label already shows it, and a name left// in the source tends to survive the agent's first edit as clutter.
const randomBackdrop=()=>Array.from({length:3},()=>Math.floor(Math.random()*256));const randomCSSBackdrop=()=> '#'+randomBackdrop().map(n=>n.toString(16).padStart(2,'0')).join('');
export const RUNTIMES = { mjs: { id: "mjs", label: "javascript", extension: ".mjs", mime: "application/javascript; charset=utf-8", // The handled-piece loader resolves .mjs and .lisp under an @handle. routable: true, blank: (name) => `// ${name}, ${stamp()}// A blank Aesthetic Computer piece.
function paint({ wipe }) { wipe("${randomCSSBackdrop()}"); return false; // Painted once; return true to keep painting.}
export { paint };`, }, lisp: { id: "lisp", label: "kidlisp", extension: ".lisp", mime: "text/x-lisp; charset=utf-8", routable: true, blank: (name) => `; ${name}, ${stamp()}(wipe "${randomCSSBackdrop()}")`, }, lua: { id: "lua", label: "processing", extension: ".lua", mime: "text/x-lua; charset=utf-8", // Lua is the language of L5, Aesthetic Computer's Processing surface, so a // piece here is written in Processing's vocabulary — setup and draw, not // paint — against `lib/l5.mjs`. // // The shape of the blank is load-bearing. A push over the code channel // carries only { piece, source, codeChannel }: no extension, no language. // The client recognises Lua in that message by reading the source — it must // begin with a `--` comment AND declare `function setup(` or `function // draw(` — and anything else is compiled as JavaScript and fails. Both are // natural in real L5, and this blank keeps them. routable: false, blank: (name) => `-- ${name}, ${stamp()}-- A blank Aesthetic Computer piece, in Processing (L5).
function setup() noStroke()end
function draw() background(${randomBackdrop().join(", ")})end`, },};
// Some runtimes answer to more than one name. Lua is the language; Processing// is what it is for.export const RUNTIME_ALIASES = { processing: "lua", l5: "lua", js: "mjs", kidlisp: "lisp" };
export const DEFAULT_RUNTIME = "mjs";
export function stamp(date = new Date()) { const pad = (value) => String(value).padStart(2, "0"); return [ String(date.getFullYear()).slice(2), pad(date.getMonth() + 1), pad(date.getDate()), ].join(".");}
export function runtimeIds() { return Object.keys(RUNTIMES);}
// How the runtimes read in the interface: the id to type, named by what it is// where the two differ. `lua` is the one worth spelling out — nobody comes// looking for Lua, they come looking for Processing.export function runtimeMenu() { return runtimeIds() .map((id) => (RUNTIMES[id].label === id ? id : `${id} (${RUNTIMES[id].label})`)) .join(", ");}
export function runtimeFor(id) { const wanted = String(id || "").replace(/^\./, "").toLowerCase(); const runtime = RUNTIMES[RUNTIME_ALIASES[wanted] || wanted]; if (!runtime) { throw new Error(`unknown runtime "${id}" — try ${runtimeIds().join(", ")}`); } return runtime;}
export function runtimeForExtension(extension) { const wanted = String(extension || "").toLowerCase(); return Object.values(RUNTIMES).find((runtime) => runtime.extension === wanted) || null;}