Live demo
Code example
import { TimelineEngine, TimelineProvider, Timeline, useTimeline, CanvasRenderer, fromSeconds,} from '@techsquidtv/canvas-timeline';import { useMemo } from 'react';import { demoMarkers, demoTracks } from './timeline-demo-data';import '@techsquidtv/canvas-timeline/styles.css';
function TimelineLayers() { const { state } = useTimeline();
return ( <> <Timeline.PlayheadArea /> <Timeline.PlayheadGrabber /> <Timeline.TrackList className="timeline-track-list-overlay"> {state.tracks.map((track) => ( <Timeline.Track key={track.id} trackId={track.id} /> ))} </Timeline.TrackList> <Timeline.ClipInteractionLayer /> <Timeline.RangeSelector /> </> );}
export function BasicTimeline() { const engine = useMemo( () => new TimelineEngine({ duration: fromSeconds(15), playheadTime: fromSeconds(2), zoomScale: 74, tracks: demoTracks, markers: demoMarkers, }), [] );
return ( <TimelineProvider engine={engine}> <div className="timeline-shell"> <div className="timeline-stage"> <Timeline.Root className="timeline-fill"> <CanvasRenderer /> <TimelineLayers /> </Timeline.Root> </div> <div className="timeline-scrollbar-row"> <Timeline.ViewportScrollbar> <Timeline.ViewportScrollbarThumb> <Timeline.ViewportScrollbarHandle side="start" /> <Timeline.ViewportScrollbarHandle side="end" /> </Timeline.ViewportScrollbarThumb> </Timeline.ViewportScrollbar> </div> </div> </TimelineProvider> );}const demoClipColors = [ 'oklch(0.62 0.16 250)', 'oklch(0.68 0.14 145)', 'oklch(0.72 0.16 70)', 'oklch(0.65 0.17 25)', 'oklch(0.58 0.18 305)', 'oklch(0.64 0.12 195)',] as const;
export function getDemoClipColor(index: number) { return demoClipColors[index % demoClipColors.length];}import { type Marker, type Track, fromSeconds } from '@techsquidtv/canvas-timeline';import { getDemoClipColor } from '../demo-clip-colors';
export const demoTracks: Track<'visual' | 'audio'>[] = [ { id: 'video-a', kind: 'visual', name: 'Video A', locked: false, muted: false, visible: true, selected: false, height: 48, clips: [ { id: 'intro', sourceId: 'vid-intro', timelineStart: fromSeconds(1), timelineEnd: fromSeconds(5.5), sourceStart: fromSeconds(0), selected: false, color: getDemoClipColor(0), label: 'Intro sequence', }, { id: 'main', sourceId: 'vid-main', timelineStart: fromSeconds(6.5), timelineEnd: fromSeconds(12.5), sourceStart: fromSeconds(0), selected: false, color: getDemoClipColor(1), label: 'Main feature clip', }, ], }, { id: 'overlay-b', kind: 'visual', name: 'Overlay B', locked: false, muted: false, visible: true, selected: false, height: 48, clips: [ { id: 'b-roll', sourceId: 'vid-overlay', timelineStart: fromSeconds(3), timelineEnd: fromSeconds(8.5), sourceStart: fromSeconds(0), selected: false, color: getDemoClipColor(2), label: 'B-roll overlay', }, ], }, { id: 'audio-a', kind: 'audio', name: 'Ambient Soundtrack', locked: false, muted: false, visible: true, selected: false, height: 48, clips: [ { id: 'score', sourceId: 'aud-score', timelineStart: fromSeconds(0), timelineEnd: fromSeconds(15), sourceStart: fromSeconds(0), selected: false, color: getDemoClipColor(3), label: 'Background score', }, ], },];
export const demoMarkers: Marker[] = [ { id: 'm1', time: fromSeconds(1), label: 'M1' }, { id: 'm2', time: fromSeconds(6.5), label: 'M2' },];