Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .changeset/add-phase-1-complete.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
"@timeline/core": minor
"@timeline/react": minor
"@timeline/ui": minor
"@webpacked-timeline/core": minor
"@webpacked-timeline/react": minor
"@webpacked-timeline/ui": minor
---

Phase 1 complete: headless NLE engine core with transaction-based dispatcher, snap index, ITool contract, ProvisionalState ghost layer, React hooks with selector isolation, and rAF-throttled tool router.
4 changes: 2 additions & 2 deletions .changeset/add-phase-2-tools.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
"@timeline/core": minor
"@timeline/react": minor
"@webpacked-timeline/core": minor
"@webpacked-timeline/react": minor
---

Phase 2 complete: 8 core editing tools (SelectionTool, RazorTool, RippleTrimTool, RollTrimTool, SlipTool, RippleDeleteTool, RippleInsertTool, HandTool). Rolling-state dispatcher validation. MOVE_CLIP ordering rule. ProvisionalState rubber-band extension.
2 changes: 1 addition & 1 deletion .changeset/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"commit": false,
"fixed": [],
"linked": [
["@timeline/core", "@timeline/react", "@timeline/ui"]
["@webpacked-timeline/core", "@webpacked-timeline/react", "@webpacked-timeline/ui"]
],
"access": "public",
"baseBranch": "main",
Expand Down
6 changes: 3 additions & 3 deletions .changeset/phase-3-complete.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
"@timeline/core": minor
"@timeline/react": minor
"@timeline/ui": minor
"@webpacked-timeline/core": minor
"@webpacked-timeline/react": minor
"@webpacked-timeline/ui": minor
---

Phase 3 complete: Markers, in/out points, beat grid, generators, captions, SRT/VTT import. Marker search API. Caption model completeness (EDIT_CAPTION partial updates, overlap invariant).
6 changes: 3 additions & 3 deletions .changeset/phase-4-complete.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
"@timeline/core": minor
"@timeline/react": minor
"@timeline/ui": minor
"@webpacked-timeline/core": minor
"@webpacked-timeline/react": minor
"@webpacked-timeline/ui": minor
---

Phase 4: Effects, keyframes, transitions, track groups, link groups, and two new tools (TransitionTool, KeyframeTool).
4 changes: 2 additions & 2 deletions .changeset/phase-6-complete.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
"@timeline/core": minor
"@timeline/react": minor
"@webpacked-timeline/core": minor
"@webpacked-timeline/react": minor
---

Phase 6: Playback engine — PlayheadController, pipeline contracts, seek API, J/K/L keyboard, loop regions, usePlayhead hook.
2 changes: 1 addition & 1 deletion .changeset/phase-7-complete.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
"@timeline/core": minor
"@webpacked-timeline/core": minor
---

Phase 7: Performance and scale — interval tree, virtual rendering, transaction compression, history persistence, worker contracts, SlideTool, ZoomTool. Feature complete.
6 changes: 6 additions & 0 deletions .changeset/phase-r-complete.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@webpacked-timeline/react": minor
"@webpacked-timeline/core": patch
---

Phase R: @webpacked-timeline/react complete — TimelineEngine orchestrator, 13 hooks with selector isolation, ToolRouter with rAF throttle, virtual rendering hooks, full integration test suite.
5 changes: 5 additions & 0 deletions .changeset/phase-u-complete.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@webpacked-timeline/ui": minor
---

Phase U: @webpacked-timeline/ui complete — shadcn-style CLI, 16 components across 5 tiers, 2 themes, shared utilities, full rendering contract. Feature complete.
6 changes: 3 additions & 3 deletions .claude/skills/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@

```
packages/core → imports nothing outside core stdlib + TypeScript
packages/react → imports @timeline/core + React only
packages/ui → imports @timeline/react + @timeline/core + React only
packages/react → imports @webpacked-timeline/core + React only
packages/ui → imports @webpacked-timeline/react + @webpacked-timeline/core + React only
```

Lower layers NEVER import from higher layers. A `packages/core` file that imports
`React`, `ReactDOM`, `requestAnimationFrame`, `document`, or anything from
`@timeline/react` or `@timeline/ui` is **categorically wrong** — reject it.
`@webpacked-timeline/react` or `@webpacked-timeline/ui` is **categorically wrong** — reject it.

## Rule 2 — One Entry Point for Mutation

