input#playPause(type='checkbox', name='playPause')
- var algi = 180
.scene
- for (var c = 0; c < 2; c++) {
.circle
- for (var s = 0; s < algi; ++s) {
.segment
.facet
- }
- }
label(for='playPause')
- for (var i = 0; i < 7; ++i) {
span
- }
View Compiled
$algi: 180; // the number of particles
$floops: 9; // the number of star's arms
/* You can try to change the above - BUT:
1) $floops works with some integers better than others, e.g. 7, 8, 11, 13 won't work.
2) make sure the value of $algi matches the value of - var algi in Pug (currently at 180.
4) Going for more than that might be tough on your CPU */
body {
margin: 0;
background-color: #000;
height: 100vh;
overflow: hidden;
display: grid;
font-size: .8vmin;
}
body *,
body *::before {
position: absolute;
}
.scene {
width: 100em;
aspect-ratio: 1;
perspective: 50em;
place-self: center;
pointer-events: none;
}
body *,
body *::before {
transform-style: preserve-3d;
}
.circle {
inset: 0;
--animDur: 18s;
}
.circle:nth-child(1) {
--dir: 1;
}
.circle:nth-child(2) {
--dir: -1;
animation: roll calc(var(--animDur)*#{$floops/2}) linear infinite;
}
.circle, .segment, label {
display: grid;
justify-items: center;
}
.segment {
--segH: 35em;
height: var(--segH);
bottom: 50em;
rotate: calc(var(--dir)*#{360/$algi}deg*var(--segTurn));
}
.facet {
height: calc(50em - var(--segH));
bottom: var(--segH);
animation: spin var(--animDur) linear infinite;
}
.segment,.facet {
transform-origin: 50% 100%;
}
.facet::before {
content: '';
display: block;
width: 4.5em;
aspect-ratio: 1;
border-radius: 50%;
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%);
box-shadow: inset -1px -1px hsl(calc(60deg*(var(--hue) + 1)) 100% 50%);
animation: counterSpin var(--animDur) linear infinite, darkness calc(var(--animDur)/2) ease-in-out infinite alternate;
animation-delay: 0s, calc(-1*var(--animDur)/#{$algi/$floops}*var(--faceTurn) - var(--animDur)*(.5 - var(--dir)/6));
}
/* PLAY/PAUSE TOGGLE */
label {
--labelW: 30;
width: calc(var(--labelW)*1em);
--angle: 360deg/7;
--pushZ: calc(1/cos(var(--angle)*2 - 90deg)*var(--labelW)/2);
--spanW: calc(sin(var(--angle)/2)*var(--pushZ)*2);
aspect-ratio: 2;
place-self: center;
rotate: x 30deg;
transition: all .5s ease-in-out;
}
label:hover {
scale: 1.15;
}
span {
--angle: 360deg/7;
--pushZ: calc(1/cos(var(--angle)*2 - 90deg)*var(--labelW)/2);
--spanW: calc(sin(var(--angle)/2)*var(--pushZ)*2);
width: calc(var(--spanW)*1em);
height: calc(var(--labelW)*.5em);
display: grid;
place-items: center;
transform: rotateY(calc(-30deg*var(--spanStep))) translateZ(calc(var(--pushZ)*-1em));
}
span::before {
font-size: 15em;
line-height: 0;
color: hsl(calc(var(--spanStep)*var(--angle)) 100% 50%);
backface-visibility: hidden;
background-image: linear-gradient(90deg, red, yellow);
}
input {
display: none;
}
#playPause:not(:checked) ~ .scene :is(.circle, .facet),
#playPause:not(:checked) ~ .scene .facet::before {
animation-play-state: paused;
}
#playPause:not(:checked) ~ label {
rotate: y 150deg;
}
#playPause:checked ~ label {
rotate: y 30deg;
}
/* ANIMATION KEYFRAMES */
@keyframes roll {
0% {
rotate: calc(#{360/($floops*2)}deg);
}
100% {
rotate: calc(#{360/($floops*2)}deg - 1turn);
}
}
@keyframes spin {
0% {
rotate: x calc(var(--dir)*var(--faceTurn)*#{360/($algi/$floops)}deg);
}
100% {
rotate: x calc( var(--dir)*(var(--faceTurn)*#{360/($algi/$floops)}deg + 1turn) );
}
}
@keyframes counterSpin {
0% {
transform: rotateX(calc(var(--dir)*-1*var(--faceTurn)*#{360/($algi/$floops)}deg));
}
100% {
transform: rotateX(calc( var(--dir)*(-1*var(--faceTurn)*#{360/($algi/$floops)}deg - 1turn)) );
}
}
@keyframes darkness {
100% {
filter: brightness(.15) saturate(2);
}
}
/* LOOPS / ITERATING */
@for $i from 1 through $algi
{
.segment:nth-child(#{$i}) {
--segTurn: #{$i};
}
}
@for $i from 1 through $algi/$floops {
.segment:nth-child(#{$algi/$floops}n+#{$i}) .facet
{
--faceTurn: #{$i};
}
}
@for $i from 1 through 6 {
.segment:nth-child(6n+#{$i}) .facet
{
--hue: #{$i};
}
}
$letters: S T O P L A Y;
@each $letter in $letters {
$index: index($letters, $letter);
span:nth-child(#{$index}) {
--spanStep: #{$index - 1};
}
span:nth-child(#{$index})::before {
content: "#{$letter}";
}
}
View Compiled
/* For 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-ii-4bn8
https://mackfitz.hashnode.dev/particles-spiral-patterns-in-css-part-ii */
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.