canvas-lang
Version:
A simple ASCII graphics language for the terminal
89 lines (81 loc) • 2.94 kB
JavaScript
import { drawCircle, drawRect, drawText, drawLine, bgColor, rainbowColor } from './renderer.js';
import { setTimeout as delay } from 'node:timers/promises';
import updateLog from 'log-update';
// Interpreter
export const interpretAST = async (ast) => {
let canvasOutput = "";
let backgroundColor = "black";
let variables = {};
let frames = [];
const renderCommand = async (command, frameOutput = "") => {
switch (command.type) {
case "background":
backgroundColor = command.color;
break;
case "circle":
return frameOutput + drawCircle(command.radius, command.fill);
case "rect":
return frameOutput + drawRect(command.width, command.height, command.fill);
case "text":
return frameOutput + await drawText(command.text, command.color, command.size);
case "line":
return frameOutput + drawLine(command.x1, command.y1, command.x2, command.y2, command.color);
case "variable":
variables[command.name] = command.value;
break;
case "wait":
await delay(command.duration);
return frameOutput; // Make sure to return the current frameOutput
case "rainbow":
for (let i = 0; i < command.duration; i++) {
const rainbowText = rainbowColor(command.text, i);
updateLog(bgColor(backgroundColor)(frameOutput + rainbowText));
await delay(10);
}
return frameOutput;
case "frame":
let frameContent = "";
for (const cmd of command.commands) {
frameContent = await renderCommand(cmd, frameContent);
}
frames.push(frameContent);
return frameOutput;
case "animate":
let animContent = "";
const animFrames = [];
for (const frame of command.frames) {
if (frame.type === "frame") {
let frameContent = "";
for (const cmd of frame.commands) {
frameContent = await renderCommand(cmd, frameContent);
}
animFrames.push(frameContent);
}
}
const frameDelay = Math.max(50, Math.floor(command.duration / animFrames.length));
for (let i = 0; i < command.duration / frameDelay; i++) {
const frameIndex = i % animFrames.length;
updateLog(bgColor(backgroundColor)(animFrames[frameIndex]));
await delay(frameDelay);
}
return frameOutput;
}
return frameOutput;
};
// Process all commands
for (const command of ast.commands) {
canvasOutput = await renderCommand(command, canvasOutput);
}
// If we have frames, animate them
if (frames.length > 0) {
while (true) {
for (const frame of frames) {
updateLog(bgColor(backgroundColor)(frame));
await delay(100);
}
}
} else {
// Final output
console.log(bgColor(backgroundColor)(canvasOutput));
}
};