I am currently trying to improve animations performances on my project. I have so issues with one animation that I don’t understand. The slowdowns occurs on devices not that old (Honor 9, Pixel 5). I am usually arround 20 fps, I would love to be above 30, or event at 60 (I am on a pixel 6a).
For context :
- I use a requestAnimationFrame loop to play my animation.
- I only modify opacity and transform on my elements.
I get a lot of frame drop but the main thread does not seems to be used at this point.
I’m adding the performances report to my message.
As you can see, 1 have a lot of frame dropped from 2100ms to 2300ms, but not a lot is going on in the main thread, and I can’t figure why my frames are dropped. I know I have a long task (100ms) before and a long one (210ms) after, but can this be the cause of the drop ? I’ve try reducing it, but I feel like this does not impact my animation that much.
For my animations, I used the following code :
AnimatedValue.ts
export class AnimatedValue {
startTime = 0;
steps = 0;
constructor(private readonly progressCallback: (progress: number) => void, private readonly duration = 1000) {}
animate() {
requestAnimationFrame((chrono) => {
if (!this.startTime) {
this.startTime = chrono;
this.steps = 0;
}
const elapsedTime = chrono - this.startTime;
const progress = elapsedTime / this.duration;
if (progress < 1) {
this.progressCallback(progress);
this.animate();
this.steps++;
} else {
this.progressCallback(1);
}
});
}
}
Animate.ts
const animate = async (callback: (progress: number) => void, duration: number, onEnd = () => {}) => {
return new Promise<void>((resolve) => {
const animation = new AnimatedValue((progress) => {
callback(progress);
if (progress === 1) {
requestAnimationFrame(() => {
onEnd();
resolve();
});
}
}, duration);
animation.animate();
});
};
export const animateOpen = async (
feedPlayerElement: HTMLElement,
backgroundElement: HTMLElement | null,
fromInformation: { originX?: number; originY?: number },
) => {
const { originX = 50, originY = 50 } = fromInformation;
feedPlayerElement.style.transformOrigin = `${originX}% ${originY}%`;
await animate(
(progress) => {
feedPlayerElement.style.transform = `scale(${progress})`;
if (backgroundElement) backgroundElement.style.opacity = progress.toString();
},
CLOSE_ANIMATION_DURATION,
() => {
feedPlayerElement.style.transform = '';
feedPlayerElement.style.transformOrigin = '';
if (backgroundElement) backgroundElement.style.opacity = '';
},
);
};
I am usually arround 20 fps, I would love to be above 30, or event at 60 (I am on a pixel 6a).