@remotion/canvasv4.0.527
Build a composition preview and layer list for a Remotion authoring interface. The package combines <Player> playback with registered sequence data, selection, and synchronized hover.
Experimental API: This package is not stable. Its public API may change without a major version bump.
Installation
- Remotion CLI
- npm
- bun
- pnpm
- yarn
npx remotion add @remotion/canvas
This assumes you are currently using v4.0.527 of Remotion.npm i --save-exact @remotion/[email protected]
Also update
remotion and all `@remotion/*` packages to the same version.Remove all
^ character in front of the version numbers of it as it can lead to a version conflict.This assumes you are currently using v4.0.527 of Remotion.pnpm i @remotion/[email protected]
Also update
remotion and all `@remotion/*` packages to the same version.Remove all
^ character in front of the version numbers of it as it can lead to a version conflict.This assumes you are currently using v4.0.527 of Remotion.bun i @remotion/[email protected]
Also update
remotion and all `@remotion/*` packages to the same version.Remove all
^ character in front of the version numbers of it as it can lead to a version conflict.This assumes you are currently using v4.0.527 of Remotion.yarn --exact add @remotion/[email protected]
Also update
remotion and all `@remotion/*` packages to the same version.Remove all
^ character in front of the version numbers of it as it can lead to a version conflict.Install @remotion/player as well. Keep the Remotion packages on the same version.
Basic example
Pass the same controller to <Canvas> and your layer list. showOutlines enables hover and selection on the composition.
Editor.tsximport { Canvas, getCanvasSelectionItemKey, getCanvasSequenceNodePathInfo, useCanvasController, useCanvasSelection, useCanvasSequenceHover, type CanvasSelectionItem, type TimelineTrackData, } from '@remotion/canvas'; import {useSyncExternalStore} from 'react'; import {Video} from './Video'; const Layer = ({ track, controller, items, selectedKeys, }: { track: TimelineTrackData; controller: ReturnType<typeof useCanvasController>; items: CanvasSelectionItem[]; selectedKeys: Set<string>; }) => { const nodePathInfo = getCanvasSequenceNodePathInfo(track); const item: CanvasSelectionItem = {type: 'sequence', nodePathInfo}; const key = getCanvasSelectionItemKey(item); const {hovered, onPointerEnter, onPointerLeave} = useCanvasSequenceHover( controller.hover, nodePathInfo, 'timeline', ); return ( <button aria-pressed={selectedKeys.has(key)} onPointerEnter={onPointerEnter} onPointerLeave={onPointerLeave} onClick={(event) => controller.selection.select( item, {shiftKey: event.shiftKey, toggleKey: event.metaKey || event.ctrlKey}, items, )} > {hovered ? '● ' : ''}{track.sequence.displayName ?? track.sequence.type} </button> ); }; export const Editor = () => { const controller = useCanvasController(); const tracks = useSyncExternalStore( controller.timeline.subscribe, controller.timeline.getSnapshot, controller.timeline.getSnapshot, ); const selection = useCanvasSelection(controller.selection); const items: CanvasSelectionItem[] = tracks.map((track) => ({ type: 'sequence', nodePathInfo: getCanvasSequenceNodePathInfo(track), })); const selectedKeys = new Set(selection.selectedItems.map(getCanvasSelectionItemKey)); return ( <> <Canvas controller={controller} showOutlines component={Video} compositionWidth={1920} compositionHeight={1080} durationInFrames={150} fps={30} /> <div> {tracks.map((track) => ( <Layer key={track.sequence.id} track={track} controller={controller} items={items} selectedKeys={selectedKeys} /> ))} </div> </> ); };
The timeline contains registered <Sequence> and other sequence tracks from the mounted composition. The Canvas does not edit source files or provide timeline controls; your interface owns those actions.
Selection identity
The built-in getCanvasSequenceNodePathInfo() uses a source identity when available. Otherwise it falls back to a mounted sequence ID, which can change after a remount. If your editor tracks source nodes, pass a custom resolveSequenceNodePathInfo to <Canvas> and use the same resolver for layer items. Return null for tracks that should not be selectable.
An outline requires a registered DOM element. A <Sequence layout="none"> has no outline of its own.