Skip to content

Commit

Permalink
Breaking: Switch from using the canvas renderer as default to the web…
Browse files Browse the repository at this point in the history
…gl renderer
  • Loading branch information
zplata committed Mar 23, 2022
1 parent 0be3bc7 commit 1e1cabd
Show file tree
Hide file tree
Showing 10 changed files with 49 additions and 21 deletions.
10 changes: 0 additions & 10 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,3 @@ jobs:
run: npm test
- name: Build
run: npm run build
- name: Git config
run: |
git config --local user.email 'hello@rive.app'
git config --local user.name ${{ github.actor }}
- name: Authenticate with registry
run: npm config set //registry.npmjs.org/:_authToken ${{ secrets.NPM_TOKEN }}
- name: Release
env:
GITHUB_TOKEN: ${{ secrets.REPO_TOKEN }}
run: npm run release
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,30 @@ npm i --save rive-react

_Note: This library is using React hooks so the minimum version required for both react and react-dom is 16.8.0._

### Migrating from v 0.0.x to 1.x.x

Starting in v 1.0.0, we've migrated from wrapping around the `@rive-app/canvas` runtime (which uses the `CanvasRendereringContext2D` renderer) to the `@rive-app/webgl` runtime (which uses the WebGL renderer). The high-level API doesn't require any change to upgrade, but there are some notes to consider about the backing renderer.

The backing `WebGL` runtime allows for best performance across all devices, as well as support for some features that are not supported in the `canvas` renderer runtime. To allow the `react` runtime to support some of the newer features in Rive, we needed to switch the `rive-react` backing runtime to `@rive-app/webgl`.

One note about this switch is that some browsers may limit the number of concurrent WebGL contexts. For example, Chrome may only support up to 16 contexts concurrently. We pass a property called `useOffscreenRenderer` set to true to the backing runtime when instantiating Rive by default, which helps to manage the lifecycle of the `canvas` with a single offscreen `WebGL` context, even if there are many Rive animations on the screen (i.e 16+). If you need a single `WebGL` context per Rive animation/instance, pass in the `useOffscreenRenderer` property set to `false` in the `useRive` options, or as a prop in the default export component from this runtime. See below for an example:

```js
const {rive, RiveComponent} = useRive({
src: 'foo.riv',
}, {
// Default (you don't need to set this)
useOffscreenRenderer: true,
// To override and use one context per Rive instance, uncomment and use the line below
// useOffscreenRenderer: false,
});

// or you can override the flag in JSX via props
return (
<Rive src="foo.riv" useOffscreenRenderer={false} />
);
```

## Usage

### Component
Expand Down Expand Up @@ -106,6 +130,7 @@ export default Example;

- `useDevicePixelRatio`: _(optional)_ If `true`, the hook will scale the resolution of the animation based the [devicePixelRatio](https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio). Defaults to `true`. NOTE: Requires the `setContainerRef` ref callback to be passed to a element wrapping a canvas element. If you use the `RiveComponent`, then this will happen automatically.
- `fitCanvasToArtboardHeight`: _(optional)_ If `true`, then the canvas will resize based on the height of the artboard. Defaults to `false`.
- `useOffscreenRenderer`: _(optional)_ If `true`, the Rive instance will share (or create if one does not exist) an offscreen `WebGL` context. This allows you to display multiple Rive animations on one screen to work around some browser limitations regarding multiple concurrent WebGL contexts. If `false`, each Rive instance will have its own dedicated `WebGL` context, and you may need to be cautious of the browser limitations just mentioned. Defaults to `true`.

