update using animationFrame for performance