APIs for integrating into existing event loop
Description
The Rive Advanced API requires that one uses rive's requestAnimationFrame. However, that is not practical for an HTML5 game engine:
- All games need the game loop, not all games require rive animations. Thus we need to either override
requestAnimationFrameto rive's globally, or to always include rive in builds even when it is not in use. - We may not be using
requestAnimationFrame: when the window is not focused,requestAnimationFramedoes not trigger, but some games require to continuously run, so we may for example switch tosetTimeoutduring that time to ensure the game logic keeps on running, and rive might break there. - Generally it requires integrating rive more deeply into the core of the engine than it needs to be (when it could just be an extension)
Proposed solution
I am assuming rive is only doing this as a hand-holding way to ensure some code is called before and after rendering. However, since that is supposed to be the "Low level" API, it is expected either way that the API might not be convenient or hand-holding but in exchange allows complete power and flexibility.
Therefore, I think it would be great to be able to do something like rive.startFrame()/rive.endFrame() as an alternative (or full replacement) to rive's requestAnimationFrame
Hi! You're right in that we're creating a simple wrapper around the requestAnimationFrame function, mainly as a way to coordinate rendering calls that are deferred. This helps coordinate certain scenarios such as Rive assets with mesh's, where there's an offscreen context we draw to first before other main canvas2d draw calls. The rive-wrapped rAF function calls a (not-exposed) function called flushCanvasRenderers that helps coordinate that sequence.
If we exposed this flushCanvasRenderers function, you could certainly use your own game's rAF loop and then before calling the next frame, call this new exposed function to draw Rive content. And in the case of you switching to setTimeout, you should still be able to advance the artboard and stateMachine / animation by passing some elapsed time, however you want to track that, as you normally would within the rAF loop. Would this help with your integration?
Example of what this might look like:
function draw(time) {
if (!lastTime) {
lastTime = time;
}
const elapsedMs = time - lastTime;
const elapsedSeconds = elapsedMs / 1000;
lastTime = time;
renderer.clear();
if (artboard) {
if (stateMachine) {
stateMachine.advance(elapsedSeconds);
}
artboard.advance(elapsedSeconds);
renderer.save();
renderer.align(
rive.Fit.contain,
rive.Alignment.center,
{
minX: 0,
minY: 0,
maxX: canvas.width,
maxY: canvas.height,
},
artboard.bounds
);
artboard.draw(renderer);
renderer.restore();
}
// Draw Rive contents
rive.flushCanvasRenderers();
requestAnimationFrame(draw);
}
requestAnimationFrame(draw);
Yes, that sounds perfect. Thank you for your response!
Hi sorry for the delay here.. but we just introduced a similarly-named API into v2.10.0.
You can use your own rAF loop, just make sure to call rive.resolveAnimationFrame() at the end of the loop, like in the snippet a few messages up. We're updating docs right now to reflect the new API, but you should be able to try it out now