Skip to main content

Dash NLE Timeline

Non-linear-editor (NLE) timeline & scene compositor components for Plotly Dash.

Frame-accurate scrubbing · draggable playhead · snapping · audio waveforms · trim / split / delete · hybrid DOM + Canvas preview scene · full Dash callback interoperability.

PyPI version Python Dash 4.1+ License: MIT Discord YouTube

Documentation · Discord · YouTube · GitHub


Maintained by Pip Install Python LLC.


Overview

dash-nle-timeline brings a purpose-built video-editor timeline to Plotly Dash. A calendar/scheduler widget thinks in dates; a video editor needs an integer frame grid, a real draggable playhead, snapping to clip edges / markers / grid, audio waveforms, and edits expressed as data. This library is exactly that — written in TypeScript on React 18 and compiled with dash-component-boilerplate, so everything is driven from pure Python.

  • Frame-accurate timeline — integer frames are the canonical unit; seconds are derived from fps
  • Full editing surface — drag to move (cross-track), drag edges to trim/resize, split at the playhead, delete; every edit reported as a single lastEdit event
  • Audio waveforms — painted from precomputed peaks (minmax / magnitude); no audio decoding in the browser
  • Snapping — to clip edges, the playhead, markers, and the frame grid, with a pixel-space threshold for a constant feel at any zoom
  • Playback & transport — rAF playback loop, built-in transport bar with timecode, keyboard shortcuts, and an imperative command prop
  • Scene compositor — a hybrid DOM + Canvas preview (DashNleScene) that renders any Dash component as its background and overlays image/video/text layers with per-layer visibility windows
  • Control plane / media plane split — only small JSON crosses Dash callbacks; your media stays in a <video>, an audio engine, or a server render, driven off the timeline's outputs

The package ships the compiled JS bundle — a normal pip install needs no Node.

Installation

pip install dash-nle-timeline

Quick Start

import dash_nle_timeline as nle
from dash import Dash, Input, Output, callback, html

app = Dash(__name__)

app.layout = html.Div([
    nle.DashNleTimeline(
        id="tl", fps=30, duration=300,
        tracks=[
            {"id": "v1", "kind": "video", "label": "V1"},
            {"id": "a1", "kind": "audio", "label": "A1"},
        ],
        clips=[
            {"id": "c1", "trackId": "v1", "start": 0, "duration": 90, "label": "intro.mp4"},
            {"id": "c2", "trackId": "a1", "start": 0, "duration": 220, "label": "music.wav",
             "peaks": [...], "peaksFormat": "minmax"},
        ],
    ),
    html.Pre(id="out"),
])

@callback(Output("out", "children"), Input("tl", "playhead"))
def show(frame):
    return f"frame {frame}"

if __name__ == "__main__":
    app.run(debug=True)

Edits (move / trim / resize / split / delete) persist on their own — the component applies them to its optimistic clips state and reports each one as a single lastEdit event. Write clips back from a callback only when you want to validate or override.

Documentation

Full documentation, with live examples, lives at the open-source documentation index maintained by Pip Install Python LLC:

📚 pip-install-python.com

You can also run the bundled demo locally:

pip install -r requirements.txt
pip install -e .
python usage.py           # open http://127.0.0.1:8060

usage.py exercises the full surface: scrubbing, selection, move/trim/resize/split/delete, waveforms from precomputed peaks, the imperative command prop, playback, and the scene preview synced to the playhead.

Components

Component What it is
DashNleTimeline Multi-track, frame-accurate NLE timeline: playhead, playback, editing, snapping, waveforms, markers, keyboard shortcuts, and an imperative command channel.
DashNleScene Hybrid DOM + Canvas preview compositor: renders a background (any Dash component and/or a native XYZ tileset) plus overlay image/video/text layers at the current playhead, with a screen-space camera.

Both load from a single bundled JS file — no extra external_scripts, CSS, or React setup.

Wire the two together with a plain callback:

@callback(Output("scene", "playhead"), Input("tl", "playhead"))
def sync(frame):
    return frame

The data boundary

  • Frames are canonical. fps and duration (in frames) define the grid; playhead is an integer frame that round-trips both ways (scrub in the browser, or set it from Python).
  • tracks is a list of dicts — {"id", "kind": "video" | "audio" | "camera", "label", "color"}.
  • clips is a list of dicts — id, trackId, start, duration, plus optional inPoint, label, color, thumbnails, locked, and (audio) peaks / peaksFormat. It is both an input and optimistic round-trip state: user edits persist without any callback.
  • lastEdit (output) reports each user edit as one event — move, trim, resize, split, delete — so Python can validate, override, or mirror it into your own model.
  • selectedClipIds / selectedClipId round-trip; drive selection from Python too.
  • command (input) is the imperative channel — play, pause, seek, splitAtPlayhead, copy, paste, duplicate, selectAll, zoomToFit, … — de-duplicated by id.

