use requestAnimationFrame or setInterval for animation loop