- const one = 'Have fun!'
- const two = 'Have fun!'
.scene
  .word
    - for (const [index, letter] of one.split('').entries())
      .letter__wrap(style=`--index: ${index};`)
        .letter(data-letter=letter)
          span.letter__panel(aria-hidden='true')= letter
          span.letter__panel(aria-hidden='true')= two[index]
          span.letter__panel(aria-hidden='true')= letter
          span.letter__panel(aria-hidden='true')= two[index]
          span.letter__panel
    .word__shadow
      - for (const [index, letter] of one.split('').entries())
        .letter__shadow(style=`--index: ${index};`)
View Compiled
*
  box-sizing border-box
  transition all .15s ease 0s

:root
  --movement 0.85
  --stop 0.5
  --duration calc((var(--movement) * (1 / var(--stop))))
  --stagger 0.1125
  --perspective 500
  --size 50
  --ease cubic-bezier(1, -0.52, .26, .89)
  --bg hsl(0, 0%, 90%)
  --color hsl(0, 0%, 95%)
  --hue 320
  --saturation 100
  --lightness 50

  @media(prefers-color-scheme dark)
    --bg hsl(0, 0%, 10%)

body
  align-items center
  background var(--bg)
  display flex
  justify-content center
  min-height 100vh
  overflow hidden

.scene
  perspective calc(var(--perspective) * 1px)

.word
  display flex
  transform translate(calc(var(--size) * 1.5px), 0) rotateX(-30deg) rotateY(45deg)
  transform-style preserve-3d

.letter__wrap
  animation jump calc(var(--duration) * 1s) calc((var(--stagger, 0) * var(--index, 0)) * 1s) var(--ease) infinite
  transform-origin bottom center
  transform-style preserve-3d

  .letter
    // FLIP ROTATE ALTERNATE
    // animation rotate calc(var(--duration) * 4s) calc((var(--stagger, 0) * var(--index, 0)) * 1s) ease infinite
    animation rotate calc(var(--duration) * 2s) calc((var(--stagger, 0) * var(--index, 0)) * 1s) ease infinite

.word > div:nth-of-type(5)
.word__shadow > div:nth-of-type(5)
  opacity 0

.letter
  color var(--color)
  font-family -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif
  font-size 2rem
  font-weight bold
  height calc(var(--size) * 1px)
  margin-right calc(var(--size) * 0.2px)
  position relative
  text-transform uppercase
  transform-style preserve-3d
  width calc(var(--size) * 1px)

  &__shadow
    animation scale calc(var(--duration) * 1s) calc((var(--stagger, 0) * var(--index, 0)) * 1s) var(--ease) infinite, shadow-party calc(var(--duration) * 0.5s) calc((var(--stagger, 0) * var(--index, 0)) * 1s - 7s) linear infinite
    background radial-gradient(hsl(0, 0%, 20%), transparent) 150% 150%
    height calc(var(--size) * 1px)
    margin-right calc(var(--size) * 0.2px)
    width calc(var(--size) * 1px)
    transform-origin center
    filter blur(8px)
    transform rotateX(90deg) translate3d(0, 0, calc(var(--size) * -0.5px))

  &__panel
    --bg 'hsl(%s, 100%, 15%)' % var(--hue, 65)
    animation party calc(var(--duration) * 0.5s) calc((var(--stagger, 0) * var(--index, 0)) * 1s - 7s) linear infinite
    align-items center
    background var(--bg)
    border '5px hsl(%s, %s, %s) solid' % (var(--hue) calc(var(--saturation) * 1%) calc(var(--lightness) * 1%))
    display flex
    height calc(var(--size) * 1px)
    justify-content center
    left 50%
    position absolute
    top 50%
    width calc(var(--size) * 1px)

    &:nth-of-type(1)
      transform translate3d(-50%, -50%, 0) translate3d(0, 0, calc(var(--size) * 0.5px))
    &:nth-of-type(2)
      transform translate3d(-50%, -50%, 0) rotateX(90deg) translate3d(0, 0, calc(var(--size) * 0.5px))
    &:nth-of-type(3)
      transform translate3d(-50%, -50%, 0) rotateX(180deg) translate3d(0, 0, calc(var(--size) * 0.5px))
    &:nth-of-type(4)
      transform translate3d(-50%, -50%, 0) rotateX(-90deg) translate3d(0, 0, calc(var(--size) * 0.5px))
    &:nth-of-type(5)
      transform translate3d(-50%, -50%, 0) rotateY(-90deg) translate3d(0, 0, calc(var(--size) * 0.5px))

.word__shadow
  display flex
  position absolute
  left 0
  bottom 0
  transform-style preserve-3d

// FLIP ROTATE ALTERNATE
// @keyframes rotate
//   0%, 30.625%
//     transform rotateX(0deg)
//   33.125%, 81.625%
//     transform rotateX(90deg)
//   83.125%, 100%
//     transform rotateX(180deg)

@keyframes rotate
  0%, 15%
    transform rotateX(0deg)
  20%, 65%
    transform rotateX(270deg)
  70%, 100%
    transform rotateX(540deg)

@keyframes jump
  0%, 50%, 100%
    transform scaleX(1) scaleY(1) translate(0, 0)
  15%
    transform scaleX(1.2) scaleY(0.8) translate(0, 0)
  25%
    transform scaleX(0.9) scaleY(1.1) translate(0, -100%)

@keyframes scale
  0%, 20%, 50%, 100%
    transform rotateX(90deg) translate3d(0, 0, calc(var(--size) * -0.5px)) scale(1)
  25%
    transform rotateX(90deg) translate3d(0, 0, calc(var(--size) * -0.5px)) scale(1.25)

// Stylus Gem !
@keyframes party
  for $frame in (0..100)
    {$frame * 1%}
      background 'hsl(%s, 65%, 40%)' % ($frame * 3.6)
      border-color 'hsl(%s, 100%, 50%)' % ($frame * 3.6)

@keyframes shadow-party
  for $frame in (0..100)
    {$frame * 1%}
      background radial-gradient(hsl(($frame * 3.6), 100%, 50%), transparent) 150% 150%
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.