<p><small>CSS sin() and cos() does <strong>NOT</strong> work in your browser.</small></p>
<form id="controls" class="app horizontal horizontal-labels">
<fieldset>
<label>Number of rings
<input type="range" min="2" max="12" value="10" id="rings" />
</label>
<label>Dots per ring
<input type="range" min="5" max="12" value="7" id="dots" />
</label>
<label>Spread
<input type="range" min="10" max="40" value="40" id="spread" />
</label>
</fieldset>
</form>
<ul class="dots" id="app"></ul>
.dots {
--_w: 800px;
--_sz: 30px;
aspect-ratio: 1;
border-radius: 50%;
list-style-type: none;
inline-size: var(--_w);
padding: unset;
position: relative;
}
.dots li {
--_x: calc(400px - (var(--_r) * cos(var(--_d))));
--_y: calc(400px - (var(--_r) * sin(var(--_d))));
background-color: var(--_bgc);
border-radius: 50%;
height: var(--_sz);
left: var(--_x);
position: absolute;
top: var(--_y);
width: var(--_sz);
}
html {
display: grid;
height: 100%;
}
body {
background: hsl(248, 50%, 25%);
color: hsl(248, 50%, 95%);
font-family: ui-sans-serif, system-ui, sans-serif;
margin-inline: auto;
}
p { display: none; }
@supports not (left: calc(1px * cos(45deg))) {
p { display: block; }
}
const random = (max, min = 0, f = true) => f ? Math.floor(Math.random() * (max - min) + min) : Math.random() * max;
const coords = (number, arr = []) => {
const frags = 360 / number;
for (let i = 0; i <= number; i++) arr.push((frags / 180) * i * Math.PI);
return arr;
}
const update = () => {
let s = '';
for (let i = 1; i <= rings.valueAsNumber; i++ ) {
const r = spread.valueAsNumber * i;
const theta = coords(dots.valueAsNumber * i);
for (let j = 0; j < theta.length; j++) {
s+= `<li style="--_d:${theta[j]};--_r:${r}px;--_bgc:hsl(${random(50,25)},${random(90, 50)}%,${random(90, 60)}%)"></li>`
}
}
app.innerHTML = s;
}
controls.addEventListener('input', () => update());
controls.dispatchEvent(new Event('input'))
This Pen doesn't use any external JavaScript resources.