<div class="container">
  <img src="http://s3-ap-northeast-1.amazonaws.com/nishinoshake/demo/animals/yorkshire.png" class="yorkshire" />
</div>
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
.container {
  width: 100%;
  min-height: 100vh;
  padding: 30px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}
.yorkshire {
  width: 200px;
  height: auto;
  display: block;
  will-change: transform;
}
View Compiled
type Easing = (t: number) => number

type TweenOptions = {
  from: number
  to: number
  duration: number
  easing: Easing
  onUpdate(currentValue: number): void
}

function clamp(num: number, min: number, max: number) {
  return Math.min(Math.max(num, min), max)
}

function tween({ from, to, duration, easing, onUpdate }: TweenOptions): Promise<void> {
  return new Promise((resolve) => {
    const startTime = performance.now()
    
    const tick = () => {
      const elapsedTime = performance.now() - startTime
      const progress = clamp(elapsedTime / duration, 0, 1)
      const currentValue = from + (to - from) * easing(progress)
      
      onUpdate(currentValue)
      
      if (progress === 1) {
        resolve()
      } else {
        requestAnimationFrame(tick)
      }
    }
    
    onUpdate(from)
    requestAnimationFrame(tick)
  })
}

const easeOutQuart = (t: number) => 1 - Math.pow(1 - t, 4)

function rotation(el: HTMLElement) {
  async function loop() {
    await tween({
      from: 0,
      to: 180,
      duration: 960,
      easing: easeOutQuart,
      onUpdate: val => {
        el.style.transform = `rotateY(${val}deg)`
      }
    })

    await tween({
      from: 180,
      to: 360,
      duration: 960,
      easing: easeOutQuart,
      onUpdate: val => {
        el.style.transform = `rotateY(${val}deg)`
      }
    })

    loop()
  }

  loop()
}

const yorkshire = document.querySelector<HTMLElement>('.yorkshire')

if (yorkshire) {
  rotation(yorkshire)
}
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.