use request animation frame instead of setInterval