#!/usr/bin/env bun import { mkdir, readdir, rm } from "node:fs/promises"; import { join } from "node:path"; import { $ } from "bun"; const OUTPUT_DIR = join(import.meta.dir, "../output"); const VIS_DIR = join(import.meta.dir, "../vis"); console.log("šŸŽØ Generating all visualizations...\n"); // Clean output directory await rm(OUTPUT_DIR, { recursive: true, force: true }); await mkdir(OUTPUT_DIR, { recursive: true }); // Auto-detect days from vis directory const entries = await readdir(VIS_DIR, { withFileTypes: true }); const days = entries .filter((entry) => entry.isDirectory() && /^\d{2}$/.test(entry.name)) .map((entry) => entry.name) .sort(); // Generate each day's visualization for (const day of days) { console.log(`šŸ“Š Day ${day}...`); const dayDir = join(VIS_DIR, day); const generateScript = join(dayDir, "generate.ts"); // Run the generator await $`cd ${dayDir} && bun ${generateScript}`; // Copy the output to the output directory const outputDayDir = join(OUTPUT_DIR, day); await mkdir(outputDayDir, { recursive: true }); await $`cp ${join(dayDir, "index.html")} ${outputDayDir}/index.html`; console.log(` āœ“ Generated ${day}`); } // Generate index page console.log("\nšŸ“„ Generating index page..."); // Day metadata const dayInfo: Record = { "04": { title: "Paper Removal", description: "Watch papers being removed layer by layer from a grid. Papers with fewer than 4 neighbors (including diagonals) are accessible and removed each iteration.", }, "06": { title: "Cephalopod Math", description: "Learn to read numbers like a cephalopod! Part 1 reads numbers vertically down columns, Part 2 reads digits column-by-column from right to left.", }, "07": { title: "Tachyon Beam Splitting", description: "Watch tachyon beams split as they travel through a manifold. Each splitter (^) stops a beam and creates two new beams extending left and right.", }, "08": { title: "Playground Junction Boxes", description: "3D visualization of junction boxes being connected by their shortest distances. Watch circuits form as connections merge isolated boxes into larger groups.", }, "09": { title: "Movie Theater Floor", description: "Find the largest rectangle using red tiles as opposite corners. Part 1 allows any rectangle, Part 2 requires rectangles to only contain red/green tiles.", }, "10": { title: "Factory Machines", description: "Configure indicator lights by pressing buttons that toggle specific lights. Find the minimum number of button presses to match the target configuration.", }, }; const dayCards = days .map((day) => { const info = dayInfo[day]; if (!info) return ""; return `
  • Day ${parseInt(day, 10)}: ${info.title} **
    ${info.description}
  • `; }) .join("\n"); const indexHtml = ` Advent of Code 2025 - Visualizations

    Advent of Code 2025 - Visualizations

    Interactive Problem Visualizations

      ${dayCards}
    `; await Bun.write(join(OUTPUT_DIR, "index.html"), indexHtml); console.log("\n✨ All visualizations generated successfully!"); console.log(`šŸ“ Output directory: ${OUTPUT_DIR}`); console.log(`🌐 Open ${join(OUTPUT_DIR, "index.html")} to view\n`);