### useStateMachineInput Hook

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
},
"homepage": "https://github.com/rive-app/rive-react#readme",
"dependencies": {
"@rive-app/canvas": "1.0.18"
"@rive-app/webgl": "1.0.25"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0"
Expand Down
2 changes: 1 addition & 1 deletion setupTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ window.IntersectionObserver = class IntersectionObserver {
unobserve() {}
};

jest.mock('@rive-app/canvas', () => ({
jest.mock('@rive-app/webgl', () => ({
Rive: jest.fn().mockImplementation(() => ({
on: jest.fn(),
stop: jest.fn(),
Expand Down
10 changes: 8 additions & 2 deletions src/components/Rive.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Layout } from '@rive-app/canvas';
import { Layout } from '@rive-app/webgl';
import React, { ComponentProps } from 'react';
import useRive from '../hooks/useRive';

Expand All @@ -7,13 +7,15 @@ export type RiveProps = {
artboard?: string;
animations?: string | string[];
layout?: Layout;
useOffscreenRenderer?: boolean;
};

const Rive = ({
src,
artboard,
animations,
layout,
useOffscreenRenderer = true,
...rest
}: RiveProps & ComponentProps<'div'>) => {
const params = {
Expand All @@ -24,7 +26,11 @@ const Rive = ({
autoplay: true,
};

const { RiveComponent } = useRive(params);
const options = {
useOffscreenRenderer,
};

const { RiveComponent } = useRive(params, options);
return <RiveComponent {...rest} />;
};

Expand Down
10 changes: 8 additions & 2 deletions src/hooks/useRive.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import React, {
ComponentProps,
RefCallback,
} from 'react';
import { Rive, EventType } from '@rive-app/canvas';
import { Rive, EventType } from '@rive-app/webgl';
import {
UseRiveParameters,
UseRiveOptions,
Expand Down Expand Up @@ -44,6 +44,7 @@ function RiveComponent({
const defaultOptions = {
useDevicePixelRatio: true,
fitCanvasToArtboardHeight: false,
useOffscreenRenderer: true,
};

/**
Expand Down Expand Up @@ -164,7 +165,12 @@ export default function useRive(
const setCanvasRef: RefCallback<HTMLCanvasElement> = useCallback(
(canvas: HTMLCanvasElement | null) => {
if (canvas && riveParams) {
const r = new Rive({ ...riveParams, canvas });
const {useOffscreenRenderer} = options;
const r = new Rive({
useOffscreenRenderer,
...riveParams,
canvas,
});
r.on(EventType.Load, () => setRive(r));
} else if (canvas === null && canvasRef.current) {
canvasRef.current.height = 0;
Expand Down
2 changes: 1 addition & 1 deletion src/hooks/useStateMachineInput.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useState, useEffect } from 'react';
import { Rive, StateMachineInput } from '@rive-app/canvas';
import { Rive, StateMachineInput } from '@rive-app/webgl';

/**
* Custom hook for fetching a stateMachine input from a rive file.
Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ import useStateMachineInput from './hooks/useStateMachineInput';
export default Rive;
export { useRive, useStateMachineInput };
export { RiveState, UseRiveParameters, UseRiveOptions } from './types';
export * from '@rive-app/canvas';
export * from '@rive-app/webgl';
3 changes: 2 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { RefCallback, ComponentProps } from 'react';
import { Rive, RiveParameters } from '@rive-app/canvas';
import { Rive, RiveParameters } from '@rive-app/webgl';

export type UseRiveParameters = Partial<Omit<RiveParameters, 'canvas'>> | null;

export type UseRiveOptions = {
useDevicePixelRatio: boolean;
fitCanvasToArtboardHeight: boolean;
useOffscreenRenderer: boolean;
};

export type Dimensions = {
Expand Down
4 changes: 2 additions & 2 deletions test/useRive.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import { renderHook, act } from '@testing-library/react-hooks';
import { mocked } from 'jest-mock';

import useRive from '../src/hooks/useRive';
import * as rive from '@rive-app/canvas';
import * as rive from '@rive-app/webgl';

jest.mock('@rive-app/canvas', () => ({
jest.mock('@rive-app/webgl', () => ({
Rive: jest.fn().mockImplementation(() => ({
on: jest.fn(),
stop: jest.fn(),
Expand Down

0 comments on commit 1e1cabd

Please sign in to comment.