<ThreeCanvas>
A wrapper for React Three Fiber's <Canvas /> which synchronizes with Remotions useCurrentFrame().
Since React Three Fiber is a custom renderer, normally the React contexts that surround it don't work inside. This would normally break the usage of it in Remotion, but this component wraps the contexts so you can write your markup as expected.
Instead of using React Three Fibers useFrame API, you can (and must) write your animations fully declaratively using Remotions useCurrentFrame API. This will ensure that you can scrub back and forth in the timeline and pause the animation.
A browser bug would normally cause the layout to be broken because we apply a scale transform to the canvas in the Studio. To work around this problem, the <ThreeCanvas /> requires the width and height props to be set.
Example
A spinning, color changing, scaling cube. This example can also be found in the examples folder of the Remotion repo.
tsximport {ThreeCanvas } from '@remotion/three';import {interpolate ,useCurrentFrame ,useVideoConfig } from 'remotion';constThreeBasic :React .FC = () => {constframe =useCurrentFrame ();const {width ,height } =useVideoConfig ();return (<ThreeCanvas orthographic ={false}width ={width }height ={height }style ={{backgroundColor : 'white',}}camera ={{fov : 75,position : [0, 0, 470]}}><ambientLight intensity ={0.15} /><pointLight args ={[undefined , 0.4]}position ={[200, 200, 0]} /><mesh position ={[0, 0, 0]}rotation ={[frame * 0.06 * 0.5,frame * 0.07 * 0.5,frame * 0.08 * 0.5]}scale ={interpolate (Math .sin (frame / 10), [-1, 1], [0.8, 1.2])}><boxGeometry args ={[100, 100, 100]} /><meshStandardMaterial color ={[Math .sin (frame * 0.12) * 0.5 + 0.5,Math .cos (frame * 0.11) * 0.5 + 0.5,Math .sin (frame * 0.08) * 0.5 + 0.5]} /></mesh ></ThreeCanvas >);};export defaultThreeBasic ;
frameloop behavior during rendering
During rendering, <ThreeCanvas> overrides the frameloop prop to 'never' regardless of what you pass. This means the Three.js scene will not re-render on its own — it is only re-rendered on demand via advance().
If you update textures asynchronously (e.g. from a <Video> onVideoFrame callback), you must call advance(performance.now()) instead of invalidate() to synchronously re-render the scene before the frame is captured. See Using a video as a texture for a full example.
Note on <Sequence>
A <Sequence> by default will return a <div> component which is not allowed inside a <ThreeCanvas>. To avoid an error, pass layout="none" to <Sequence>.
Using videos inside a <ThreeCanvas>
You can create a Three.js texture backed by a <Video> by using this approach.