generate-hex-grid.js (2781B)
1 import fs from 'node:fs'; 2 import path from 'node:path'; 3 import { fileURLToPath } from 'node:url'; 4 5 const SETTINGS = { 6 width: 1024, 7 height: 576, 8 amount: 20, 9 density: 1, 10 strokeWidth: 0.5, 11 baseWidth: 512, 12 randomFillOpacity: true, 13 light: { 14 back: '#FFF', 15 front: '#DDD', 16 }, 17 dark: { 18 back: '#000', 19 front: '#222', 20 }, 21 }; 22 23 const here = path.dirname(fileURLToPath(import.meta.url)); 24 const assets = path.resolve(here, '../web/src/assets'); 25 26 function randomAt(column, row) { 27 let value = Math.imul(column + 1000, 374761393) + Math.imul(row + 1000, 668265263); 28 value = Math.imul(value ^ (value >>> 13), 1274126177); 29 return ((value ^ (value >>> 16)) >>> 0) / 4294967295; 30 } 31 32 function hexPath(cx, cy, radius, halfWidth) { 33 const halfHeight = radius / 2; 34 const points = [ 35 [cx, cy - radius], 36 [cx + halfWidth, cy - halfHeight], 37 [cx + halfWidth, cy + halfHeight], 38 [cx, cy + radius], 39 [cx - halfWidth, cy + halfHeight], 40 [cx - halfWidth, cy - halfHeight], 41 ].map(([x, y]) => `${Number(x.toFixed(3))} ${Number(y.toFixed(3))}`); 42 return `M ${points[0]} L ${points[1]} L ${points[2]} L ${points[3]} L ${points[4]} L ${points[5]} Z`; 43 } 44 45 function buildSvg({ front, back }) { 46 const { width, height, amount, density, strokeWidth, baseWidth } = SETTINGS; 47 const spacing = width / amount; 48 const radius = (spacing / Math.sqrt(3)) * density; 49 const verticalSpacing = 1.5 * radius; 50 const stroke = strokeWidth * (width / baseWidth); 51 const rows = Math.ceil(height / verticalSpacing) + 1; 52 53 const paths = []; 54 for (let row = -1; row <= rows; row += 1) { 55 const parity = ((row % 2) + 2) % 2; 56 const cy = radius + verticalSpacing * row; 57 for (let column = 0; column <= amount; column += 1) { 58 const cx = parity * (spacing / 2) + spacing * column; 59 const random = randomAt(column, row); 60 const opacity = !SETTINGS.randomFillOpacity 61 ? 1 62 : random >= 0.45 63 ? Number((random ** 2).toFixed(2)) 64 : 0; 65 const fill = opacity > 0 ? ` fill="${front}" fill-opacity="${opacity}"` : ' fill="none"'; 66 paths.push( 67 `<path stroke="${front}" stroke-width="${Number(stroke.toFixed(4))}"${fill} d="${hexPath( 68 cx, 69 cy, 70 radius, 71 spacing / 2 72 )}"/>` 73 ); 74 } 75 } 76 77 return [ 78 `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}">`, 79 `<rect width="100%" height="100%" fill="${back}"/>`, 80 ...paths, 81 '</svg>', 82 '', 83 ].join('\n'); 84 } 85 86 fs.writeFileSync(path.join(assets, 'hex-grid-light.svg'), buildSvg(SETTINGS.light)); 87 fs.writeFileSync(path.join(assets, 'hex-grid-dark.svg'), buildSvg(SETTINGS.dark)); 88 89 console.log('wrote hex-grid-light.svg and hex-grid-dark.svg');