input#spinStop(type='checkbox', name='spinStop')

- var ngon = 180
.chain
  - for (var i = 0; i < ngon; ++i) {
  .segment
  - }
  
label(for='spinStop')
  span S
  span.flip
    span.InTo TO
    span.letterP P
View Compiled


body {
  margin: 0;
  background: #000;
  height: 100vh;
  display: grid;
  overflow: hidden;
  perspective: 100vmin;
}

body, body * {
  transform-style: preserve-3d;
}

.chain {
  display: flex;
  flex-direction: row;
  align-self: center;
  position: absolute;
  inset: 25vh -10vw;
  justify-content: space-between;
  animation: spin 6s linear infinite;
  --spinAxis: x;
  pointer-events: none;
}

@keyframes spin {
  100% {
    rotate: var(--spinAxis) 360deg;
  }
}

.segment {
  width: 1px;
  height: 100%;
  position: relative;
  rotate: var(--spinAxis) calc(var(--turn)*12deg);
  display: flex;
  justify-content: center;
}

.segment::before {
  content: '';
  position: absolute;
  width: 5vmin;
  aspect-ratio: 1;
  background-image: radial-gradient(at 30% 30%, #fff, hsl(calc(60deg*(var(--hue) - 1)) 100% 85%) 10%, hsl(calc(60deg*var(--hue)) 100% 25%) 50%, hsl(calc(60deg*(var(--hue) + .5)) 100% 10%) 66%, hsl(calc(60deg*(var(--hue) + .5)) 100% 5%) 75%);
  border-radius: 50%;
  box-shadow: inset -1px -1px hsl(calc(60deg*(var(--hue) + 1)) 100% 50%);
  animation: counterSpin 6s linear infinite;
}

@keyframes counterSpin {
  0% {
    rotate: var(--spinAxis) calc(-1*var(--turn)*12deg);
  }
  100% {
    rotate: var(--spinAxis) calc(-1*var(--turn)*12deg - 360deg);
  }
}

.chain, .segment::before {
  animation-delay: -.8s;
}


/* LOOPS / ITERATIONS */


@for $i from 1 through 6 {
  .segment:nth-child(6n+#{$i}) {
    --hue: #{$i};
  }
}

@for $i from 1 through 30 {
  .segment:nth-child(30n+#{$i}) {
    --turn: #{$i};
  }
}

/* PLAY/PAUSE TOGGLE */

input {
  display: none;
}

label {
  font-family: courier new;
  font-size: 15vmin;
  font-weight: bolder;
  color: #fff;
  place-self: center;
  perspective: 50vmin;
}

label, span {
  display: flex;
  transition: all 1s ease-in-out;
}

.flip {
  rotate: y 180deg;
}

.letterP {
  rotate: y -180deg;
}

.InTo {
  position: relative;
  backface-visibility: hidden;
}

.InTo::before {
  content: 'IN';
  position: absolute;
  inset: 0;
  backface-visibility: hidden;
  display: flex;
  rotate: y 180deg;
}

#spinStop:not(:checked) ~ label {
  isolation: isolate;
}

#spinStop:checked ~ label :is(.flip,.letterP)
{
  rotate: y 0deg;
}

#spinStop:not(:checked) ~ .chain,
#spinStop:not(:checked) ~ .chain .segment::before {
  animation-play-state: paused;
}

@media (orientation: portrait) {
  .chain {
    inset: -10vh 25vw;
    flex-direction: column;
    --spinAxis: y;
  }

  .segment {
    width: 100%;
    height: 1px;
    justify-content: unset;
  }
}

View Compiled
/* A step-by-step guide of how to make a 2D version of this, with comments on each line of code, in a tutorial on my blog at:

https://dev.to/mackfitz/particles-spiral-patterns-in-css-part-i-2p9n

https://mackfitz.hashnode.dev/particles-spiral-patterns-in-css-part-i */

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.