1) You cannot rely on any fixed rounding technique : some screens are 60Hz, some 50Hz, or even 100Hz or 120Hz (like mine), ... not to mention mobiles that might be 30Hz, 20Hz,...
2) the error of the rAF might be in fact greater than 0/1, might be 2, and if the garbage collector occurs, you might even miss a frame or two, even on a Desktop : your code has to handle this nicely.
3) For this reason and to allow to pause the game, you have to use your own game time, and not real-world time to compute the right frame in your animation :
// each rAF you do something like :
var now = Date.now() | 0;
var delta = (now - this.previousCallTime);
if (delta < 14 ) { return }; // max rate is 66Hz.
if (delta > 60 ) { delta = 16; }; // if too many frames missed,
// consider only 1 frame elapsed
game.time = game.time + delta ;
this.previousCallTime = now;
3) And now compute the frame with :
var frameIndex = ( ( (game.time - this.animStartGameTime )
/ this.animFrameDuration ) | 0) % this.FrameCount ;
4) So let us see an example with 60Hz, and 3 step 20Hz anim (=50ms) :
frame time 16 17 17 16 17 17 17 16 17 16
animtation time 16 33 50 66 83 100 117 133 150
animation index 0 0 0 1 1 *2* 2 2 0
Ooops , the animation is choppy, we have 3 frame 0, but only 2 frame 1, then 3 frame 2 again... !!!
But you know what ? Sadly enough this is an issue that cannot be solved : you are trying to approximate a fixed integer by a sum of random integers : whatever you do there WILL be times when you do not have the regularity you seek.
the effect can be reduced if you take a higher number of frames, but only reduced.
The solution provided by Matt Kemp is not what you seek :
1. Yes, you will have regularity on the index (0,1,2,0,..,0,1,2,..) but
the time each frame last will be different, so for a hero walking
for instance, the player will feel like the walking speed is
changing over time, which is noticable also, so you trade one glitch
for another, which is far far worse with 2+ ms jitter + garbage
collection occuring : the real-world case.
2. It works only in 60Hz, which is a no-go.
So if you are very sensitive to animation quality, use 8, 12, 15 frames/seconds or more, this is the only real solution.
Rq : most LCD TV do this kind of computation to handle NTSC/PAL/... 's different framerate with the same screen frequency : it is not noticeable.
I put a small code i wrote before into a JSFiddle so you can experiment and see by your self : change the parameters or the index computation function, and you will see there is no way to get around this, you can just improve by raising the number of frames.
Here :
http://jsbin.com/ewowel/2/edit
Results :
"Anim same frame count (index trunced) : 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6"
"Anim same frame count mean : 6 error : 0"
"Anim same frame count (index trunced) : 6,6,7,6,6,6,6,6,6,6,6,6,5,6,6,6,6,6,6,7,6,6,6,5" "Anim same frame count mean : 6 error : 4"
"Anim same frame count (index trunced) : 7,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6"
"Anim same frame count mean : 6 error : 2"