first commit
This commit is contained in:
commit
2111c52a64
3 changed files with 272 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
.make.*
|
15
index.html
Normal file
15
index.html
Normal file
|
@ -0,0 +1,15 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<title>Hex grid wallpaper?</title>
|
||||
<script type="module" src="script.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<svg id="board" viewBox="-20 -20 40 40">
|
||||
</svg.
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
256
script.js
Normal file
256
script.js
Normal file
|
@ -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<subs.length) {
|
||||
o += fn(subs[i]);
|
||||
}
|
||||
});
|
||||
return o;
|
||||
}
|
||||
}
|
||||
|
||||
const dp = interpolator(x => 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<weights.length;i++) {
|
||||
z += weights[i];
|
||||
if(z >= 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<steps && !is_occupied(x+dx,y+dy);n++) {
|
||||
x = x+dx;
|
||||
y = y+dy;
|
||||
occupied[hash(x,y)] = true;
|
||||
trace += (trace ? ' L' : 'M') + coords` ${hex_project(x,y)}`;
|
||||
|
||||
}
|
||||
}
|
||||
console.log(trace);
|
||||
svg.append(element('path',{d:trace,fill:'none',stroke: `hsl(${hue},50%, ${rlerp(95,99)}%)`, 'stroke-width': rlerp(0.1,0.2), 'stroke-linejoin': 'round'}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function layer_parquet() {
|
||||
const h = cos(PI/3);
|
||||
}
|
||||
|
||||
layer_lines();
|
||||
layer_hexes();
|
||||
const viewport = 15;
|
||||
svg.setAttribute('viewBox', `${-viewport} ${-viewport} ${2*viewport} ${2*viewport}`)
|
Loading…
Add table
Add a link
Reference in a new issue