DashNleTimeline in depth

  • Time — fps, duration (frames), playhead (round-trips), playing, loop; rAF playback loop with a throttled playhead round-trip.
  • View — pixelsPerSecond (zoom), scrollX (pan); Ctrl/⌘ + wheel zooms anchored at the cursor.
  • Editing — drag to move (cross-track), drag edges to trim/resize, S to split at the playhead, Delete to delete; snapping via snapping / snapThreshold.
  • Waveforms — precomputed peaks painted on a per-lane canvas; formats minmax (interleaved [min0, max0, …]) and magnitude.
  • Markers & keyframes — markers ({"id", "frame", "label", "color"}) on the ruler; camera-keyframe diamonds on camera tracks via cameraKeyframes.
  • Keyboard — the keyboard prop (default on) toggles all shortcuts: Space, arrows (Shift = 1s), S split, Delete, ⌘/Ctrl + C/V/D copy/paste/duplicate, ⌘/Ctrl + A select all, Home/End, + / - zoom.
  • Transport bar — the controls prop (default on): to-start / step / play-pause / step + timecode above the ruler.
  • Theming — theme="dark" / "light", plus style / className passthrough.

API reference

DashNleTimeline props (selected)

Prop Type Description
fps / duration int Frame rate and total length in frames — the canonical time grid
playhead int Current frame — input and output
playing / loop bool Playback state (rAF loop inside the component)
tracks list Track dicts (video / audio / camera)
clips list Clip dicts — input and optimistic round-trip state
lastEdit output The most recent user edit as a single event
selectedClipIds / selectedClipId list / str Selection — round-trips both ways
markers list Ruler markers {"id", "frame", "label", "color"}
cameraKeyframes list Keyframe diamonds rendered on camera tracks
snapping / snapThreshold bool / int Snap to edges / playhead / markers / grid; pixel-space threshold
pixelsPerSecond / scrollX number Zoom and horizontal pan
command dict Imperative channel (seek, togglePlay, zoomToFit, …), de-duped by id
keyboard / controls bool Toggle shortcuts / the built-in transport bar
theme / style / className — Appearance and sizing

DashNleScene props (selected)

Prop Type Description
playhead int Frame to render — drive it from the timeline
resolution list Design-space [width, height] of the scene
children Dash components Background slot — a map, a plot, a video feed, anything
tileset dict Native XYZ tile background
layers list Overlay layers (image / video / text) with [start, end) visibility windows
camera dict Screen-space camera (pan / zoom over the scene)

The full prop tables are generated into dash_nle_timeline/DashNleTimeline.py and dash_nle_timeline/DashNleScene.py docstrings by dash-generate-components.

Development

# Install dependencies
npm install                  # TypeScript + webpack toolchain
pip install -r requirements.txt

# Build the JS bundle + regenerate the Python wrappers
npm run build                # webpack UMD bundle + dash-generate-components → dash_nle_timeline/*.py
npm run watch                # JS-only rebuild loop (when prop signatures don't change)

# Standalone smoke test
python usage.py              # http://127.0.0.1:8060

# Build a distribution
python -m build
  • TypeScript source of truth: src/ts/ — components/ holds the two public components, internal/ the subcomponents, and time.ts / snap.ts / waveform.ts / edits.ts / tiles.ts are pure helpers.
  • The built bundle and generated wrappers are committed, so pip install -e . works without npm.
  • dash_nle_timeline/__init__.py is hand-maintained (it registers the UMD bundle) — dash-generate-components does not regenerate it.
  • Keep the version in package.json and pyproject.toml in sync when cutting a release.

Requirements

  • Python >= 3.8
  • Dash >= 4.1
  • Node.js >= 16 (for development / rebuilding the JS bundle only)

Community & support

Come build with us:

More from Pip Install Python LLC

dash-nle-timeline is one of several tools built and maintained by Pip Install Python LLC:

Project What it is
📚 Pip Install Python Open-source documentation index for the Python & Dash ecosystem
🔀 PiratesBargain.com E-commerce / digital commerce
🧠 ai-agent.buzz Infinite AI canvas
🎬 2plot.media Videography application

License

MIT — see LICENSE. Built by Pip Install Python LLC to bring a real video-editing timeline into the Dash framework.

Metadata

Release files for dash-nle-timeline 0.0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for dash-nle-timeline 0.0.1
File Size Uploaded Provenance Actions
dash_nle_timeline-0.0.1.tar.gz 173.3 kB Without provenance Details for dash_nle_timeline-0.0.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for dash-nle-timeline 0.0.1
File Interpreter ABI Platform Actions
dash_nle_timeline-0.0.1-py3-none-any.whl Python 3 none any Details for dash_nle_timeline-0.0.1-py3-none-any.whl

Total release size: 350.2 kB

Release files / dash_nle_timeline-0.0.1.tar.gz

Download URL dash_nle_timeline-0.0.1.tar.gz
Size 173.3 kB
Tags Source
SHA-256 checksum
How to use checksums
abe016e696595d03da6e12688948a79d56a8e9d46bb24da44055f9fe3a3347da
BLAKE2b-256 checksum
How to use checksums
eed3890ed339b7380a4273810014d7bd6eced7a36bde90dba43bec3ba7ecdba2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.3

Release files / dash_nle_timeline-0.0.1-py3-none-any.whl

Download URL dash_nle_timeline-0.0.1-py3-none-any.whl
Size 177.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
32606a542012bc613b24af34071f58e8b5c5ebbd583718a52104d13c83b6e455
BLAKE2b-256 checksum
How to use checksums
1be6b115dcf703cff6e799628c0e22c8da2f7f63430437a5a9a18b80f51abbcc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.3

Security for dash-nle-timeline 0.0.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.0.1 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page