Skip to content
Merged
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
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,6 @@ When you're sending a pull request:

## Runtime backends

The legacy backend exists for behavior comparison during the experimental
The legacy backend exists for behavior comparison during the new-runtime
rollout — see [docs/runtime-backends.md](docs/runtime-backends.md) for how to
select it and the behavioral differences to compare against.
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ class HybridRiveFile(
override fun updateReferencedAssets(referencedAssets: ReferencedAssetsType) {
RiveLog.w(
TAG,
"updateReferencedAssets is not supported with the experimental backend — already-rendered artboards cannot be updated. Use the legacy backend for runtime asset swapping."
"updateReferencedAssets is not supported — already-rendered artboards cannot be updated. Supply assets via referencedAssets at load time instead."
)
}

Expand Down
50 changes: 50 additions & 0 deletions docs/migrating-to-0.5.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Migrating to 0.5 (the new Rive runtime)

0.5 switches the library to Rive's new CommandQueue-based runtime
([New Runtime](https://rive.app/docs/runtimes/apple/apple) on iOS,
[New Compose API](https://rive.app/docs/runtimes/android) on Android) and
completes the move to the async JS API. The recommended path:

## 1. On the latest 0.4.x: move to the async APIs

The full async surface already ships in 0.4 — migrate there first, while
everything still behaves exactly as before. Your editor's deprecation
strikethroughs point at each replacement:

| Deprecated | Use instead |
| ------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
| `property.value` (read / write) | `getValueAsync()` / `set(value)` |
| `viewModel(path)` | `viewModelAsync(path)` |
| `createInstanceByName/ByIndex`, `createDefaultInstance`, `createInstance` | `createInstanceByNameAsync`, `createDefaultInstanceAsync`, `createBlankInstanceAsync` |
| `viewModelByName/ByIndex`, `defaultArtboardViewModel` | `viewModelByNameAsync`, `defaultArtboardViewModelAsync` |
| list `length`, `getInstanceAt`, `addInstance(At)`, `removeInstance(At)`, `swap` | the `*Async` equivalents |
| `artboardNames`, `artboardCount`, `viewModelCount`, `propertyCount`, `instanceCount`, `getEnums` (sync) | the `*Async` equivalents |
| `useViewModelInstance(file)` (sync creation) | `useViewModelInstance(file, { async: true })` |
| state-machine inputs / text runs / Rive events on the view | [data binding](https://rive.app/docs/runtimes/data-binding) |

## 2. Try the 0.5 beta

```sh
npm install @rive-app/react-native@next
```

The new runtime is now the default. Things to know:

- Deprecated sync APIs still work, but they block the JS thread and log a
once-per-member `[Rive/Deprecation]` warning.
- The deprecated state-machine-input, text-run, and Rive-event view methods
**throw** — data binding replaces them.
- Property accessors (`numberProperty(path)` etc.) return unvalidated
handles; a typo'd path surfaces via the `getValueAsync()` rejection or the
`useRive*` hooks' `error` result instead of an `undefined` return.
- `updateReferencedAssets` (runtime asset swapping) is not supported.

## 3. 0.5 stable

Same behavior as the beta: fully migrated apps run warning-free; remaining
deprecated calls keep working with runtime warnings.

## 4. 0.6
Comment thread
mfazekas marked this conversation as resolved.

Removal of the deprecated APIs is planned for 0.6. Apps that completed
step 1 need no further changes.
22 changes: 11 additions & 11 deletions docs/riv-files.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ Properties of all .riv files used in this project.
|------|----|----|-----|-------|
| `quick_start.riv` | Yes | Yes | Yes | Artboard: `health_bar_v01`. VM props: `health` (number), `gameOver` (trigger). Game health/damage system. |
| `databinding.riv` | Yes | Yes | Yes | Primary data binding test file. `Person` VM with: `age` (number), `name` (string), `likes_popcorn` (bool), `favourite_color` (color), `favourite_pet` (enum), `jump` (trigger). Nested `pet` VM. Enum `Pets`: dog/cat/frog/owl/chipmunk/rat. 2 view models total. |
| `databinding_lists.riv` | Yes | Yes | - | `DevRel` VM with `team` list property. Default 5 items. Tests list mutations (exercised on the experimental backend by `databinding-advanced` / `async-api` harness suites). |
| `databinding_images.riv` | Yes | Yes | - | `MyViewModel` with `bound_image` image property. Runs on the experimental backend (covered by harness suites). |
| `artboard_db_test.riv` | Yes | Yes | - | Multiple artboards, artboard properties: `artboard_1`, `artboard_2`. Runs on the experimental backend (covered by harness suites). |
| `databinding_lists.riv` | Yes | Yes | - | `DevRel` VM with `team` list property. Default 5 items. Tests list mutations (exercised on the new runtime by `databinding-advanced` / `async-api` harness suites). |
| `databinding_images.riv` | Yes | Yes | - | `MyViewModel` with `bound_image` image property. Runs on the new runtime (covered by harness suites). |
| `artboard_db_test.riv` | Yes | Yes | - | Multiple artboards, artboard properties: `artboard_1`, `artboard_2`. Runs on the new runtime (covered by harness suites). |
| `viewmodelproperty.riv` | Yes | Yes | - | Complex nested VMs: `vm1`/`vm2` instances with nested `pet` VM. Tests replaceViewModel(). |
| `rewards.riv` | Yes | Yes | Yes | Bouncing chest animation by default. Nested property paths: `Coin/Item_Value` (number), `Button/State_1` (string), `Energy_Bar/Bar_Color` (color), `Button/Pressed` (trigger). Works with experimental runtime. |
| `rewards.riv` | Yes | Yes | Yes | Bouncing chest animation by default. Nested property paths: `Coin/Item_Value` (number), `Button/State_1` (string), `Energy_Bar/Bar_Color` (color), `Button/Pressed` (trigger). Works with the new runtime. |
| `many_viewmodels.riv` | Yes | Yes | - | Named instances: `red`, `green`, `blue`. Image property: `imageValue`. |
| `rating.riv` | Yes | No | No | Static 5-star selector — no auto-play animation, only responds to SM number input: `rating` (0-5). |
| `out_of_band.riv` | Yes | No | - | SM: `State Machine 1`. OOB image (`referenced-image-2929282`), font (`Inter-594377`), audio (`referenced_audio-2929340`). |
Expand All @@ -40,16 +40,16 @@ Properties of all .riv files used in this project.

| URL | SM | DB | AP | Notes |
|-----|----|----|-----|-------|
| `cdn.rive.app/animations/vehicles.riv` | **No** | No | Yes | Endless looping vehicle parade. No state machine, no interactivity. **Does not work with experimental iOS runtime** (requires SM). |
| `cdn.rive.app/animations/off_road_car_v7.riv` | **No** | No | Yes | Off-road car with idle/bouncing/windshield_wipers timeline animations. No state machine. **Does not work with experimental iOS runtime**. |
| `cdn.rive.app/animations/vehicles.riv` | **No** | No | Yes | Endless looping vehicle parade. No state machine, no interactivity. **Does not work with the new iOS runtime** (requires SM). |
| `cdn.rive.app/animations/off_road_car_v7.riv` | **No** | No | Yes | Off-road car with idle/bouncing/windshield_wipers timeline animations. No state machine. **Does not work with the new iOS runtime**. |

## Experimental Backend Compatibility
## New Runtime Compatibility

Historical note: `databinding_images.riv`, `artboard_db_test.riv`, and
`databinding_lists.riv` list mutations crashed early experimental builds
`databinding_lists.riv` list mutations crashed early new-runtime builds
(EXC_BAD_ACCESS); all three are now exercised green by the harness suites CI
runs on the experimental backend.
runs on the new runtime.

Files that **don't work** with experimental backend:
- `vehicles.riv` (remote) - no state machine, experimental API requires one
Files that **don't work** with new runtime:
- `vehicles.riv` (remote) - no state machine, the new runtime requires one
- `swap_character_assets.riv` - no state machine (asset-only file)
17 changes: 10 additions & 7 deletions docs/runtime-backends.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Runtime backends (contributor guide)

The library ships two native backends and uses the **experimental** Rive
The library ships two native backends and uses the **new** Rive
runtime backend (Rive's CommandQueue-based async API) by default. The
previous implementation is kept as the **legacy** backend **for development
and behavior comparison only** — it is not a supported end-user
configuration and will be removed once the experimental backend has fully
configuration and will be removed once the new runtime has fully
proven out. Select it at build time:

- **iOS** — set the Podfile global before `pod install`:
Expand All @@ -16,7 +16,7 @@ proven out. Select it at build time:

(`USE_RIVE_LEGACY=1 pod install` also works, but the env var only applies
to that invocation — any plain `pod install` afterwards silently switches
the project back to the experimental backend, so prefer the Podfile
the project back to the new runtime, so prefer the Podfile
global.)

- **Android** — set the Gradle property, e.g. in `android/gradle.properties`:
Expand All @@ -26,9 +26,12 @@ proven out. Select it at build time:
```

You can check which backend is active at runtime via
`RiveFileFactory.getBackend()` (`'experimental' | 'legacy'`).
`RiveFileFactory.getBackend()` (`'experimental' | 'legacy'`, where
`'experimental'` is the new runtime). This API is for internal testing only —
it and the legacy runtime will be removed in a future release once the new
runtime has fully proven out (not necessarily 0.6).

Behavioral differences on the experimental backend:
Behavioral differences on the new runtime:

- The deprecated state-machine-input, text-run, and Rive-event view methods
throw — use [data binding](https://rive.app/docs/runtimes/data-binding)
Expand All @@ -38,9 +41,9 @@ Behavioral differences on the experimental backend:
`useRive*` hooks' `error` result instead of an `undefined` return.
- `updateReferencedAssets` (runtime asset swapping) is not supported.

## Android render backend (experimental backend only)
## Android render backend (new runtime only)

The experimental Android backend renders with OpenGL by default. Vulkan can
The new Android runtime renders with OpenGL by default. Vulkan can
be opted into per process:

```ts
Expand Down
2 changes: 1 addition & 1 deletion example/__tests__/asset-loading.harness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ function isExperimental() {

describe('Asset loading with referencedAssets', () => {
// referencedAssets with raw ResolvedReferencedAsset objects only works
// on the experimental backend; legacy uses a different resolution path.
// on the new runtime; legacy uses a different resolution path.
it('loads file with font asset (type: font)', async () => {
if (!isExperimental()) return;
const file = await RiveFileFactory.fromSource(OUT_OF_BAND, {
Expand Down
4 changes: 2 additions & 2 deletions example/__tests__/async-api.harness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ describe('Async ViewModel Creation', () => {
const instance = await vm.createInstanceByNameAsync('__DoesNotExist__');
expect(instance).toBeUndefined();
} catch {
// experimental backend may throw
// new runtime may throw
}
});

Expand Down Expand Up @@ -275,7 +275,7 @@ describe('Async ViewModelInstance Methods', () => {
expect(result).toBeUndefined();
}
} catch {
// experimental backend may throw
// new runtime may throw
}
});

Expand Down
2 changes: 1 addition & 1 deletion example/__tests__/autoplay.harness.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ describe('imperative playback control (play/pause/reset)', () => {
cleanup();
});

// reset() is deprecated and a no-op on the experimental backend (no reset
// reset() is deprecated and a no-op on the new runtime (no reset
// primitive in the runtime); it logs an error and resolves without throwing.
it('reset() resolves without throwing (deprecated no-op)', async () => {
const { file, instance } = await loadBouncingBall();
Expand Down
2 changes: 1 addition & 1 deletion example/__tests__/bind-before-ready.harness.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const delay = (ms: number) => new Promise((r) => setTimeout(r, ms));

describe('bindViewModelInstance before view ready', () => {
it('bind called before configure completes is applied', async () => {
// The race only exists on iOS experimental — riveInstance is set async
// The race only exists on the new iOS runtime — riveInstance is set async
if (
Platform.OS !== 'ios' ||
RiveFileFactory.getBackend() !== 'experimental'
Expand Down
2 changes: 1 addition & 1 deletion example/__tests__/databinding-advanced.harness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ describe('ViewModel Creation Variants', () => {
const instance = vm.createInstanceByName('DoesNotExist');
expect(instance).toBeUndefined();
} catch {
// experimental backend throws - that's fine
// new runtime throws - that's fine
}
});

Expand Down
2 changes: 1 addition & 1 deletion example/__tests__/play-after-autoplay-false.harness.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ async function waitForWritableInput(context: TestContext): Promise<void> {
// backends (both platforms).
function skipOnExperimental(): boolean {
if (RiveFileFactory.getBackend() === 'experimental') {
console.warn('SKIP: experimental backend — SMI inputs are not supported');
console.warn('SKIP: new runtime — SMI inputs are not supported');
return true;
}
return false;
Expand Down
2 changes: 1 addition & 1 deletion example/__tests__/reconfigure.harness.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ function SwitchableRiveView({

describe('RiveView reconfigure (file switch)', () => {
it('animation still plays after switching file prop and back', async () => {
// Fix only applies to iOS experimental — setupRiveUIView teardown churn
// Fix only applies to the new iOS runtime — setupRiveUIView teardown churn
if (
Platform.OS !== 'ios' ||
RiveFileFactory.getBackend() !== 'experimental'
Expand Down
2 changes: 1 addition & 1 deletion example/__tests__/rivelog.harness.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const isExperimental = RiveFileFactory.getBackend() === 'experimental';
type LogEntry = { level: string; tag: string; message: string };

describe('RiveLog', () => {
// Deprecation warnings only fire in the experimental backend
// Deprecation warnings only fire in the new runtime
(isExperimental ? it : it.skip)(
'captures deprecation warning from sync method',
async () => {
Expand Down
4 changes: 2 additions & 2 deletions example/__tests__/use-rive-trigger.harness.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ describe('useRiveTrigger hook', () => {

expect(context.error).toBeNull();

// Wait for the experimental backend's view to be ready before firing.
// Wait for the new runtime's view to be ready before firing.
await waitForViewReady(context);

// Fire trigger and wait for it — pollChanges() runs on frame ticks,
Expand Down Expand Up @@ -243,7 +243,7 @@ describe('useRiveTrigger hook', () => {

expect(context.error).toBeNull();

// Wait for the experimental backend's view to be ready before firing.
// Wait for the new runtime's view to be ready before firing.
await waitForViewReady(context);

// Fire trigger AFTER the re-render burst — before the fix, this was lost
Expand Down
4 changes: 2 additions & 2 deletions example/__tests__/view-methods.harness.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,11 @@ describe('RiveView methods', () => {
});
});

// The headline behavioral break of the experimental backend: the deprecated
// The headline behavioral break of the new runtime: the deprecated
// SMI-input / text-run / event methods throw instead of being implemented.
// Guards the documented contract (specs say "Throws on the experimental
// backend") — if an implementation lands, update the docs and these tests.
describe('deprecated RiveView methods throw on the experimental backend', () => {
describe('deprecated RiveView methods throw on the new runtime', () => {
const mountView = async () => {
const file = await RiveFileFactory.fromSource(BOUNCING_BALL, undefined);
const context: TestContext = { ref: null, error: null };
Expand Down
2 changes: 1 addition & 1 deletion example/__tests__/viewmodel-properties.harness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ describe('Property Listeners', () => {
const delay = (ms: number) => new Promise((r) => setTimeout(r, ms));

describe('Listener callback invocation (experimental only)', () => {
// The experimental backend emits the current value on addListener;
// The new runtime emits the current value on addListener;
// legacy only fires on subsequent changes — these tests would hang.
it('numberProperty listener emits current value', async () => {
if (!isExperimental()) return;
Expand Down
2 changes: 1 addition & 1 deletion ios/new/HybridRiveFile.swift
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ class HybridRiveFile: HybridRiveFileSpec {
}

func updateReferencedAssets(referencedAssets: ReferencedAssetsType) {
RCTLogWarn("[Rive] updateReferencedAssets is not supported with the experimental backend — already-rendered artboards cannot be updated. Use the legacy backend for runtime asset swapping.")
RCTLogWarn("[Rive] updateReferencedAssets is not supported — already-rendered artboards cannot be updated. Supply assets via referencedAssets at load time instead.")
}

func getEnums() throws -> Promise<[RiveEnumDefinition]> {
Expand Down
4 changes: 2 additions & 2 deletions ios/new/HybridRiveView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,11 @@ class HybridRiveView: HybridRiveViewSpec {
}

func onEventListener(onEvent: @escaping (UnifiedRiveEvent) -> Void) throws {
throw RuntimeError.error(withMessage: "Events are not supported in the experimental iOS API")
throw RuntimeError.error(withMessage: "Events are not supported by the new iOS runtime — use data binding")
}

func removeEventListeners() throws {
throw RuntimeError.error(withMessage: "Events are not supported in the experimental iOS API")
throw RuntimeError.error(withMessage: "Events are not supported by the new iOS runtime — use data binding")
}

func setNumberInputValue(name: String, value: Double, path: String?) throws {
Expand Down
16 changes: 8 additions & 8 deletions ios/new/RiveReactNativeView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@
// Probe for a default ViewModel first. If the artboard has none,
// the SDK would fire an error event — skip auto-binding silently instead.
do {
let _ = try await config.file.getDefaultViewModelInfo(for: artboard)

Check warning on line 101 in ios/new/RiveReactNativeView.swift

View workflow job for this annotation

GitHub Actions / lint-swift

Prefer `_ = foo()` over `let _ = foo()` when discarding a result from a function (redundant_discardable_let)
dataBind = .auto
} catch {
dataBind = .none
Expand Down Expand Up @@ -172,7 +172,7 @@

func reset() {
// Deprecated: the experimental Rive runtime has no reset primitive.
RiveLog.e("RiveReactNativeView", "reset() is deprecated and not supported on the experimental backend")
RiveLog.e("RiveReactNativeView", "reset() is deprecated and not supported on the new runtime")
}

func playIfNeeded() {
Expand All @@ -183,31 +183,31 @@
}

func setNumberInputValue(name: String, value: Float, path: String?) throws {
throw RuntimeError.error(withMessage: "SMI inputs not supported in experimental API")
throw RuntimeError.error(withMessage: "SMI inputs are not supported by the new runtime — use data binding")
}

func getNumberInputValue(name: String, path: String?) throws -> Float {
throw RuntimeError.error(withMessage: "SMI inputs not supported in experimental API")
throw RuntimeError.error(withMessage: "SMI inputs are not supported by the new runtime — use data binding")
}

func setBooleanInputValue(name: String, value: Bool, path: String?) throws {
throw RuntimeError.error(withMessage: "SMI inputs not supported in experimental API")
throw RuntimeError.error(withMessage: "SMI inputs are not supported by the new runtime — use data binding")
}

func getBooleanInputValue(name: String, path: String?) throws -> Bool {
throw RuntimeError.error(withMessage: "SMI inputs not supported in experimental API")
throw RuntimeError.error(withMessage: "SMI inputs are not supported by the new runtime — use data binding")
}

func triggerInput(name: String, path: String?) throws {
throw RuntimeError.error(withMessage: "SMI inputs not supported in experimental API")
throw RuntimeError.error(withMessage: "SMI inputs are not supported by the new runtime — use data binding")
}

func setTextRunValue(name: String, value: String, path: String?) throws {
throw RuntimeError.error(withMessage: "Text runs not supported in experimental API")
throw RuntimeError.error(withMessage: "Text runs are not supported by the new runtime — use data binding")
}

func getTextRunValue(name: String, path: String?) throws -> String {
throw RuntimeError.error(withMessage: "Text runs not supported in experimental API")
throw RuntimeError.error(withMessage: "Text runs are not supported by the new runtime — use data binding")
}

// MARK: - Internal
Expand Down
Loading
Loading