Releases: Grandgular/rive
v2.0.0 — Renderer split (WebGL2 + Canvas)
Tag: v2.0.0
Packages: @grandgular/rive-angular-webgl2@2.0.0 · @grandgular/rive-angular-canvas@2.0.0
This release is a major product-line change: Rive for Angular is split into two renderer-specific npm packages, matching Rive’s Canvas vs WebGL2 model (similar to rive-react). The monolithic @grandgular/rive-angular meta package is no longer built from this repository — you choose one runtime at install time (@rive-app/webgl2 or @rive-app/canvas).
The Angular public API (<rive-canvas>, RiveCanvasComponent, RiveFileService, provideRiveRuntime, data binding, etc.) stays the same; what changes are package names, import paths, and peer dependencies.
What’s new
| Item | Role |
|---|---|
@grandgular/rive-angular-webgl2 |
Recommended for most apps — Rive Renderer via peer @rive-app/webgl2 |
@grandgular/rive-angular-canvas |
Smaller Canvas2D runtime via peer @rive-app/canvas |
Embedded rive-angular-core |
Shared code is copied into each published package; npm run sync:rive-angular-core syncs from libs/rive-angular-core |
libs/rive-angular-core |
Internal library for shared tests/utilities (not published on its own) |
Install (pick one)
WebGL2 / Rive Renderer (recommended):
npm install @grandgular/rive-angular-webgl2 @rive-app/webgl2Canvas2D:
npm install @grandgular/rive-angular-canvas @rive-app/canvasCode change
Replace the old import with the package you install:
// Before (meta package — no longer published from this repo)
import { RiveCanvasComponent, Fit, Alignment } from '@grandgular/rive-angular';
// After — WebGL2 (example)
import { RiveCanvasComponent, Fit, Alignment } from '@grandgular/rive-angular-webgl2';
// After — Canvas2D (example)
// import { RiveCanvasComponent, Fit, Alignment } from '@grandgular/rive-angular-canvas';Template usage is unchanged:
<rive-canvas
src="assets/animation.riv"
[fit]="Fit.Contain"
[alignment]="Alignment.Center"
/>Optional: provideRiveRuntime (unchanged API)
import { ApplicationConfig } from '@angular/core';
import { provideRiveRuntime } from '@grandgular/rive-angular-webgl2';
export const appConfig: ApplicationConfig = {
providers: [
provideRiveRuntime({
wasmUrl: 'assets/rive/rive.wasm',
lazy: true,
}),
],
};(Use the same import path as the package you chose — rive-angular-webgl2 or rive-angular-canvas.)
Migration from @grandgular/rive-angular
- Remove the old package:
npm uninstall @grandgular/rive-angular - Install one of the two packages and its Rive peer (
@rive-app/webgl2or@rive-app/canvas) as above - Update all imports from
'@grandgular/rive-angular'to the new package name - If the legacy package still exists on npm for your users, mark it deprecated with a message pointing to the new package names (see repository maintainer notes)
Why 2.0.0 on new package names?
Both new packages ship as 2.0.0 to mark the next major in the Grandgular Rive Angular line: removing the single meta package and requiring new install paths and peers is a breaking change for consumers, even where the component API is unchanged. See the root README (“Why 2.0.0”).
Details
- Full narrative: README.md
- Changelog: CHANGELOG.md (section 2.0.0)
- Per-package READMEs: rive-angular-webgl2 · rive-angular-canvas
GitHub release title (copy-paste)
v2.0.0 — Renderer split (WebGL2 + Canvas)
Use this file as the release description body, or paste the sections you need into the GitHub “Release notes” field when you publish tag v2.0.0.
v1.1.0 - Configurable runtime initialization
Adds provideRiveRuntime() to control when the Rive WASM runtime initializes (eager by default, optional lazy mode). Changes are additive relative to v1.0.0 - no breaking changes.
What's new
| API | Role |
|---|---|
provideRiveRuntime({ wasmUrl }) |
Eager runtime initialization on app startup |
provideRiveRuntime({ wasmUrl, lazy: true }) |
Lazy runtime initialization on first real usage |
RiveRuntimeConfig |
Public config type export for runtime setup |
| Internal shared runtime initializer | Idempotent + deduplicated runtime readiness across component/service |
RiveCanvasComponent and RiveFileService now coordinate runtime readiness in a single flow, including concurrent first-use scenarios.
import { ApplicationConfig } from '@angular/core';
import { provideRiveRuntime } from '@grandgular/rive-angular';
export const appConfig: ApplicationConfig = {
providers: [
provideRiveRuntime({
wasmUrl: 'assets/rive/rive.v1.wasm',
lazy: true,
}),
],
};Migration note
If you previously used:
provideAppInitializer(() => RuntimeLoader.setWasmUrl('assets/rive/rive.v1.wasm'));You can now use:
provideRiveRuntime({ wasmUrl: 'assets/rive/rive.v1.wasm' });Details
See CHANGELOG.md and the library README.md.
v1.0.0 - Lifecycle outputs
@grandgular/rive-angular v1.0.0
First stable release under. Adds animation lifecycle outputs (aligned with @rive-app/canvas callbacks) and re-exports LoopType and LoopEvent. Changes are additive relative to v0.4.0 — no breaking changes.
What’s new
| Output | Role |
|---|---|
animationPlay / animationPause / animationStop |
Play / pause / stop (RiveEvent, EventType) |
animationLoop |
Loop iteration finished; event.data is LoopEvent |
animationAdvance |
Per-frame advance (high frequency; emitted outside NgZone.run) |
isPlaying / isPaused signals behave as before; the new outputs expose the same lifecycle as events.
<rive-canvas
src="animation.riv"
(animationPlay)="onPlay($event)"
(animationLoop)="onLoop($event)"
/>Details
See CHANGELOG.md and the library README.
v0.4.0 — Data Binding & ViewModel Support
@grandgular/rive-angular v0.4.0
Major feature release adding full Rive Data Binding and ViewModel support with declarative and imperative APIs. Brings Angular library to feature parity with React's @rive-app/react-webgl2 hooks.
🎉 What's New
Declarative Data Binding
🔗 dataBindings Input — New reactive input for template-driven ViewModel property updates. Keys present in the input are controlled — the input is the source of truth.
<rive-canvas
src="assets/game.riv"
[dataBindings]="{
backgroundColor: '#FF5733',
score: playerScore(),
playerName: userName(),
isActive: true
}"
/>ViewModel Selection
🎯 viewModelName Input — Select which ViewModel to use (defaults to artboard's default ViewModel). Changing this input after load automatically reinitializes the ViewModel.
<rive-canvas
src="assets/multi-vm.riv"
viewModelName="GameViewModel"
/>Two-Way Reactivity
dataBindingChange Output — React to property changes from within the animation, including trigger events.
onDataChange(event: DataBindingChangeEvent) {
console.log(`${event.path} changed to ${event.value}`);
// event.propertyType: 'color' | 'number' | 'string' | 'boolean' | 'enum' | 'trigger'
}<rive-canvas
src="assets/interactive.riv"
(dataBindingChange)="onDataChange($event)"
/>Universal Data Binding Methods
🔧 Auto-Detecting API — Set and get any ViewModel property with automatic type detection.
riveRef = viewChild.required(RiveCanvasComponent);
// Auto-detects property types
this.riveRef().setDataBinding('score', 100); // number
this.riveRef().setDataBinding('playerName', 'Bob'); // string
this.riveRef().setDataBinding('isActive', true); // boolean
const score = this.riveRef().getDataBinding('score'); // returns number
// Fire triggers
this.riveRef().fireViewModelTrigger('onComplete');Color Manipulation (Resolves ng-rive #56)
🎨 Rich Color API — Set and manipulate colors using multiple formats: hex strings, ARGB integers, or RiveColor objects.
// Multiple color formats supported
this.riveRef().setColor('backgroundColor', '#FF5733'); // hex string
this.riveRef().setColor('backgroundColor', 0xFFFF5733); // ARGB integer
this.riveRef().setColor('backgroundColor', { r: 255, g: 87, b: 51, a: 255 });
// RGBA components
this.riveRef().setColorRgba('backgroundColor', 255, 87, 51, 255);
// Opacity manipulation (preserves RGB)
this.riveRef().setColorOpacity('backgroundColor', 0.5); // 0.0-1.0
// Get color
const color = this.riveRef().getColor('backgroundColor');
// Returns: { r: 255, g: 87, b: 51, a: 255 }Color Utilities (Exported)
🛠️ Standalone Color Tools — Utility functions exported for consumer use.
import { parseRiveColor, riveColorToArgb, riveColorToHex } from '@grandgular/rive-angular';
// Parse any color format
const color = parseRiveColor('#FF5733');
// Returns: { r: 255, g: 87, b: 51, a: 255 }
// Convert to formats
const argb = riveColorToArgb(color); // 0xFFFF5733
const hex = riveColorToHex(color); // '#FF5733FF'Controlled vs Uncontrolled Semantics
⚖️ React-inspired pattern — Keys in dataBindings input are controlled (input wins on every update). Keys outside are uncontrolled (managed imperatively). Calling setDataBinding() on a controlled key logs a warning in debug mode.
Advanced ViewModel Access
🔬 viewModelInstance Signal — Direct access to the ViewModel instance for advanced scenarios.
const vm = this.riveRef().viewModelInstance();
if (vm) {
console.log('ViewModel properties:', vm.properties);
}Error Handling
🏷️ New RIVE_4xx Error Codes — Data Binding validation errors emitted through loadError output:
| Code | Name | Description |
|---|---|---|
RIVE_401 |
ViewModelNotFound |
Specified ViewModel not found in file |
RIVE_402 |
DataBindingPropertyNotFound |
Property path not found in ViewModel |
RIVE_403 |
DataBindingTypeMismatch |
Value type mismatch, invalid color format, or opacity out of range |
📐 API Reference
New Component Inputs
| Input | Type | Description |
|---|---|---|
dataBindings |
Record<string, DataBindingValue> |
Declarative ViewModel property bindings (controlled keys) |
viewModelName |
string | undefined |
ViewModel name to use (defaults to artboard's default) |
New Component Outputs
| Output | Type | Description |
|---|---|---|
dataBindingChange |
EventEmitter<DataBindingChangeEvent> |
Emits when ViewModel properties change from animation |
New Component Signals
| Signal | Type | Description |
|---|---|---|
viewModelInstance |
Signal<ViewModel | null> |
Direct access to current ViewModel instance |
New Component Methods
| Method | Signature | Description |
|---|---|---|
setDataBinding |
(path: string, value: DataBindingValue): void |
Set any ViewModel property (auto-detects type) |
getDataBinding |
(path: string): DataBindingValue | undefined |
Get any ViewModel property (auto-detects type) |
fireViewModelTrigger |
(path: string): void |
Fire a trigger property |
setColor |
(path: string, color: string | number | RiveColor): void |
Set color (hex, ARGB, or object) |
getColor |
(path: string): RiveColor | undefined |
Get color as RiveColor object |
setColorRgba |
(path: string, r: number, g: number, b: number, a?: number): void |
Set color using RGBA components |
setColorOpacity |
(path: string, opacity: number): void |
Set opacity (0.0-1.0) |
New Exported Types
interface RiveColor {
r: number; // 0-255
g: number; // 0-255
b: number; // 0-255
a: number; // 0-255
}
type DataBindingValue = number | string | boolean | RiveColor;
type DataBindingPropertyType =
| 'number'
| 'string'
| 'boolean'
| 'color'
| 'enum'
| 'trigger';
interface DataBindingChangeEvent {
path: string;
value: DataBindingValue;
propertyType: DataBindingPropertyType;
}New Exported Utilities
// Color parsing and conversion
function parseRiveColor(input: string | number | RiveColor): RiveColor;
function riveColorToArgb(color: RiveColor): number;
function riveColorToHex(color: RiveColor): string;🔄 Architecture
Data Binding uses Rive's official ViewModel system (introduced in @rive-app/canvas ^2.35.0) instead of direct shape manipulation. ViewModels are created in the Rive editor and provide:
- Type-safe property bindings
- Designer-friendly workflow
- Two-way reactivity
- Automatic UI updates
✅ No Breaking Changes
- All new features are optional and additive
dataBindingsinput is optional — existing templates unaffected- All new methods are purely additive
- No existing API signatures changed
- Files without ViewModels work exactly as before
📚 Documentation
- Updated README with Data Binding examples (declarative, imperative, color manipulation)
- Updated error codes table with
RIVE_401,RIVE_402,RIVE_403 - Updated API reference with 8 new methods and 3 new inputs/outputs
- Added Color Utilities section
- See CHANGELOG.md for complete details
🎯 Issue Resolution
This release resolves ng-rive issue #56 — "How to set solid color dynamically?" by providing a comprehensive color manipulation API through the ViewModel system.
🙏 Thanks
All 112 tests passing (53 new tests for Data Binding and color scenarios). Production-ready and feature-complete for dynamic data-driven animations.
v0.3.0 — Text Run Support
@grandgular/rive-angular v0.3.0
Feature release adding full Rive Text Run support with declarative and imperative APIs, matching the official @rive-app/canvas SDK.
🎉 What's New
Declarative Text Runs
📝 textRuns Input — New reactive input for template-driven text updates. Keys present in the input are controlled — the input is the source of truth.
<rive-canvas
src="assets/hello.riv"
[textRuns]="{ greeting: userName(), subtitle: 'Welcome' }"
/>Imperative Text Runs
🔧 getTextRunValue() / setTextRunValue() — Read and write text run values programmatically for keys not managed by the textRuns input (uncontrolled keys).
riveRef = viewChild.required(RiveCanvasComponent);
const value = this.riveRef().getTextRunValue('greeting');
this.riveRef().setTextRunValue('dynamicText', 'New value');Nested Artboard Text Runs
🪆 getTextRunValueAtPath() / setTextRunValueAtPath() — Access text runs inside nested artboards and components.
this.riveRef().setTextRunValueAtPath('button_text', 'Click Me', 'NestedArtboard/Button');Controlled vs Uncontrolled Semantics
⚖️ React-inspired pattern — Keys in textRuns input are controlled (input wins on every update). Keys outside are uncontrolled (managed imperatively). Calling setTextRunValue() on a controlled key logs a warning in debug mode.
Error Handling
🏷️ RIVE_205 Error Code — New TextRunNotFound validation error emitted through loadError output when a text run name doesn't exist in the animation file.
📐 API Compatibility
All four text run methods are a 1:1 match with the official @rive-app/canvas ^2.35.0 SDK:
| Method | Signature |
|---|---|
getTextRunValue |
(textRunName: string): string | undefined |
setTextRunValue |
(textRunName: string, textRunValue: string): void |
getTextRunValueAtPath |
(textRunName: string, path: string): string | undefined |
setTextRunValueAtPath |
(textRunName: string, textRunValue: string, path: string): void |
✅ No Breaking Changes
textRunsinput is optional — existing templates are unaffected.- All new methods are purely additive.
- No existing API signatures changed.
📚 Documentation
- Updated README with declarative, imperative, and nested text run examples.
- Updated error codes table with
RIVE_205. - Updated API reference table with all four new methods.
- See CHANGELOG.md for complete details.
🙏 Thanks
All 59 tests passing (13 new tests for text run scenarios). Production-ready.
v0.2.0 — Enhanced DX, Validation & Critical Fixes
@grandgular/rive-angular v0.2.0
Major feature release with enhanced developer experience, comprehensive validation system, and critical stability improvements.
🎉 What's New
Debug Mode & Validation
- 🛠️ Debug Mode — New
debugModeinput andprovideRiveDebug()for configurable logging ('none' | 'error' | 'warn' | 'info' | 'debug') - ✅ Automatic Validation — Validates artboard, animation, state machine, and input names against loaded files with helpful suggestions
- 🏷️ Error Codes — Structured error codes (
RIVE_1xx,RIVE_2xx,RIVE_3xx) for programmatic error handling
Reactive Configuration
- ⚡ Reactive Inputs — All component inputs (
fit,alignment,artboard,animations,stateMachines) now trigger appropriate updates - 🎨 Layout Optimization — Changes to
fit/alignmentupdate layout without full reload
Architecture Improvements
- 🔒 Readonly Signals — Public signals properly encapsulated to prevent external mutation
- 🏗️ DI Integration —
ElementObserverconverted to Angular service for better testability - 📦 Type Safety — Eliminated unsafe type assertions in configuration
🐛 Critical Fixes
- 📱 Multi-Monitor Support — Device pixel ratio now read dynamically, supporting monitor changes and zoom
- ⏱️ Proper Timing —
riveReadyoutput now emits after animation fully loads (not just instance creation) - 🔄 Race Conditions — Fixed race conditions in
RiveFileServiceand cache management - 🧹 Memory Leaks — Fixed
clearCache()to properly handle pending loads - 🔐 No Mutations — Service no longer mutates
ArrayBufferobjects (usesWeakMap)
⚠️ Breaking Changes
1. Readonly Signals
Public signals (isPlaying, isPaused, isLoaded, riveInstance) are now readonly.
Before:
component.isPlaying.set(true); // ❌ No longer worksAfter:
component.playAnimation(); // ✅ Use component methods2. riveReady Timing
riveReady output now emits after animation is fully loaded.
Before:
// Emitted immediately, instance might not be ready
(riveReady)="onReady($event)"After:
// Emits after load, instance is guaranteed ready
(riveReady)="onReady($event)" // artboardNames available
// Or use (loaded) if you don't need the instance📚 Documentation
See CHANGELOG.md for complete details and migration guide.
🙏 Thanks
All 45 tests passing. Production-ready with comprehensive audit completed.
v0.1.2 — Safari ResizeObserver fix
@grandgular/rive-angular v0.1.2
Patch release with a Safari browser compatibility fix.
What's Changed
🐛 ResizeObserver loop fix — Resolved ResizeObserver loop completed with undelivered notifications error that occurred in Safari browsers during canvas resize operations
Technical Details
- Added error boundary handling for ResizeObserver callback
- Prevents console errors without affecting animation rendering functionality
v0.1.1 — Repository links update
@grandgular/rive-angular v0.1.1
Patch release with updated package metadata.
What's Changed
🔗 Repository links — Updated GitHub repository URLs from personal account to organization account (Grandgular/rive)
Package Metadata Updates
repository.url: https://github.com/Grandgular/rive.githomepage: https://github.com/Grandgular/rive/tree/main/libs/rive-angular#readmebugs.url: https://github.com/Grandgular/rive/issues
v0.1.0 — Angular wrapper for Rive animations
@grandgular/rive-angular v0.1.0
Initial release of a modern Angular wrapper for Rive animations with reactive state management.
Highlights
- 🚀 Modern Angular — Built with Angular 18+ signals, standalone components, and zoneless architecture
- ⚡ Performance-first — Runs outside Angular zone, OnPush change detection, IntersectionObserver for off-screen optimization
- 🔄 Reactive API — Signal-based state management (
isPlaying,isPaused,isLoaded,riveInstance) - 📦 File caching —
RiveFileServicefor preloading and caching .riv files - 🌐 SSR-ready — Full server-side rendering support
- 🎯 Type-safe — Full TypeScript support
What's included
- RiveCanvasComponent — Standalone component with support for animations, state machines, triggers, and inputs
- RiveFileService — Preload and cache .riv files with reference counting
- Public methods —
playAnimation,pauseAnimation,stopAnimation,reset,setInput,fireTrigger - Event outputs —
loaded,loadError,stateChange,riveEvent,riveReady
Requirements
- Angular 18.0.0 or higher
- @rive-app/canvas 2.35.0 or higher
Install
```bash
npm install @grandgular/rive-angular @rive-app/canvas
```
Documentation
See README for full API reference and usage examples.