Particles & spiral patterns in CSS: part II
Tags: css, spiral, cssart, generativeart
Published: 2023-07-24 05:17:03

---
title: Particles & spiral patterns in CSS: part II
series: Particles & spiral patterns
published: true
date: 2023-07-24 04:58:17 UTC
tags: CSS,spiral,cssart,generativeart
canonical_url:
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pvc43sax8o1c9smv3qkc.png
---

The week of Codepen's particle challenge is up - but I'm far from done obsessing over particles and serpentines. In Friday's [Part I](https://dev.to/mackfitz/particles-spiral-patterns-in-css-part-i-2p9n) I merely scratched the surface, showing you my first demo for this week's challenge:

{% codepen https://codepen.io/MackFitz/pen/RwqyKVa %}

and based on that, showed you how to draw the most basic 2D serpentine pattern:

{% codepen https://codepen.io/MackFitz/pen/XWyYvwm %}

To reiterate: the dots are deposited in equal intervals by a line spinning around its center point and also moving in a straight line - like so:

![A demonstration of how a spiral is drawn by an arom spinning around its center and moving from left to right, depositiing dots as it goes](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cnclsf3oamobrkexwu0y.gif)

For my second demo I decided to push it a little further in terms of complexity:

{% codepen https://codepen.io/MackFitz/pen/VwVxOgR %}

and then tweaked it a bit:

{% codepen https://codepen.io/MackFitz/pen/qBQKqPo %}

It was a headache to coordinate - and now might be a headache to wrap your head around ;)

Let me break down what's happening here - which is only a slight modification of my original linear serpentine. This time, however, instead of traveling along a straight line from one end to another, the pivot point is stationary. It is at the center of the viewport. Also, the line that spins around like the hand of a clock isn't the one drawing. It is merely a join for another line, and it is that one that deposits the dots as it spins while being spun itself:

![A demonstration of how an arm draws a circular, spirograph-like spiral by rotating around the center and flailing another, shorter joint even faster](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0uxalrb2oxluc1252g7a.gif)

As complex as that sounds, the HTML setup for it is almost as simple as for the linear serpentine:

```
<div class="spiroGraph"> <!-- the container for our serpentine -->
  <div class="arm"> <!-- the spinning joint anchored at the center of the viewport -->
    <div class="foreArm"></div> <!-- the joing that spins while also being spun -->
  </div>
</div>

```

We'll need to spawn a large number of the .arms - and like last time, the easiest way to do that is using Emmet - which is built into VS Code and Codepen. Instead of typying up the entire HTML markup above manually, just type:

.spiroGraph>.arm\*180>.foreArm

and press Enter (VS Code) or Tab (Codepen) - and witness 180 .arms, each with a .foreArm, spawned instantly.

That does it for HTML - so let's go over to our style sheets. As before, let's use SCSS - which will allow us to write most of our code just as we would in plain CSS, but will let us use for-loops for quickly styling each of our 180 .arms and .foreArms, and also declare variables.

First, let's set up the scene:

```
$particles: 360; /* an SCSS variable defining the number of particles across the whole serpentine; not the same as a CSS variable */

body {
  margin: 0;
  background-color: #000; /* hex code for the color black */
  height: 100vh; /* so that the body takes up the entire viewport's height */
  display: grid; /* we'll want to center the content */
  align-content: center;
  overflow: hidden;
  font-size: .8vmin; /* setting font size to be .8 of 1% of the shorter viewport dimention (height on desktop, width on mobile */
}

.spiroGraph {
  position: relative; /* thus the container will be the point of reference for its child, the .foreArm */
  display: flex;
  height: 100em; /* using font size as a unit for object size - making it 80% of the shorter vieport dimension */
  justify-content: center; /* we'll want the .arm to be placed at the center of the horizontal axis */
}

```

Now for all the moving bits:

```

.arm {
  --particles: #{$particles}; /* a proper CSS variable that takes its name and value after its SCSS counterpart */
  position: absolute; /* the container floats freely, independent of any other objects */
  bottom: 50em; /* the bottom end of the .arm is anchored at the center of the viewport */
  height: 30em; /* since there's got to be room for the .foreArm, we don't want it to be be 50em - but can't be less than 25em */
  transform-origin: bottom; /* its pivot point is located at its bottom end */
  rotate: calc(360deg/var(--particles)*var(--turnStep)); /* it does a full 360 over 360 particles - ergo each step is 1deg - but this formula will let you tweak that number */
}

.foreArm {
  --loops: 9; /* we'll want our serpentine to have 9 loops */
  position: absolute;
  bottom: 100%; /* its bottom will be where normally its top would be; thus it'll be anchored at the tip of the .arm */
  height: 20em; /* 50em (half of the viewport's height) minus the height of the .arm */
  /* also note we didn't declare the width for either - which is why we do this: */
  display: flex;
  justify-content: center; /* the .foreArm's child WILL have width, and we need to cente it */
  transform-origin: bottom; /* its pivot point is located at its bottom end */
  rotate: calc(360deg/var(--particles)*var(--loops)*var(--turnStep)); /* it has to make 9 loops of full 360 rotations, ergo it has to spin 9 times faster than the foreArm: 1deg x 9 = 9deg */
}

.foreArm::before {
  content: ''; /* no text */
  position: absolute;
  width: 2em;
  aspect-ratio: 1; /* the height matches the width */
  border-radius: 50%; /* our particle will be round */
  background-color: red /* for now */
}

```

Since we haven't set up the variable of --turnStep for each .arm:nth-child, no rotation was applied - so what you're probably seeing right now is a single red dot in the middle at the top of the container;

![A single red dot - indicating that the setup for the spiral works, but the variable for rotation step was not applied](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yu7tvw9aqjydx2gjy1f4.png)

Let's fix that - and quickly loop over the variable:

```
@for $i from 1 through 360 {
  .arm:nth-child(#{$i}) {
    --turnStep: #{$i};
  }
}

```

Now that's more like it. Are you seeing a spiral of 360 red dots?

![A spiral of red dots made with HTML and CSS](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ku0y11pd3klqr75d9l0m.png)

We can just as easily add some more color to it - by applying the same degree-based formula that we did to rotation.

```
.foreArm::before {
  content: ''; /* no text */
  position: absolute;
  width: 2em;
  aspect-ratio: 1; /* the height matches the width */
  border-radius: 50%; /* our particle will be round */
  background-color: hsl(calc(360deg/var(--particles)*var(--turnStep)) 100% 50%); /* the color will cycle through the full spectrum of colors of the rainbow */
}

```

That should make our serpentine look like this:

![A spiral of rainbow-colored dots, made with HTML and CSS](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ahbtcaw2k3lej94t9pyg.png)

And thus we get a proper spirograph-like serpentine. But again, this is really basic, and there's a whole lot more you can do with it. You can make more - or fewer - particles as you like (as long as you make sure your HTML and your SCSS have the same number of objects). Or experiment with dot sizes - or arm lengths and centers of rotation.

To make things easier, here's a live demo on Codepen that you can tinker with. For instance, see the madness that happens when you just reverse the direction of rotation on the .foreArm - like this:

```
rotate: calc(-360deg/var(--particles)*var(--loops)*var(--turnStep)); /* notice the minus before 360deg - that makes it assume the negative value, and this reverse the direction of rotation */

```

{% codepen https://codepen.io/MackFitz/pen/eYQjwEG %}

Have fun - and come back next time for another crazy loop done in (almost) pure HTML and CSS.