Metadata-Version: 2.4
Name: dash-nle-timeline
Version: 0.0.1
Summary: Purpose-built NLE timeline + scene compositor components for Dash 4 — frame-accurate scrubbing, draggable playhead, snapping, audio waveforms, and a hybrid DOM+Canvas preview scene with a background children slot for any Dash component.
Author-email: Pip Install Python LLC <pipinstallpython@gmail.com>
License: MIT
Project-URL: Homepage, https://github.com/pip-install-python/dash-nle-timeline
Project-URL: Issues, https://github.com/pip-install-python/dash-nle-timeline/issues
Keywords: dash,timeline,nle,video,editor,waveform,plotly
Classifier: Framework :: Dash
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Topic :: Multimedia :: Video
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: dash>=4.1
Dynamic: license-file

<div align="center">

# Dash NLE Timeline

**Non-linear-editor (NLE) timeline & scene compositor components for [Plotly Dash](https://dash.plotly.com).**

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

[![PyPI version](https://img.shields.io/pypi/v/dash-nle-timeline?color=blue)](https://pypi.org/project/dash-nle-timeline/)
[![Python](https://img.shields.io/pypi/pyversions/dash-nle-timeline)](https://pypi.org/project/dash-nle-timeline/)
[![Dash 4.1+](https://img.shields.io/badge/Dash-4.1%2B-1a1a2e?logo=plotly&logoColor=white)](https://dash.plotly.com/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![Discord](https://img.shields.io/badge/Discord-Join-5865F2?logo=discord&logoColor=white)](https://discord.gg/WEnZR35mrK)
[![YouTube](https://img.shields.io/badge/YouTube-%402plotai-FF0000?logo=youtube&logoColor=white)](https://www.youtube.com/channel/UC6Bmo0t0ZUpU_xKBYW0bJuQ)

**[Documentation](https://pip-install-python.com)** · [Discord](https://discord.gg/WEnZR35mrK) · [YouTube](https://www.youtube.com/channel/UC6Bmo0t0ZUpU_xKBYW0bJuQ) · [GitHub](https://github.com/pip-install-python/dash-nle-timeline)

<br/>

_Maintained by **[Pip Install Python LLC](https://pip-install-python.com)**._

</div>

---

## 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

```bash
pip install dash-nle-timeline
```

## Quick Start

```python
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](https://pip-install-python.com)**

You can also run the bundled demo locally:

```bash
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:

```python
@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

```bash
# 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:

- 💬 **Discord** — [discord.gg/WEnZR35mrK](https://discord.gg/WEnZR35mrK)
- ▶️ **YouTube** — [@2plotai](https://www.youtube.com/channel/UC6Bmo0t0ZUpU_xKBYW0bJuQ)
- 🐛 **Issues** — [github.com/pip-install-python/dash-nle-timeline/issues](https://github.com/pip-install-python/dash-nle-timeline/issues)

## 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](https://pip-install-python.com)** | Open-source documentation index for the Python & Dash ecosystem |
| 🔀 **[PiratesBargain.com](https://piratesbargain.com)**     | E-commerce / digital commerce                                   |
| 🧠 **[ai-agent.buzz](https://ai-agent.buzz)**               | Infinite AI canvas                                              |
| 🎬 **[2plot.media](https://2plot.media)**                   | Videography application                                         |

## License

MIT — see [LICENSE](LICENSE). Built by **[Pip Install Python LLC](https://pip-install-python.com)**
to bring a real video-editing timeline into the Dash framework.