Expand Down
6 changes: 3 additions & 3 deletions .claude/skills/adapter/HOOKS.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,13 @@ function useClip(id: ClipId) {

---

## Hooks Never Import from @timeline/core Directly
## Hooks Never Import from @webpacked-timeline/core Directly

All calls go through the `TimelineEngine` adapter class. Hooks never call `dispatch()` directly.

```typescript
// ❌
import { dispatch } from "@timeline/core";
import { dispatch } from "@webpacked-timeline/core";

// ✅
const { engine } = useTimelineContext();
Expand Down Expand Up @@ -167,6 +167,6 @@ function ClipShell({ id }: { id: ClipId }) {

## Common mistakes to avoid

- Importing `dispatch` from `@timeline/core` inside a hook — always call `engine.dispatch()`
- Importing `dispatch` from `@webpacked-timeline/core` inside a hook — always call `engine.dispatch()`
- Using `useEffect` + `useState` to mirror engine state — use `useSyncExternalStore` always
- Subscribing to `engine.getState` (entire state snapshot) — always write a scoped selector
6 changes: 3 additions & 3 deletions .claude/skills/tools/ITOOL_CONTRACT.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ import type {
TimelinePointerEvent,
TimelineKeyEvent,
ProvisionalState,
} from "@timeline/core";
} from "@webpacked-timeline/core";

class NoOpTool implements ITool {
readonly id = "no-op" as ToolId;
Expand Down Expand Up @@ -186,7 +186,7 @@ Use `NoOpTool` as a base for unit tests that need an `ITool` but don't care abou

```typescript
import { describe, it, expect } from "vitest";
import { dispatch } from "@timeline/core";
import { dispatch } from "@webpacked-timeline/core";

it("MoveTool produces correct MOVE_CLIP transaction", () => {
const tool = new MoveTool();
Expand Down Expand Up @@ -399,7 +399,7 @@ packages/react/src/tests/
```

Unit tests live in core. Integration tests live in react.
A tool test that imports anything from `@timeline/react` is wrong.
A tool test that imports anything from `@webpacked-timeline/react` is wrong.

---

Expand Down
10 changes: 5 additions & 5 deletions .claude/skills/ui/COMPONENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,18 @@

---

# COMPONENTS — @timeline/ui Rules
# COMPONENTS — @webpacked-timeline/ui Rules

## Critical Rule

**No component imports from `@timeline/core` directly.** No component calls `dispatch()` directly. State flows in through hooks only.
**No component imports from `@webpacked-timeline/core` directly.** No component calls `dispatch()` directly. State flows in through hooks only.

```typescript
// ❌ WRONG
import { dispatch, findClipById } from "@timeline/core";
import { dispatch, findClipById } from "@webpacked-timeline/core";

// ✅ CORRECT
import { useClip, useTimeline } from "@timeline/react";
import { useClip, useTimeline } from "@webpacked-timeline/react";
```

---
Expand Down Expand Up @@ -102,7 +102,7 @@ function TrackRow({ id }: { id: TrackId }) {

## What Components Do NOT Do

- ❌ Import from `@timeline/core` directly
- ❌ Import from `@webpacked-timeline/core` directly
- ❌ Call `dispatch()` directly
- ❌ Implement drag logic (that belongs in `packages/react/tools/`)
- ❌ Keep a `useState` copy of clip data
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ jobs:
- run: pnpm install --frozen-lockfile

- name: Type check
run: pnpm --filter @timeline/core exec tsc --noEmit
run: pnpm --filter @webpacked-timeline/core exec tsc --noEmit

- name: Test
run: pnpm --filter @timeline/core test --run
run: pnpm --filter @webpacked-timeline/core test --run

- name: Build
run: pnpm --filter @timeline/core build
run: pnpm --filter @webpacked-timeline/core build
144 changes: 138 additions & 6 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ _No unreleased changes._

## [0.0.1] — Phase 0 Complete

### @timeline/core
### @webpacked-timeline/core

#### Added
- FrameRate discriminated union
Expand All @@ -31,7 +31,7 @@ _No unreleased changes._

## [0.1.0] — Phase 1 Complete

### @timeline/core
### @webpacked-timeline/core

#### Added
- Tool scaffolding: ITool interface, ToolContext, ToolRegistry
Expand All @@ -44,7 +44,7 @@ _No unreleased changes._

## [0.2.0] — Phase 2 Complete

### @timeline/core
### @webpacked-timeline/core

#### Added
- SelectionTool (click, drag, multi-drag, rubber-band)
Expand All @@ -65,7 +65,7 @@ _No unreleased changes._

## [0.3.0] — Phase 3 Complete — February 27, 2025

### @timeline/core
### @webpacked-timeline/core

#### Added

Expand Down Expand Up @@ -140,6 +140,138 @@ _No unreleased changes._

---

## [0.8.0] — Phase U Complete — February 27, 2025

### Added (@webpacked-timeline/ui)

**CLI**
- `npx @webpacked-timeline/ui add <component>` — copies
components into your project
- `npx @webpacked-timeline/ui add --preset=<name>` —
install curated bundles
- `npx @webpacked-timeline/ui list` — show all components
with install status
- `npx @webpacked-timeline/ui diff <component>` —
show changes vs registry
- `npx @webpacked-timeline/ui update <component>` —
update with diff preview + confirmation
- Theme install: `add theme --theme=dark-pro`
- Manifest tracking: `.timeline-ui.json`
- Registry dependency resolution (topological)

**Theme system**
- `dark-pro` theme (DaVinci-inspired default)
- `light` theme (Final Cut Pro-inspired)
- 45+ CSS custom property tokens
- Token naming: `--tl-{component}-{property}-{state}`

**Shared utilities** (copied into _shared/)
- `time.ts` — frameToPx, pxToFrame,
frameToTimecode, rulerTickInterval
- `geometry.ts` — Rect, clamp, normalizeRect,
rectsOverlap
- `use-drag.ts` — useDrag() hook with threshold
- `use-snap.ts` — useSnap() hook via engine

**Components**

Tier 1 — Core:
timeline-root, track, clip, playhead, ruler

Tier 2 — Editing:
toolbar, zoom-bar

Tier 3 — Media:
waveform (canvas), thumbnail-strip, clip-label

Tier 4 — Advanced:
effect-lane, keyframe-diamond,
transition-handle

Tier 5 — Markers:
marker-pin, marker-range, in-out-handles

**Rendering contract**
- All components read engine via TimelineProvider
- Zero hardcoded colors (CSS vars only)
- Render prop escape hatches on all content
components
- No local useState for canonical engine values
- All mutations via engine.dispatch() only

### Tests
- 113 UI tests (CLI + components)
- 1152+ total tests across monorepo
- Registry integrity: all registered files
verified to exist

---

## [0.7.0] — Phase R Complete — February 27, 2025

### Added (@webpacked-timeline/react)

**TimelineEngine**
- Full orchestrator wiring Dispatcher,
PlaybackEngine, ToolRouter, SnapIndexManager,
TrackIndex, HistoryStack, KeyboardHandler
- `TimelineEngineOptions`: pipeline, clock,
historyLimit, compression, tools, callbacks
- `EngineSnapshot`: state, provisional, playhead,
history, trackIds, cursor, change
- `DEFAULT_PLAYHEAD_STATE` for edit-only mode
- Playback events wired to snapshot rebuild
(usePlayheadFrame updates every rAF tick)
- `handlePointerLeave` with Option Y pattern
- `undo()` / `redo()` with full state sync

**Hooks (13 total)**
- `useTimeline(engine)` — timeline metadata
- `useTrackIds(engine)` — stable track list
- `useTrack(engine, id)` — single track
- `useClip(engine, id)` — single clip,
provisional-first lookup
- `useClips(engine, trackId)` — track clips
- `useMarkers(engine)` — timeline markers
- `useHistory(engine)` — canUndo/canRedo,
stable object reference
- `useActiveToolId(engine)` — active tool
- `useCursor(engine)` — CSS cursor string
- `useProvisional(engine)` — ghost clip state
- `usePlayheadFrame(engine)` — current frame,
updates every rAF tick during playback
- `useIsPlaying(engine)` — playback state
- `useChange(engine)` — StateChange diff
- `usePlayhead(engine)` — full playhead state
- `usePlayheadEvent(engine, type, handler)`
- `useVirtualWindow(engine, w, s, ppf)`
- `useVisibleClips(engine, window)`
- `useToolRouter(engine, options)`

**ToolRouter**
- `createToolRouter()` — React pointer/key
event → TimelinePointerEvent/KeyEvent
- rAF throttle on onPointerMove only
- Option Y: pointerLeave → handlePointerUp
+ handlePointerLeave + clearProvisional
- `useToolRouter()` hook with stable ref

**Selector isolation**
- Proven: updating clip A does not re-render
component watching clip B (toBe test)
- `historyFlags` cache prevents spurious
re-renders on unchanged undo/redo state
- `stableTrackIds` only recreates on actual
track list change

### Tests
- Phase R adds 97 react tests
- 1039 total tests across core + react
- Integration suite: 27 tests covering
full dispatch→hook→re-render round-trips

---

## [0.6.0] — Phase 7 Complete — February 27, 2025

### Added
Expand Down Expand Up @@ -292,7 +424,7 @@ _No unreleased changes._
- play() seeks to startFrame - prerollFrames on entry
- 'loop-point' event on wrap

**React Hooks (@timeline/react)**
**React Hooks (@webpacked-timeline/react)**
- `usePlayhead(engine)` — useSyncExternalStore,
stable action callbacks
- `usePlayheadEvent(engine, type, handler)` —
Expand All @@ -308,7 +440,7 @@ _No unreleased changes._

## [0.4.0] — Phase 4 Complete — February 27, 2025

### @timeline/core
### @webpacked-timeline/core

#### Added

Expand Down
Loading