Repository navigation
Features
Automatic message delivery
Rive workers now deliver their messages on the main thread automatically, so apps don't need to poll them. Replies, errors, and property updates arrive without waiting for a poll, and the main thread doesn't run a poll every frame anymore. The polling APIs are deprecated, as described under Behavior changes. (Change)
Image loading in scripts
Scripts can now turn encoded image bytes into an Image with context:loadImage(buffer), then draw it or assign it to a view model image property. The bytes decode the same way as the file's own images. On Android, scripts should use loadImage to decode images, because context:decodeImage isn't available there. (Change)
Artboard properties in scripts
Scripts can now read and set view model artboard properties with vm:getArtboard(name), which wasn't available on Android before. context:bindableArtboard(name) returns one of the file's own artboards to assign to such a property, or the default artboard when called without a name. (Change)
Integration APIs
This release adds the opt-in @RiveImplementationApi annotation for runtimes and frameworks that integrate Rive into their own view systems, such as React Native. Four existing APIs are now public behind it: RiveWorker.stateMachineSettled, RiveWorker.unsettleStateMachine, RiveSurface.resize, and RiveFramePacer. They aren't part of the supported app API and can change or be removed in any minor release. Apps should keep using Rive, RiveCanvasSession, and the other public entry points. Contributed by @mfazekas in #483. (Change)
Fixes
- Crashes when an image decode runs out of memory: An
OutOfMemoryErrorwhile decoding an image crashed the app, for example on theRive CmdServerthread. The decode now fails instead, and the image doesn't load.RiveWorker.decodeImagethrowsRiveImageException, and the worker keeps running. Reported in #481 and contributed by @mfazekas in #482. (Fix) - Legacy Canvas renderer crashes on undecodable images: With the Legacy Android Canvas renderer, an image that Android couldn't decode, for example because its bytes were malformed or memory ran out, crashed the app when drawn. The image now fails to load and draws nothing, as it does with the Rive renderer. (Fix)
- List rows that contain themselves: A list whose rows ended up hosting rows of themselves crashed with a stack overflow. This happened, for example, when a list inside a row was bound to a path that the row's view model doesn't have, so the binding resolved to the list that made the row. Rive now stops building such rows and leaves them empty. (Fix)
- Multi-finger scrolling: A scroll view dragged with two or more fingers could jump or fling. The newest finger now drives the scroll, and lifting it while other fingers stay down ends the drag without a fling. A second finger that moves during a scroll no longer clicks what it landed on. In the Legacy API, this applies when
multiTouchEnabledis on. (Fix) - Presses stuck in hidden content: Lifting a finger while a nested artboard or list was hidden, collapsed, paused, or scaled to zero didn't reach the state machines inside it. The press could stay held and block later fingers. The lift now reaches them. (Fix)
- List rows stuck in their hover state: A list row under the pointer never got a pointer exit when it scrolled out of a virtualized list or when its item was removed from a list. Whatever its enter listeners had set, such as a highlight or a view model value, stayed set. The row now gets its exit before it leaves, and the exit's events and view model changes are delivered. (Fix)
- Row opacity overwritten by lists: A list's opacity replaced the opacity of its rows instead of combining with it, so an opacity that a row authored, animated, or bound was lost. Opacity changes also reached the rows a frame late, and rows added while the list was transparent didn't start hidden. Rows now keep their own opacity, and the list applies its opacity when it draws them. (Fix)
- Text glyphs missing their image paint: Glyphs that a modifier faded, effect paths drawn below full opacity, and text with a shared global style drew their plain color instead of the image. The image was also fit to the glyphs, while the Editor fits it to the text's layout box. The image now covers every glyph and fits the layout box. (Fix)
- Outdated list item indexes: A list item's List Index value, which scripts read with
getIndex(), came from where a list component last placed the item, so it could lag behind the list. Right after an item was added, removed, or moved, the index could be outdated, and items of a list that no list component shows never got one. The index now updates as soon as the list changes. (Fix) - Stale layer masks on nested artboards: With GPU Canvas enabled, a layer mask over a nested artboard, or one using a nested artboard as its source, kept showing the content as it was first drawn while the nested artboard animated or was replaced. It now updates. (Fix)
- GPU Canvas content a frame behind: With GPU Canvas enabled, a canvas that drew a script's GPU canvas showed that GPU canvas's previous frame. It now shows the current frame. (Fix)
- Darkened script drawings with the Legacy Canvas renderer: With the Legacy Android Canvas renderer, a script's drawing under reduced opacity darkened as well as faded. For example, opaque red at 50% drew as dark red at half alpha. It now only fades, as images already did. (Fix)
Behavior changes
Polling APIs
With automatic delivery, the polling APIs are deprecated.
RiveWorker.beginPollingreturns immediately. It used to suspend until the lifecycle was destroyed, so code after the call or in a surroundingfinallyblock now runs right away. Release the worker when its lifecycle or owning component ends instead.- The
autoPollparameter ofrememberRiveWorker,rememberRiveWorkerOrNull, andrememberDeferredRiveWorkeris ignored. Messages are delivered even when it isfalse. RiveWorker.pollMessagesstill delivers the queued messages at once, but apps no longer need to call it.
Messages also arrive while the lifecycle is below RESUMED, where polling used to stop.
Fills and strokes painted with an image
A fill or stroke painted with an image now draws nothing while the image is missing. It used to draw its plain color. This applies when no image is chosen, before the image loads or decodes, after it is cleared, and when an artboard paint can't render. On Android, artboard paints currently render only when GPU Canvas is enabled, so without GPU Canvas, fills and strokes that use one now draw nothing. (Change)
Performance
Faster first frame for RiveCanvasSession
RiveCanvasSession now draws its first frame as soon as it starts or resumes, without waiting for a frame callback, like the Rive composable. Previously, a busy main thread could delay that frame by more than one display refresh. Contributed by @charliesbot in #486. (Change)
Lists
Lists with many data-bound rows, such as charts, do less work each frame. Rows whose binds ease through an interpolator converter now go idle once their values land, instead of advancing every frame. A list applies its opacity when it draws its rows, rather than setting every row's opacity on each step of a fade. With the Rive renderer, virtualized lists also skip drawing buffered rows that the scroll viewport clips away. (Change, Change, Change)
In a C++ benchmark on an M2 Max Mac, the median idle advance of a line chart with 7,595 eased rows went from 4.96 ms to 0.22 ms. This illustrates one improvement, and gains depend on the content.
Data binding and state machines
A state machine now binds each view model property its conditions read once, not once per condition. A list row that wakes with nothing to change also goes idle again in the same frame. Adding and removing binds no longer scans a view model property's list of dependents, which speeds up opening and closing content where many binds read one property. After warm-up, state changes don't allocate. (Change, Change, Change)
In a C++ benchmark, content with about 182,000 binds to each of two view model properties showed its first frame after 1.42 s instead of 7.9 s. Gains depend on the content.