Skip to main content

@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.

warning

Experimental API: This package is not stable. Its public API may change without a major version bump.

Installation

npx remotion add @remotion/canvas

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.tsx
import { 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.

APIs

License

Remotion License