<!-- CLICK TO GENERATE -->
<canvas id="loadingScreen"></canvas>
:root {
--bgColor:#ffffff;
}
body {
margin: 0;
}
@media (prefers-color-scheme: dark) {
:root {
--bgColor:#282525;
}
}
import Knobs from "https://cdn.skypack.dev/@yaireo/knobs@1.3.5";
let cellSize = 40;
const colours = ['#ff318c', '#b345f1', '#765af8'];
const shapes = ['spot', 'crossSpots', 'quarterCircles'];
const circleQuarters = [
'topRight',
'bottomRight',
'bottomLeft',
'topLeft'
];
let spotRadius = cellSize / 8;
const canvas = document.getElementById('loadingScreen');
const ctx = canvas.getContext('2d');
let bgColour = getComputedStyle(document.documentElement).getPropertyValue('--bgColor');
let quarterCount = 5;
stretchCanvasToWindow();
draw();
const knobs = new Knobs({
knobs: [
{
label: 'Cell Size',
type: 'range',
value: 40,
min: 10,
max: 200,
onChange: (e, knobData, hsla) => {
cellSize = parseInt(knobData.value);
spotRadius = cellSize / 8;
draw();
},
},
{
label: 'Quarter Count',
type: 'number',
value: 5,
min: 1,
max: 50,
onChange: (e, knobData, hsla) => {
quarterCount = parseInt(knobData.value);
draw();
},
},
{
label: 'Background Colour',
cssVarsHSLA: false,
type: 'color',
value: bgColour,
defaultFormat: 'hex',
onChange: (e, knobData, hsla) => {
bgColour = removeHexAlpha(knobData.value);
draw();
},
},
{
label: 'Shape Colour 1',
type: 'color',
value: '#ff318c',
defaultFormat: 'hex',
onChange: (e, knobData, hsla) => {
colours[0] = removeHexAlpha(knobData.value);
draw();
},
},
{
label: 'Shape Colour 2',
type: 'color',
value: '#b345f1',
defaultFormat: 'hex',
onChange: (e, knobData, hsla) => {
colours[1] = removeHexAlpha(knobData.value);
draw();
},
},
{
label: 'Shape Colour 3',
type: 'color',
value: '#765af8',
defaultFormat: 'hex',
onChange: (e, knobData, hsla) => {
colours[2] = removeHexAlpha(knobData.value);
draw();
},
},
]
});
window.addEventListener('resize', (e) => {
stretchCanvasToWindow();
draw();
});
canvas.addEventListener('click', draw);
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => {
bgColour = getComputedStyle(document.documentElement).getPropertyValue('--bgColor');
draw();
});
function draw() {
for (let x = 0; x < canvas.width; x+= cellSize) {
for (let y = 0; y < canvas.height; y+= cellSize) {
const shapeChoice = randomShape();
switch(shapeChoice) {
case 'spot':
spot(x, y);
break;
case 'crossSpots':
crossSpots(x, y);
break;
case 'quarterCircles':
quarterCircles(x, y);
break;
}
}
}
}
function spot(x, y) {
const cellCentre = cellCentreCoordinates(x, y);
ctx.fillStyle = randomColour();
ctx.fillRect(x, y, cellSize, cellSize);
ctx.fillStyle = bgColour;
circle(cellCentre.x, cellCentre.y, spotRadius);
ctx.fill();
}
function crossSpots(x, y) {
const cellCentre = cellCentreCoordinates(x, y);
const spots = crossSpotCoordinates(cellCentre.x, cellCentre.y);
ctx.fillStyle = bgColour;
ctx.fillRect(x, y, cellSize, cellSize);
ctx.fillStyle = randomColour();
spots.forEach((spot) => {
circle(spot.x, spot.y, spotRadius);
ctx.fill();
});
}
function crossSpotCoordinates(cX, cY) {
const centreOffSet = cellSize / 4;
return [
// Top
xAndYCoordinates(cX, cY - centreOffSet),
// Right
xAndYCoordinates(cX + centreOffSet, cY),
// Bottom
xAndYCoordinates(cX, cY + centreOffSet),
// Left
xAndYCoordinates(cX - centreOffSet, cY),
]
}
function cellCentreCoordinates(cX, cY) {
return xAndYCoordinates(
cX + (cellSize / 2),
cY + (cellSize / 2)
);
}
function xAndYCoordinates(x, y) {
return {
x: x,
y: y
};
}
function quarterCircles(x, y) {
const cellCorner = randomCellCorner();
const quarterColour = randomColour();
const quarterCircleParams = decideQuarterCircleParamValues(cellCorner, x, y);
ctx.fillStyle = bgColour;
ctx.fillRect(x, y, cellSize, cellSize);
ctx.fillStyle = quarterColour;
let radiusIncrement = cellSize / quarterCount;
let runningRadius = cellSize;
for (let i = 0; i < quarterCount; i++) {
let fillStyle = quarterColour;
if (i % 2 === 1) {
fillStyle = bgColour;
}
drawQuarterCircle (
quarterCircleParams.centreX,
quarterCircleParams.centreY,
runningRadius,
quarterCircleParams.startAngle,
fillStyle
);
runningRadius -= radiusIncrement;
}
}
function circle(cX, cY, radius) {
ctx.beginPath();
ctx.moveTo(cX, cY);
ctx.arc(cX, cY, radius, 0, Math.PI * 2);
ctx.closePath();
}
function drawQuarterCircle (cX, cY, radius, startAngleDeg, fillStyle) {
const startAngle = startAngleDeg * (Math.PI / 180);
const endAngle = startAngle + Math.PI * 0.5;
ctx.fillStyle = fillStyle;
ctx.beginPath();
ctx.moveTo(cX, cY);
// Draw actual arc
ctx.arc(cX, cY, radius, startAngle, endAngle, false);
ctx.closePath()
ctx.fill();
}
function randomShape() {
return shapes[randomIndex(shapes.length)];
}
function randomColour() {
return colours[randomIndex(colours.length)];
}
function randomCellCorner() {
return circleQuarters[randomIndex(circleQuarters.length)];
}
function randomIndex(arrayLength) {
return Math.floor(Math.random() * arrayLength);
}
function decideQuarterCircleParamValues(cellCorner, x, y) {
let centreX, centreY, startAngle, endAngle;
switch (cellCorner) {
case 'topRight':
centreX = x + cellSize;
centreY = y;
startAngle = 90;
break;
case 'bottomRight':
centreX = x + cellSize;
centreY = y + cellSize;
startAngle = 180;
break;
case 'bottomLeft':
centreX = x;
centreY = y + cellSize;
startAngle = 270;
break;
case 'topLeft':
centreX = x;
centreY = y;
startAngle = 0;
break;
}
return {
centreX: centreX,
centreY: centreY,
startAngle: startAngle
};
}
function stretchCanvasToWindow() {
canvas.height = window.innerHeight;
canvas.width = window.innerWidth;
}
function removeHexAlpha(hex) {
return hex.slice(0, 7);
}
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.