Something went wrong. Try again.
Monorepo for Aesthetic.Computer aesthetic.computer
Something went wrong. Try again.
4.4 kB · 170 lines
JavaScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171#!/usr/bin/env node// Convert font_1 JSON glyphs to GameBoy assembly tile data
import fs from 'fs';import path from 'path';import { fileURLToPath } from 'url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));const fontDir = '/workspaces/aesthetic-computer/system/public/aesthetic.computer/disks/drawings/font_1';
// Character set we want to exportconst chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 !?.,';
function rasterizeGlyph(glyphData) { const [width, height] = glyphData.resolution; const pixels = Array(height).fill().map(() => Array(width).fill(0)); // Draw lines and points for (const cmd of glyphData.commands) { if (cmd.name === 'line' && cmd.args.length >= 4) { const [x1, y1, x2, y2] = cmd.args; drawLine(pixels, x1, y1, x2, y2); } else if (cmd.name === 'point' && cmd.args.length >= 2) { const [x, y] = cmd.args; if (y >= 0 && y < height && x >= 0 && x < width) { pixels[y][x] = 1; } } } return pixels;}
function drawLine(pixels, x1, y1, x2, y2) { // Bresenham's line algorithm const dx = Math.abs(x2 - x1); const dy = Math.abs(y2 - y1); const sx = x1 < x2 ? 1 : -1; const sy = y1 < y2 ? 1 : -1; let err = dx - dy; let x = x1, y = y1; const height = pixels.length; const width = pixels[0].length; while (true) { if (y >= 0 && y < height && x >= 0 && x < width) { pixels[y][x] = 1; } if (x === x2 && y === y2) break; const e2 = 2 * err; if (e2 > -dy) { err -= dy; x += sx; } if (e2 < dx) { err += dx; y += sy; } }}
function pixelsTo2bpp(pixels) { // Convert 6x10 pixels to 8x16 GameBoy tile (2bpp format) // Pad to 8 pixels wide, extend to 16 rows (8 rows per tile in 2 tiles) const result = []; for (let row = 0; row < 16; row++) { let low = 0, high = 0; for (let col = 0; col < 8; col++) { const bit = 7 - col; // MSB first const pixel = (row < pixels.length && col < pixels[row].length) ? pixels[row][col] : 0; // For pixel value 1, set both bits (color 11 = darkest) if (pixel) { low |= (1 << bit); high |= (1 << bit); } } result.push(low, high); } return result;}
function byteToHex(byte) { return '$' + byte.toString(16).toUpperCase().padStart(2, '0');}
// Main conversionconst charMap = { ' ': 'symbols/space', '!': 'symbols/exclamation', '?': 'symbols/question mark', '.': 'symbols/period', ',': 'symbols/comma',};
// Build character-to-file mappingfor (let i = 0; i < 26; i++) { const char = String.fromCharCode(65 + i); // A-Z charMap[char] = 'uppercase';}
for (let i = 0; i < 10; i++) { charMap[i.toString()] = 'numbers';}
console.log('; Font tiles generated from font_1 JSON glyphs');console.log('; 6x10 glyphs padded to 8x16 GameBoy tiles\n');console.log('FontTiles:');
let tileIndex = 1;for (const char of chars) { const folder = charMap[char]; if (!folder) { console.log(`; Tile ${tileIndex} - '${char}' (not found)`); // Output blank tile for (let i = 0; i < 16; i++) { console.log(' DB $00, $00'); } tileIndex++; continue; } // Find the JSON file const folderPath = path.join(fontDir, folder); let jsonFile = null; try { const files = fs.readdirSync(folderPath); // Look for file starting with the character jsonFile = files.find(f => f.startsWith(char + ' ') && f.endsWith('.json')); } catch (e) { console.log(`; Tile ${tileIndex} - '${char}' (folder not found: ${folder})`); for (let i = 0; i < 16; i++) { console.log(' DB $00, $00'); } tileIndex++; continue; } if (!jsonFile) { console.log(`; Tile ${tileIndex} - '${char}' (no JSON)`); for (let i = 0; i < 16; i++) { console.log(' DB $00, $00'); } tileIndex++; continue; } const jsonPath = path.join(folderPath, jsonFile); const glyphData = JSON.parse(fs.readFileSync(jsonPath, 'utf8')); const pixels = rasterizeGlyph(glyphData); const bytes = pixelsTo2bpp(pixels); console.log(` ; Tile ${tileIndex} - '${char}'`); for (let i = 0; i < bytes.length; i += 2) { console.log(` DB ${byteToHex(bytes[i])}, ${byteToHex(bytes[i+1])}`); } tileIndex++;}
console.log('FontTilesEnd:');