Open Source Editor EngineAlpha

A Canvas-Based React Timeline Editor

A high-performance modular framework combining headless state, React interaction layers, and a 60fps canvas renderer. Build professional video, audio, or animation timelines that stay butter smooth under any workload.

interactive-editor-showcase.tsx
Live Demo

Built for Professional Grade Editing

Engineered to overcome web rendering bottlenecks, keeping interaction physics snappy and rendering layouts precise.

Canvas Rendering Engine

Drawn using a 2D HTML5 canvas context in a background worker. Keeps the main DOM tree completely flat, bypassing reflow paint storms during scrubbing, zooming, and playback.

Frame-Accurate Edits

Native implementation of linear track layouts, spatial search indexes, snapping lines, in/out marker ranges, and professional slip/slide/trim calculations.

React Or Your Own UI Surface

Use our pre-bundled React hooks, provider states, and delegated hit-testing interaction layers, or write custom CSS/DOM interfaces around the headless engine core.

Modular & Lightweight

A monorepo structure separating state logic, React bindings, canvas drawing pipeline, and math utilities. Import only the sub-packages your application requires.

Designed for Developers

Get up and running in minutes. Simply construct a timeline engine, wrap your application in the provider context, and drop in ready-made canvas renderers and drag interaction nodes.

pnpm add @techsquidtv/canvas-timeline
App.tsx
import {
CanvasRenderer,
Timeline,
TimelineEngine,
TimelineProvider,
fromSeconds,
type Track,
} from '@techsquidtv/canvas-timeline';
import '@techsquidtv/canvas-timeline/styles.css';
import { useMemo } from 'react';
const tracks: Track[] = [
32 collapsed lines
{
id: 'video',
kind: 'visual',
name: 'Video',
height: 48,
clips: [
{
id: 'intro',
sourceId: 'intro.mov',
timelineStart: fromSeconds(1),
timelineEnd: fromSeconds(5.5),
sourceStart: fromSeconds(0),
label: 'Intro',
},
],
},
{
id: 'audio',
kind: 'audio',
name: 'Audio',
height: 48,
clips: [
{
id: 'score',
sourceId: 'score.wav',
timelineStart: fromSeconds(0),
timelineEnd: fromSeconds(15),
sourceStart: fromSeconds(0),
label: 'Score',
},
],
},
];
function App() {
const engine = useMemo(
() =>
new TimelineEngine({
duration: fromSeconds(15),
playheadTime: fromSeconds(2),
tracks,
}),
[]
);
return (
<TimelineProvider engine={engine}>
<div className="timeline-shell">
<div className="timeline-stage">
<Timeline.Root className="timeline-fill">
<CanvasRenderer />
<Timeline.PlayheadArea />
<Timeline.PlayheadGrabber />
<Timeline.ClipInteractionLayer />
</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>
);
}