Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ jobs:
node-version: ${{ matrix.node-version }}
cache: 'npm'

- name: Use pinned npm via Corepack (match packageManager)
run: |
corepack enable
corepack prepare npm@11.12.1 --activate
npm --version

- name: Install dependencies
run: npm ci

Expand Down Expand Up @@ -63,6 +69,12 @@ jobs:
node-version: '20.x'
cache: 'npm'

- name: Use pinned npm via Corepack (match packageManager)
run: |
corepack enable
corepack prepare npm@11.12.1 --activate
npm --version

- name: Install dependencies
run: npm ci

Expand Down
108 changes: 90 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,26 @@

Modern Angular wrapper for [Rive](https://rive.app) animations with reactive state management, built with Angular signals and zoneless architecture.

**1.x** is the stable major line: the public API follows [Semantic Versioning](https://semver.org/).
**2.x** is the current major line: the public API follows [Semantic Versioning](https://semver.org/).
Current release candidate in this branch: **`2.0.0-beta.4`** (pre-release).

## Migration from v1 to v2

Version `2.0.0` contains a deliberate breaking change to remove hard runtime linkage to `@rive-app/canvas` and fully support `webgl2-only` installations.

### Breaking change: runtime value exports removed

These exports are now **type-only** from `@grandgular/rive-angular`:

- `Rive`
- `RiveFile`
- `Layout`
- `StateMachineInput`
- `ViewModelInstance`

If your app used them as runtime values (for example `new Rive(...)` from this package), switch to direct SDK imports from `@rive-app/canvas` or `@rive-app/webgl2` depending on your runtime path.

Most applications using `RiveCanvasComponent`, `RiveFileService`, `Fit`, `Alignment`, `EventType`, `LoopType`, and component APIs do not require code changes.

## What is Rive?

Expand Down Expand Up @@ -54,7 +73,7 @@ This library follows the design principles of the official [rive-react](https://

| Aspect | rive-react | @grandgular/rive-angular |
|--------|------------|--------------------------|
| Component API | `<Rive>` component | `<rive-canvas>` |
| Component API | `<Rive>` component | `<rive>` (`<rive-canvas>` legacy alias) |
| Reactivity | Hooks (useState, useEffect) | Signals |
| File preloading | `useRiveFile` hook | `RiveFileService` |
| State access | Hook return values | Public signals |
Expand All @@ -73,6 +92,8 @@ npm uninstall ng-rive
npm install @grandgular/rive-angular @rive-app/canvas
```

If you use WebGL2 (`provideRiveRuntime({ renderer: 'webgl2' })`) or rely on automatic fallback from WebGL2 to Canvas, also install `@rive-app/webgl2` (see [Installation](#installation)).

### 2. Update imports

| ng-rive | @grandgular/rive-angular |
Expand All @@ -95,7 +116,7 @@ npm install @grandgular/rive-angular @rive-app/canvas

```html
<!-- Standalone, signals, zoneless -->
<rive-canvas
<rive
src="assets/my-animation.riv"
[autoplay]="true"
style="width: 500px; height: 500px"
Expand All @@ -117,7 +138,7 @@ npm install @grandgular/rive-angular @rive-app/canvas
**@grandgular/rive-angular:**

```html
<rive-canvas
<rive
src="assets/my-animation.riv"
stateMachines="StateMachine"
(loaded)="onLoaded()"
Expand All @@ -132,6 +153,14 @@ onLoaded() {

## Installation

`@rive-app/canvas` and `@rive-app/webgl2` are **optional peer dependencies**: install the runtime package(s) that match how you configure the library. The bundler only pulls in the SDK that is actually imported for your `renderer` / fallback path.

| Goal | Packages to install |
|------|------------------------|
| Canvas only (default `renderer`, or you never use WebGL2) | `@grandgular/rive-angular` + `@rive-app/canvas` |
| WebGL2 only (e.g. `renderer: 'webgl2'` and `strict: true`, so no Canvas fallback) | `@grandgular/rive-angular` + `@rive-app/webgl2` |
| WebGL2 with automatic fallback to Canvas (`strict: false`) | `@grandgular/rive-angular` + `@rive-app/canvas` + `@rive-app/webgl2` |

```bash
npm install @grandgular/rive-angular @rive-app/canvas
```
Expand All @@ -142,8 +171,23 @@ Or with yarn:
yarn add @grandgular/rive-angular @rive-app/canvas
```

Add WebGL2 when needed:

```bash
npm install @rive-app/webgl2
```

If a required package is missing, initialization fails with an error that names the package and suggests either installing it or setting `strict: true` to avoid loading that renderer/fallback path.

## Quick Start

### Selector notice

- Preferred selector: `<rive>`
- Legacy selector: `<rive-canvas>` (deprecated, will be removed in a future major version)

Both selectors are supported in the current major for backward compatibility.

### Basic usage

```typescript
Expand All @@ -155,7 +199,7 @@ import { RiveCanvasComponent, Fit, Alignment } from '@grandgular/rive-angular';
standalone: true,
imports: [RiveCanvasComponent],
template: `
<rive-canvas
<rive
src="assets/animation.riv"
[autoplay]="true"
[fit]="Fit.Cover"
Expand All @@ -165,7 +209,7 @@ import { RiveCanvasComponent, Fit, Alignment } from '@grandgular/rive-angular';
/>
`,
styles: [`
rive-canvas {
rive {
width: 100%;
height: 400px;
}
Expand Down Expand Up @@ -196,7 +240,7 @@ import { RiveCanvasComponent } from '@grandgular/rive-angular';
standalone: true,
imports: [RiveCanvasComponent],
template: `
<rive-canvas
<rive
src="assets/interactive.riv"
[stateMachines]="'StateMachine'"
(loaded)="onLoaded()"
Expand Down Expand Up @@ -228,7 +272,7 @@ Rive text runs allow you to update text content at runtime. The library provides
Use the `textRuns` input for reactive, template-driven text updates:

```html
<rive-canvas
<rive
src="assets/hello.riv"
[textRuns]="{ greeting: userName(), subtitle: 'Welcome' }"
/>
Expand Down Expand Up @@ -298,7 +342,7 @@ import { RiveCanvasComponent } from '@grandgular/rive-angular';
standalone: true,
imports: [RiveCanvasComponent],
template: `
<rive-canvas
<rive
src="assets/animation.riv"
[dataBindings]="{
backgroundColor: themeColor(),
Expand Down Expand Up @@ -356,7 +400,7 @@ import { RiveCanvasComponent } from '@grandgular/rive-angular';
standalone: true,
imports: [RiveCanvasComponent],
template: `
<rive-canvas src="assets/animation.riv" />
<rive src="assets/animation.riv" />

<button (click)="updateColor()">Update Color</button>
<button (click)="updateScore()">Update Score</button>
Expand Down Expand Up @@ -425,7 +469,7 @@ const hex = riveColorToHex({ r: 255, g: 0, b: 0, a: 255 }); // '#FF0000FF'
If your `.riv` file contains multiple ViewModels, specify which one to use:

```typescript
<rive-canvas
<rive
src="assets/animation.riv"
viewModelName="GameViewModel"
[dataBindings]="{ score: 42 }"
Expand All @@ -452,7 +496,7 @@ Imperative methods (`setDataBinding`, `setColor`, `setColorOpacity`, `fireViewMo
- Opacity value is out of range (must be between 0.0 and 1.0)

```typescript
<rive-canvas
<rive
src="assets/animation.riv"
(loadError)="handleError($event)"
/>
Expand Down Expand Up @@ -497,7 +541,7 @@ import { RiveCanvasComponent, RiveFileService } from '@grandgular/rive-angular';
imports: [RiveCanvasComponent],
template: `
@if (fileState().status === 'success') {
<rive-canvas
<rive
[riveFile]="fileState().riveFile"
[autoplay]="true"
/>
Expand Down Expand Up @@ -553,7 +597,7 @@ Available log levels: `'none' | 'error' | 'warn' | 'info' | 'debug'`
Enable debug mode for a specific component instance:

```typescript
<rive-canvas
<rive
src="assets/animation.riv"
[debugMode]="true"
/>
Expand All @@ -568,6 +612,9 @@ When debug mode is enabled, the library will log:

Use `provideRiveRuntime()` to control when the Rive WASM runtime initializes.

By default, runtime uses `renderer: 'canvas'` for backward compatibility.
To enable vector feathering support, configure `renderer: 'webgl2'`.

### Eager mode (default)

Initializes runtime on app startup:
Expand All @@ -578,7 +625,10 @@ import { provideRiveRuntime } from '@grandgular/rive-angular';

export const appConfig: ApplicationConfig = {
providers: [
provideRiveRuntime({ wasmUrl: 'assets/rive/rive.v1.wasm' }),
provideRiveRuntime({
wasmUrl: 'assets/rive/rive.v1.wasm',
renderer: 'canvas',
}),
],
};
```
Expand All @@ -596,11 +646,29 @@ export const appConfig: ApplicationConfig = {
provideRiveRuntime({
wasmUrl: 'assets/rive/rive.v1.wasm',
lazy: true,
renderer: 'webgl2',
strict: false,
}),
],
};
```

### Renderer fallback behavior

```typescript
provideRiveRuntime({
renderer: 'webgl2',
strict: false,
});
```

- `renderer` is optional; default is `'canvas'`.
- `strict` is optional; default is `false`.
- With `strict: false`, the library automatically falls back to the other renderer if the preferred renderer fails to initialize. **Both** `@rive-app/canvas` and `@rive-app/webgl2` must be installed for fallback to succeed if the other SDK is needed.
- With `strict: true`, fallback is disabled and initialization fails fast if the chosen renderer cannot load — useful when you intentionally ship only one runtime package.

If fallback fails (for example WebGL2 unavailable **and** the Canvas package is not installed), the error explains what failed and suggests installing the missing package or using `strict: true` with a single renderer.

### Migration from `provideAppInitializer`

If you used:
Expand All @@ -624,7 +692,7 @@ The library validates your configuration against the loaded Rive file and provid
Validation errors (e.g., missing artboard or animation) are **non-fatal**. They are emitted via the `loadError` output but do not crash the application.

```typescript
<rive-canvas
<rive
src="assets/anim.riv"
[artboard]="'WrongName'"
(loadError)="onError($event)"
Expand Down Expand Up @@ -659,12 +727,16 @@ In this case, `onError` receives a `RiveValidationError` with code `RIVE_201`, a
interface RiveRuntimeConfig {
wasmUrl?: string;
lazy?: true;
renderer?: 'canvas' | 'webgl2';
strict?: boolean;
}
```

- `provideRiveRuntime(config?: RiveRuntimeConfig)` - configures Rive runtime initialization strategy.
- `lazy` omitted - eager initialization on startup.
- `lazy: true` - deferred initialization at first runtime usage.
- `renderer` omitted - defaults to `'canvas'` for backward compatibility.
- `strict` omitted - defaults to `false` and allows automatic fallback.

### RiveCanvasComponent

Expand Down Expand Up @@ -723,7 +795,7 @@ import {
@Component({
imports: [RiveCanvasComponent],
template: `
<rive-canvas
<rive
src="animation.riv"
(animationPlay)="onAnimationPlay($event)"
(animationPause)="onAnimationPause($event)"
Expand Down Expand Up @@ -850,7 +922,7 @@ See [CHANGELOG.md](libs/rive-angular/CHANGELOG.md) for complete details, migrati
## Requirements

- Angular 18.0.0 or higher
- @rive-app/canvas 2.35.0 or higher
- At least one of: `@rive-app/canvas` or `@rive-app/webgl2` (^2.35.0), matching your `provideRiveRuntime` / fallback setup (see [Installation](#installation))
- TypeScript 5.4 or higher

## Contributing
Expand Down
59 changes: 59 additions & 0 deletions libs/rive-angular/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,65 @@

All notable changes to this project will be documented in this file.

## [2.0.0-beta.4] - 2026-04-26

### Changed

- Runtime fallback is now explicit via `provideRiveRuntime({ fallback: true })`; selecting `renderer: 'webgl2'` no longer requires installing `@rive-app/canvas`, and the default Canvas path no longer requires `@rive-app/webgl2`.
- Removed the `strict` runtime option from the beta API; omit `fallback` to ship only the selected runtime.

## [2.0.0-beta.3] - 2026-04-20

### Fixed

- Dynamic SDK imports: add `/* @vite-ignore */` so Vite does not fail to resolve optional peers (`@rive-app/webgl2` / `@rive-app/canvas`) when only one runtime is installed (e.g. canvas-only apps using default `renderer`).

## [2.0.0-beta.2] - 2026-04-20

### Fixed

- Public `Rive` type: restored SDK-compatible event API on the stub interface (`on`, `off`, `removeAllRiveEventListeners`) so direct instance usage (e.g. `rive.on(EventType.RiveEvent, ...)`) type-checks again after v2 type-only exports.

## [2.0.0-beta.1] - 2026-04-20

### Fixed

- `RiveFileService`: `await Promise.resolve(file.init())` so promise rejections from `RiveFile.init()` are handled and the file state moves to `failed` instead of staying `loading`.
- `RiveFileService` tests: async `flushLoadMicrotasks()` for init-failure cases (reliable in CI).

## [2.0.0-beta.0] - 2026-04-19

### Added

- **Dual runtime support** for `@rive-app/canvas` and `@rive-app/webgl2` with `provideRiveRuntime()` options `renderer` and explicit `fallback`.
- **Preferred component selector**: `<rive>` (with `<rive-canvas>` still supported as a legacy alias).
- **Runtime tests** covering `webgl2`, single-runtime behavior, and explicit fallback failures.

### Changed

- Runtime SDK loading now uses dynamic imports for both renderers and no longer keeps a static runtime import of `@rive-app/canvas`.
- Runtime error handling now emits clearer missing-package and fallback failure messages, including install hints for single-runtime and fallback setups.
- Runtime initialization defaults are centralized through `DEFAULT_RIVE_RUNTIME_RESOLVED_CONFIG` and reused by both `RiveCanvasComponent` and `RiveFileService`.
- README/docs were updated to describe optional runtime peers and renderer/fallback installation matrix.

### Fixed

- Stabilized async zoneless specs in `RiveCanvasComponent` and `RiveFileService` by removing dangling timers and isolating runtime lifecycle state between tests.

### Breaking Changes

- The following exports from `@grandgular/rive-angular` are now **type-only** and are no longer runtime values: `Rive`, `RiveFile`, `Layout`, `StateMachineInput`, `ViewModelInstance`.
- This removes accidental hard linkage to `@rive-app/canvas` in `webgl2-only` installs.

### Migration

- If you used these symbols as runtime classes/values, import them directly from the selected Rive SDK package (`@rive-app/canvas` or `@rive-app/webgl2`).
- Typical component/service usage (`RiveCanvasComponent`, `RiveFileService`, `Fit`, `Alignment`, `EventType`, `LoopType`) remains unchanged.

### Notes

- `<rive-canvas>` is deprecated and is planned for removal in a future major release.

## [1.1.0] - 2026-04-16

### Added
Expand Down
Loading
Loading