// Bundles src/*.js into the single self-contained ../index.html // npm run build minified // npm run build:readable unminified, for debugging // npm run build:dev ../dev.html: unminified, plus the development tools in src/dev.js import { readFileSync, writeFileSync } from 'node:fs'; import { gzipSync } from 'node:zlib'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { transformSync } from 'esbuild'; const here = path.dirname(fileURLToPath(import.meta.url)); const FILES = ['quality.js', 'math.js', 'shaders.js', 'world.js', 'main.js', 'audio.js']; // concatenation order matters const dev = process.argv.includes('--dev'), readable = dev || process.argv.includes('--readable'); const out = dev ? 'dev.html' : 'index.html'; if (dev) FILES.push('dev.js'); let js = FILES.map((f) => readFileSync(path.join(here, 'src', f), 'utf8')).join('\n'); const tpl = readFileSync(path.join(here, 'template.html'), 'utf8'); // everything runs inside one async function; startup errors are shown on screen const wrap = (body) => `(async()=>{${body}\n})().catch(e=>{console.error(e);document.body.className='l e';document.getElementById('s').textContent=(e.cause?'':'Failed to start: ')+e.message});`; let html; if (readable) { html = tpl.replace('/*SCRIPT*/', () => wrap(js)); } else { // shrink the WGSL inside /*wgsl*/ template literals, then minify the JS and the page's CSS const minWgsl = (s) => s.replace(/\/\/[^\n]*/g, '').replace(/\s+/g, ' ').replace(/ ?([{}()\[\];,:=+\-*\/<>&|!%@]) ?/g, '$1').trim(); js = js.replace(/\/\*wgsl\*\/`([^`]*)`/g, (_, w) => '`' + minWgsl(w) + '`'); const code = transformSync(wrap(js), { minify: true, target: 'es2022', legalComments: 'none' }).code.trim(); const css = (_, s) => '