From 2111c52a64cb3e696c0db97f84109435394e4bb9 Mon Sep 17 00:00:00 2001 From: Christian Lawson-Perfect Date: Sun, 9 Feb 2025 20:07:04 +0000 Subject: [PATCH] first commit --- .gitignore | 1 + index.html | 15 ++++ script.js | 256 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 272 insertions(+) create mode 100644 .gitignore create mode 100644 index.html create mode 100644 script.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8bc0f76 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.make.* \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..aa54e42 --- /dev/null +++ b/index.html @@ -0,0 +1,15 @@ + + + + + + Hex grid wallpaper? + + + +
+ + + + \ No newline at end of file diff --git a/script.js b/script.js new file mode 100644 index 0000000..356245f --- /dev/null +++ b/script.js @@ -0,0 +1,256 @@ +function element(name, attr, content, children) { + const e = document.createElementNS('http://www.w3.org/2000/svg', name); + if(attr) { + Object.entries(attr).forEach(([k,v]) => e.setAttribute(k,v)); + } + if(content !== undefined) { + e.innerHTML = content; + } + if(children) { + children.forEach(c => e.append(c)); + } + return e; +} + +function interpolator(fn) { + return function(strs, ...subs) { + let o = ''; + strs.forEach((s,i) => { + o += s; + if(i x.toFixed(4)) + +const coords = interpolator(([x,y]) => dp`${x} ${y}`); + +function midpoint([x1,y1],[x2,y2]) { + return [(x1+x2)/2, (y1+y2)/2]; +} + +const {cos, sin, PI, sqrt} = Math; +const hex_points = [0,1,2,3,4,5].map(i => [cos(i*PI/3)/sqrt(3), sin(i*PI/3)/sqrt(3)]); +const midpoints = [0,1,2,3,4,5].map(i => midpoint(hex_points[i], hex_points[(i+1)%6])); + +const svg = document.getElementById('board'); +svg.append() + +const dr = [cos(PI/6),sin(PI/6)]; +const [drx,dry] = dr; +const dc = [cos(PI/6),-sin(PI/6)]; +const [dcx,dcy] = dc; + +function hex_project(r,c) { + return [r*drx + c*dcx, r*dry + c*dcy]; +} + +function lerp(a,b,t) { + return (1-t)*a + t*b; +} + +function clamp(a,b,t) { + return Math.max(a,Math.min(b,t)); +} + +function rlerp(a,b) { + return lerp(a,b,Math.random()); +} + +function rint(n) { + return Math.floor(Math.random()*n); +} + +function draw_hex([x,y], sqd, hue) { + const hex_d = coords`M ${hex_points[0]} `+(hex_points.slice(1).map(p=>coords`L ${p}`)).join(' '); + const s = clamp(0,1, 2*sqd**0.3)*rlerp(0.8,1); + return element('path',{d:hex_d,fill: dp`hsl(${hue},50%,${rlerp(90,95)}%)`, transform: dp`translate(${x} ${y}) scale(${s})`}) +} + +function fill_hex_with_tris([x,y], sqd, hue) { + const g = element('g'); + + const density = clamp(0,1, 1.5*sqd**0.3); + + for(let i=0;i<6;i++) { + if(Math.random() < density) { + g.append(draw_tri([x,y],i, hue)); + } + } + return g; +} + +function draw_tri([x,y], o, hue) { + o = o || 0; + const tri_d = coords`M ${hex_points[o%6]} L ${hex_points[(o+1)%6]} L ${[0,0]}`; + return element('path',{d:tri_d,fill: dp`hsl(${hue},50%,${rlerp(90,95)}%)`, transform: dp`translate(${x} ${y})`}) +} + +function draw_circle([x,y], sqd, hue) { + const l = clamp(90,95,1000*sqrt(sqd)); + const radius = clamp(0, 1, 3*sqd**0.3) * rlerp(0.8,1) * 0.5; + return element('circle', {cx: x, cy: y, r: radius, fill: `hsl(${hue},50%,${rlerp(0.95,1)*l}%)`}) +} + +function draw_branches([x,y], sqd, hue) { + const w = clamp(0, 0.3, 0.3 * sqrt(sqd)); + let o = Math.random() < 0.5 ? 0 : 1; + const branch_d = coords`M 0 0 L ${midpoints[o]} M 0 0 L ${midpoints[o+2]} M 0 0 L ${midpoints[o+4]}`; + return element('path',{d: branch_d, 'stroke-width': w, stroke: dp`hsl(${hue},50%,${rlerp(85,95)}%)`, transform: dp`translate(${x} ${y})`}) +} + +function draw_hex_outline([x,y], sqd, hue) { + let o = rint(6); + let n = Math.floor(clamp(1,6,80*sqd**1)); + const w = 1 - clamp(0,0.7,lerp(0.2,0.7,1*sqd**0.5)); + let outer = coords`M ${hex_points[o]}`; + let inner = ''; + for(let i=0;i<=n;i++) { + const [px,py] = hex_points[(o+i)%6]; + outer += coords`L ${[px,py]}`; + inner = coords` L ${[w*px,w*py]}` + inner; + } + const hex_d = outer + inner; + return element('path',{d:hex_d, fill: dp`hsl(${hue},50%,${rlerp(90,95)}%)`, transform: dp`translate(${x} ${y})`}) +} + +function draw_arcs([x,y], sqd, hue) { + const g = element('g'); + const density = clamp(0, 1, 1.5*sqd**0.3); + + for(let i=0;i<6;i++) { + if(Math.random() < density) { + const r = 1/sqrt(3)/2/density; + const arc = element('path', {fill: dp`hsl(${hue},50%,${rlerp(90,95)}%)`, d: dp`M ${hex_points[i][0]} ${hex_points[i][1]} L ${midpoints[i][0]} ${midpoints[i][1]} A ${r} ${r} 0 0 1 ${midpoints[(i+5)%6][0]} ${midpoints[(i+5)%6][1]}`, transform: dp`translate(${x} ${y})`}) + g.append(arc); + } + } + g.append(element('circle', {cx: x, cy: y, fill: dp`hsl(${hue},50%,${rlerp(90,95)}%)`, r: 1/sqrt(3)/2*density})); + return g; +} + +function choice(l) { + const i = Math.floor(Math.random() * l.length); + return l[i]; +} + +const fns = [ + draw_branches, + draw_hex, + draw_hex_outline, + fill_hex_with_tris, + //draw_circle, + draw_arcs, +]; + +const spots = []; + +function hue_for(x,y) { + const rhue = 40; + const hue = ((x+y)/80 + 0.5) * 360 + rlerp(-rhue, rhue); + return hue; +} + +for(let i=0;i<20;i++) { + const fn = choice(fns); + const an = rlerp(0,2*PI); + const r = sqrt(rlerp(0,1))*30; + const pos = [r*cos(an), r*sin(an)]; + const [x,y] = pos; + const size = rlerp(1, 5); + const hue = hue_for(x,y); + spots.push({fn,pos, hue, size}); + const c = element('circle',{cx: pos[0], cy: pos[1], r: 1, fill: dp`hsl(${hue},100%,50%)`}); + //svg.append(c); +} + +function sqdist([x1,y1], [x2,y2]) { + return (x1-x2)**2 + (y1-y2)**2; +} + +function weighted_choice(weights,things) { + let t = 0; + weights.forEach(x => t += x); + const x = Math.random() * t; + let z = 0; + for(let i=0;i= x) { + return things[i]; + } + } +} + +function layer_hexes() { + for(let r=-40;r<40;r++) { + for(let c=-40;c<40;c++) { + const p = hex_project(r,c); + const weights = spots.map(({pos}) => { + return 1/sqdist(p, pos); + }) + const {fn, pos, hue, size} = weighted_choice(weights, spots) + const el = fn(p, size/(1+sqdist(p,pos)), hue); + svg.append(el); + } + } +} + +function layer_lines() { + const occupied = {}; + function hash(x,y) { + return `${x},${y}`; + } + function is_occupied(x,y) { + return hash(x,y) in occupied; + } + for(let r=-30;r<30;r++) { + for(let c=-30;c<30;c+=1) { + if(is_occupied(r,c)) { + continue; + } + let [x,y] = [r,c]; + const hue = hue_for(...hex_project(r,c)); + let trace = ''; + let steps = 10; + for(let i=0;i<1000;i++) { + const directions = [ + [1,0], + [0,1], + [-1,0], + [0,-1], + [1,-1], + [-1,1] + ]; + const available = directions.filter(([dx,dy]) => !is_occupied(x+dx,y+dy)); + console.log(available); + if(!available.length) { + break; + } + const [dx,dy] = choice(available); + console.log(dx,dy); + for(let n=0;n