- const RING_COUNT = 21;
.container
  .scene
    .scene__shadow
    .plane(style=`--ring-count: ${RING_COUNT}`)
      .plane__shadow
      - let rings = 0;
      while rings < RING_COUNT
        .ring(style=`--index: ${rings}; --name: slink-${rings}`)
        - rings++;
View Compiled
*
*:after
*:before
  box-sizing border-box
  transform-style preserve-3d
  
:root
  --border-width 1.2vmin
  --depth 20vmin
  --stack-height 6vmin
  --scene-size 20vmin
  --ring-size calc(var(--scene-size) * 0.6)
  --plane radial-gradient(hsla(0, 0%, 0%, 0.1) 50%, transparent 65%)
  --ring-shadow hsla(0, 0%, 0%, 0.5)
  --hue-one 320
  --hue-two 210
  --blur 10px
  --speed 1.2s
  --bg hsl(0, 0%, 98%)
  --ring-filter brightness(1) drop-shadow(0 0 0 var(--accent))
  
  @media(prefers-color-scheme dark)
    --bg hsl(0, 0%, 15%)
    --ring-shadow 'hsla(%s, 100%, 50%, 1)' % var(--hue-one)
    --plane 'radial-gradient(hsla(%s, 90%, 60%, 0.1) 50%, transparent 65%)' % var(--hue-one)
    --ring-filter brightness(1.75) drop-shadow(0 0 1vmin var(--accent))

body
  background var(--bg)
  min-height 100vh
  display grid
  place-items center
  overflow hidden
  
.scene
  height var(--scene-size)
  width var(--scene-size)
  animation step-up var(--speed) infinite ease
  
  &__shadow
    position absolute
    top 0
    left 100%
    height 100%
    width 100%
    animation fade-in var(--speed) infinite linear
    background var(--plane)
    transform scale(1.25)
    filter blur(var(--blur))

.flipper
  height var(--scene-size)
  width var(--scene-size)
  animation flip-flop calc(var(--speed) * 2) infinite steps(1)
  
@keyframes flip-flop
  0%
    transform rotate(0deg)
  50%
    transform rotate(180deg)
  100%
    transform rotate(360deg)

.plane
  height 100%
  width 100%
  transform translateZ(var(--depth))
  position relative
  
  &__shadow
    content ''
    height 100%
    width 100%
    position absolute
    top 50%
    left 50%
    background var(--plane)
    filter blur(var(--blur))
    transform translate(-50%, -50%) scale(1.25)
    animation fade-out var(--speed) infinite linear  

.scene__shadow
.plane__shadow    
  &:after
    content ''
    height var(--ring-size)
    width var(--ring-size)
    position absolute
    top 50%
    left 50%
    border var(--border-width) solid var(--ring-shadow)
    border-radius 50%
    transform translate(-50%, -50%) scale(0.8)
      
.container
  transform translateZ(100vmin) rotateX(-12deg) rotateY(0deg) rotateX(90deg) translateZ(calc(var(--depth) * -1.5)) rotate(0deg)
  animation rotate-scene calc(var(--speed) * 40) infinite linear
  
.ring
  --origin-z calc(var(--stack-height) - (var(--stack-height) / var(--ring-count)) * var(--index))
  --destination-z calc(((var(--depth) + var(--origin-z)) - (var(--stack-height) - var(--origin-z))) * -1)
  --hue var(--hue-one)
  --accent 'hsl(%s 100% 55%)' % var(--hue)
  --ring-filter brightness(1) drop-shadow(0 0 0 var(--accent))
  height var(--ring-size)
  width var(--ring-size)
  border-radius 50%
  border var(--border-width) solid var(--accent)
  position absolute
  top 50%
  left 50%
  transform-origin calc(100% + (var(--scene-size) * 0.2)) 50%
  animation-name var(--name)
  animation-duration var(--speed)
  animation-iteration-count infinite
  animation-timing-function cubic-bezier(.25,0,1,1)
  filter var(--ring-filter)
  
  &:nth-of-type(odd)
    --hue var(--hue-two)
    
  @media(prefers-color-scheme dark)
    --ring-filter brightness(2) drop-shadow(0 0 calc(var(--border-width) * 0.5) var(--accent))


// STYLUS GENERATED KEYFRAMES BE HERE...
$ring-count = 21
$animation-window = 50
$animation-step = $animation-window / $ring-count
// Need to generate the keyframes here.
// This would be a great use case for animation-repeat-delay instead of padding out
// keyframes. We would be able to reuse dynamic delays with the same keyframes.

// Need to generate keyframes based on ring-count and given a set window within the keyframes.
// For example; 50% of the window for 10 rings.

for $ring in (0..$ring-count)
  // Generate a set of keyframes based on the ring index
  // index is the ring
  $start = $animation-step * ($ring + 1)
  @keyframes slink-{$ring} {
    // In here is where we need to generate the keyframe steps based on ring count and window.
    0%, {$start * 1%} {
      transform translate3d(-50%, -50%, var(--origin-z)) translateZ(0) rotateY(0deg)
    }
    // Flip without falling
    {($start + ($animation-window * 0.75)) * 1%} {
      transform translate3d(-50%, -50%, var(--origin-z)) translateZ(0) rotateY(180deg)
    }
    // Fall until cut off point
    {($start + $animation-window) * 1%}, 100% {
      transform translate3d(-50%, -50%, var(--origin-z)) translateZ(var(--destination-z)) rotateY(180deg)
    }
  }
  
@keyframes fade-in {
  {$animation-window * 1%}, 0% {
    opacity 0
  }
  {$animation-window * 1.5%}, 100% {
    opacity 1
  }
}

@keyframes fade-out {
  0% {
    opacity 1
  }
  {$animation-window * 1.5%}, 100% {
    opacity 0
  }
} 
    
@keyframes step-up
  to
    transform translate3d(-100%, 0, var(--depth))
  
    
@keyframes rotate-scene
  to
    transform translateZ(100vmin) rotateX(-12deg) rotateY(0deg) rotateX(90deg) translateZ(calc(var(--depth) * -1.5)) rotate(360deg)
View Compiled
// 404
View Compiled
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.