Pattern Grid Generator
by vovkasolovev
HTML
<div class="container" id="pattern"></div>
<button class="button" aria-label="Regenerate" type="button"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
</svg> <span>Regenerate</span></button>
CSS
:root {
--bg-inner: white;
--bg-outer: white;
}
* {
box-sizing: border-box;
}
body {margin:0;
position: relative;
}
.container {
height: 100vh;
width: 100vw;
background-image: radial-gradient(var(--bg-inner) 0%, var(--bg-outer) 100%);
}
.container svg {
width: 100%;
aspect-ratio: 1;
}
.container svg * {
/* Removes little gaps between the shapes */
shape-rendering: geometricprecision;
}
.button {
position: absolute;
bottom: 0;
right: 0;
padding: 0.5rem;
margin: 0;
border-top-left-radius: 12px;
background: #ffffffcc;
border: 0.5px solid #555555cc;
line-height: 1;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
gap: 0.25rem;
font-weight: 600;
color: #333;
font-size: 0.75rem;
}
.button svg {
width: 1.25rem;
}
.button:hover svg {
transform: rotate(-45deg);
}
.button:focus, .button:active {
outline: 2px solid #f06;
}
.button:focus svg, .button:active svg {
transform: rotate(-90deg);
}
JavaScript
/* https://frontend.horse/articles/generative-grids/ */
import { SVG } from "https://cdn.skypack.dev/@svgdotjs/[email protected]";
import { random } from "https://cdn.skypack.dev/@georgedoescode/[email protected]";
import tinycolor from "https://cdn.skypack.dev/[email protected]";
console.clear();
let draw, squareSize, numRows, numCols, colors, colorPalette;
const selectedCharacters = [
"A",
"B",
"C",
"D",
"E",
"F",
"G",
"H",
"I",
"J",
"K",
"L",
"M",
"N",
// O removed for looking like a circle
"P",
// Q removed for an annoying descender
"R",
"S",
"T",
"U",
"V",
"W",
"X",
"Y",
"Z",
"&"
];
/*
Block Design Functions
*/
function drawCircle(x, y, foreground, background) {
// Create group element
const group = draw.group().addClass("draw-circle");
// Draw Background
group.rect(squareSize+2, squareSize+5).fill(background).move(x-1, y-1);
// Draw Foreground
group.circle(squareSize).fill(foreground).move(x, y);
// 30% of the time add inner circle
if (Math.random() < 0.3) {
group
.circle(squareSize / 2)
.fill(background)
.move(x + squareSize / 4, y + squareSize / 4);
}
}
function drawDots(x, y, foreground, background) {
const group = draw.group().addClass("dots");
const sizeOptions = [2, 3, 4];
const size = random(sizeOptions);
const offset = 10;
const circleSize = (squareSize/size) -(offset);
const space = (squareSize - (offset) - (circleSize * (size-1)));
// Draw Background
group.rect(squareSize+2, squareSize+2).fill(background).move(x-1, y-1);
// Draw Dots
for (let i = 0; i < size; i++) {
for (let j = 0; j < size; j++) {
group
.circle(circleSize)
.fill(foreground)
.move(x + offset + i * space, y + offset + j * space);
}
}
}
function drawCross(x, y, foreground, background) {
const group = draw.group().addClass("draw-cross");
const crossGroup = draw.group();
// Draw Background
...