diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index ae85809..406b5b3 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -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 diff --git a/README.md b/README.md index a838879..a33a819 100644 --- a/README.md +++ b/README.md @@ -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 ( + +); +``` + ## Usage ### Component @@ -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 diff --git a/package.json b/package.json index f955c38..82d4ce3 100644 --- a/package.json +++ b/package.json @@ -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" diff --git a/setupTests.ts b/setupTests.ts index 638a0d4..aecc97b 100644 --- a/setupTests.ts +++ b/setupTests.ts @@ -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(), diff --git a/src/components/Rive.tsx b/src/components/Rive.tsx index 38637b0..bf0065b 100644 --- a/src/components/Rive.tsx +++ b/src/components/Rive.tsx @@ -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'; @@ -7,6 +7,7 @@ export type RiveProps = { artboard?: string; animations?: string | string[]; layout?: Layout; + useOffscreenRenderer?: boolean; }; const Rive = ({ @@ -14,6 +15,7 @@ const Rive = ({ artboard, animations, layout, + useOffscreenRenderer = true, ...rest }: RiveProps & ComponentProps<'div'>) => { const params = { @@ -24,7 +26,11 @@ const Rive = ({ autoplay: true, }; - const { RiveComponent } = useRive(params); + const options = { + useOffscreenRenderer, + }; + + const { RiveComponent } = useRive(params, options); return ; }; diff --git a/src/hooks/useRive.tsx b/src/hooks/useRive.tsx index c38d136..264e719 100644 --- a/src/hooks/useRive.tsx +++ b/src/hooks/useRive.tsx @@ -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, @@ -44,6 +44,7 @@ function RiveComponent({ const defaultOptions = { useDevicePixelRatio: true, fitCanvasToArtboardHeight: false, + useOffscreenRenderer: true, }; /** @@ -164,7 +165,12 @@ export default function useRive( const setCanvasRef: RefCallback = 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; diff --git a/src/hooks/useStateMachineInput.ts b/src/hooks/useStateMachineInput.ts index b6212ea..97dfab1 100644 --- a/src/hooks/useStateMachineInput.ts +++ b/src/hooks/useStateMachineInput.ts @@ -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. diff --git a/src/index.ts b/src/index.ts index 28b2951..9f36ca0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -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'; diff --git a/src/types.ts b/src/types.ts index 0290776..931e0af 100644 --- a/src/types.ts +++ b/src/types.ts @@ -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> | null; export type UseRiveOptions = { useDevicePixelRatio: boolean; fitCanvasToArtboardHeight: boolean; + useOffscreenRenderer: boolean; }; export type Dimensions = { diff --git a/test/useRive.test.tsx b/test/useRive.test.tsx index a6ccace..9ce12c0 100644 --- a/test/useRive.test.tsx +++ b/test/useRive.test.tsx @@ -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(),