Skip to main content
Each frame goes through three phases:
  1. Advance. sm->advanceAndApply(dt) updates state machines, animations, layout, and data bindings.
  2. Record. RiveRenderer records draw commands into the active RenderContext.
  3. Submit. renderContext->flush(...) builds the GPU work and lets the backend submit it.

FrameDescriptor

Configures the upcoming frame. Values are reset every beginFrame.

FlushResources

Carries everything the backend needs to submit the recorded work. On D3D12, Vulkan, and Metal you must update currentFrameNumber and safeFrameNumber every frame against your fence values. Otherwise the renderer can’t safely recycle staging buffers and you’ll either see overwrites mid-flight or unbounded memory growth.

Fixed-Timestep Accumulator

State machines and animations are deterministic at fixed dts. Wrap your real-elapsed-time delta in an accumulator so playback is reproducible across frame rates:
The cap (kMaxFrameDt) prevents catch-up storms after the app gets paused in a debugger or backgrounded by the OS.

Resize Handling

Three things have to happen on a resize:
  1. Resize your swap-chain / framebuffer.
  2. Re-create the RenderTarget.
  3. Either feed the new size into the artboard (for Fit::layout) or call resetSize(), then run advanceAndApply(0) so layout solves before the next draw.

Aligning Artboard to Viewport

Use computeAlignment (or Renderer::align) to map artboard-space into the viewport. Stash the matrix — you’ll need its inverse to convert pointer coordinates back into artboard-space.

When to Skip a Frame

advanceAndApply returns true if the state machine has more work; false if everything has settled. For animations that have looped to rest, you can skip both the advance step and the draw call, dropping CPU/GPU usage to zero between user inputs. Pointer events and external view-model writes can wake the state machine back up — re-draw at least once after each.

Tear-Down

Always destroy Rive objects before the RenderContext and the underlying GPU device. Rive objects hold reference-counted GPU resources; killing the device first leaves them with dangling handles and crashes on release.