Why jitter through fps limiter

I need a fps limiter to reduce the speed to 30 fps. The jitter is especially noticeable on smartphones, except on my PC. But it has nothing to do with the 30fps, since my movements are slow and everything is smooth on the PC. The graphics performance of smartphones is also sufficient. What am I doing wrong here?

  1. With some jitter on 30 and 60fps on smartphones
animate(currentTime) {        
       const elapsed = currentTime - this.lastFrameTime;

        if (elapsed >= this.timeFpsMax) {
            this.lastFrameTime = currentTime - (elapsed % this.timeFpsMax);

            const deltaTime = this.timeFpsMax / 1000; 
                        
            this.mixer.update(deltaTime);
            
            this.stats.begin();
            this.composer.render();
            this.stats.end();
        }
}
  1. With some jitter on 30 and 60fps on smartphones
animate(currentTime) {
        const now = currentTime / 1000;
        let deltaTime = now - lastTime;
        lastTime = now;

        deltaTime = Math.min(deltaTime, 0.1); 

        accumulator += deltaTime;

        while (accumulator >= fixedTimeStep) {
            this.mixer.update(fixedTimeStep);
           
            accumulator -= fixedTimeStep;

            needsRender = true;
        }

        if (needsRender) {
            this.stats.begin();
            this.composer.render();
            this.stats.end();

            needsRender = false;
        }
}
  1. No Jitter (60fps)
animate(currentTime) {
        this.mixer.update(this.clock.getDelta());
        this.stats.begin();
        this.composer.render();
        this.stats.end();
}

Thanks…

#2 looks the most correct to me..
but you probably don’t need to loop like that, and instead just update the mixer with

this.mixer.update(((accumulator/fixedTimeStep)|0)*fixedTimeStep));

since you don’t appear to be doing anything else in that loop.

but beyond that, it’s an even more complicated topic. The RAF is scheduled in such a way that there isn’t necessarily a 1 to 1 time match between how the RAF gets called and what gets rendered, since its really timeslicing in a multitasked system.. RAF tries to present you with an idealized 60fps frame, but may move/shuffle things around in there according to its own needs.. which may result in staggering of your frame updates.

Add to that, that performance.now() is Also not super accurate due to rowhammer mitigation.

It’s not ideal, and you may have to live with some jitter.

If you are frame capping for rendering reasons this might be unavoidable..

If you are frame capping for simulation reasons, there is a different approach that can work which is to update your simulation at a fixed rate, but then interpolate between your .. say 30fps frames, to match the current time of render.