@twick/timeline 0.14.0 → 0.14.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,175 +1,261 @@
1
- # @twick/timeline
2
-
3
- ## Timeline Editor CRUD Operations
4
-
5
- The TimelineEditor provides a clean interface for managing tracks and elements using the visitor pattern.
6
-
7
- ### Track Operations
8
-
9
- ```typescript
10
- import { TimelineEditor, TimelineOperationContext } from '@twick/timeline';
11
-
12
- // Create editor with context
13
- const context: TimelineOperationContext = {
14
- contextId: 'my-editor',
15
- setTotalDuration: (duration) => console.log('Duration:', duration),
16
- setPresent: (data) => console.log('Present:', data),
17
- handleUndo: () => console.log('Undo'),
18
- handleRedo: () => console.log('Redo'),
19
- handleResetHistory: () => console.log('Reset History'),
20
- setLatestProjectVersion: (version) => console.log('Version:', version),
21
- setTimelineAction: (action, payload) => console.log('Action:', action, payload),
22
- };
23
-
24
- const editor = new TimelineEditor(context);
25
-
26
- // Create a new track
27
- const track = editor.addTrack('My Video Track');
28
-
29
- // Get track by ID
30
- const trackById = editor.getTrackById(track.getId());
31
-
32
- // Get track by name
33
- const trackByName = editor.getTrackByName('My Video Track');
34
-
35
- // Remove track
36
- editor.removeTrackById(track.getId());
37
- ```
38
-
39
- ### Element Operations (Using Visitor Pattern)
40
-
41
- The TimelineEditor uses the visitor pattern to handle different element types consistently:
42
-
43
- ```typescript
44
- import {
45
- TimelineEditor,
46
- TextElement,
47
- VideoElement,
48
- ImageElement,
49
- AudioElement,
50
- TrackElement
51
- } from '@twick/timeline';
52
-
53
- // Add elements to track
54
- const textElement = new TextElement('Hello World')
55
- .setStart(0)
56
- .setEnd(5)
57
- .setName('Welcome Text');
58
-
59
- const videoElement = new VideoElement('video.mp4', { width: 720, height: 480 })
60
- .setStart(0)
61
- .setEnd(30)
62
- .setName('Main Video');
63
-
64
- // Add elements using visitor pattern
65
- await editor.addElementToTrack(track.getId(), textElement);
66
- await editor.addElementToTrack(track.getId(), videoElement);
67
-
68
- // Update elements
69
- const updatedTextElement = new TextElement('Updated Text')
70
- .setId(textElement.getId()) // Keep same ID
71
- .setStart(0)
72
- .setEnd(8)
73
- .setName('Updated Welcome Text');
74
-
75
- editor.updateElementInTrack(track.getId(), updatedTextElement);
76
-
77
- // Remove elements
78
- editor.removeElementFromTrack(track.getId(), textElement);
79
- ```
80
-
81
- ### Complete CRUD Example
82
-
83
- ```typescript
84
- // Create editor and track
85
- const editor = new TimelineEditor(context);
86
- const track = editor.addTrack('Demo Track');
87
-
88
- // Create elements
89
- const textElement = new TextElement('Sample Text')
90
- .setStart(0)
91
- .setEnd(5)
92
- .setName('Sample Text Element');
93
-
94
- const imageElement = new ImageElement('image.jpg', { width: 300, height: 200 })
95
- .setStart(5)
96
- .setEnd(10)
97
- .setName('Sample Image');
98
-
99
- // Add elements
100
- await editor.addElementToTrack(track.getId(), textElement);
101
- await editor.addElementToTrack(track.getId(), imageElement);
102
-
103
- // Update element
104
- const updatedText = new TextElement('Updated Sample Text')
105
- .setId(textElement.getId())
106
- .setStart(0)
107
- .setEnd(8)
108
- .setName('Updated Text Element');
109
-
110
- editor.updateElementInTrack(track.getId(), updatedText);
111
-
112
- // Remove element
113
- editor.removeElementFromTrack(track.getId(), imageElement);
114
-
115
- // Get timeline data
116
- const timelineData = editor.getTimelineData();
117
- console.log('Timeline:', timelineData);
118
- ```
119
-
120
- ### Utility Functions
121
-
122
- ```typescript
123
- import {
124
- getCurrentElements,
125
- getTotalDuration,
126
- generateShortUuid,
127
- isElementId,
128
- isTrackId
129
- } from '@twick/timeline';
130
-
131
- // Get elements currently playing at a specific time
132
- const currentElements = getCurrentElements(currentTime, tracks);
133
-
134
- // Get total duration of all tracks
135
- const totalDuration = getTotalDuration(trackData);
136
-
137
- // Generate unique IDs
138
- const elementId = generateShortUuid(); // "e-xxxxxxxxxxxx"
139
- const trackId = generateShortUuid(); // "t-xxxxxxxxxxxx"
140
-
141
- // Check ID types
142
- isElementId('e-123456789abc'); // true
143
- isTrackId('t-123456789abc'); // true
144
- ```
145
-
146
- ### Visitor Pattern Benefits
147
-
148
- - **Type Safety**: Each element type is handled specifically
149
- - **Extensibility**: Easy to add new element types
150
- - **Consistency**: Same pattern for all CRUD operations
151
- - **Maintainability**: Clean separation of concerns
152
-
153
- ### React Hook Usage
154
-
155
- ```typescript
156
- import { useTimelineContext } from '@twick/timeline';
157
-
158
- function MyComponent() {
159
- const { editor } = useTimelineContext();
160
-
161
- // Use editor methods
162
- const track = editor.addTrack('My Track');
163
-
164
- // Add elements
165
- const textElement = new TextElement('Hello World')
166
- .setStart(0)
167
- .setEnd(5);
168
-
169
- await editor.addElementToTrack(track.getId(), textElement);
170
-
171
- return <div>Timeline Editor Ready</div>;
172
- }
173
- ```
174
-
175
-
1
+ # @twick/timeline
2
+
3
+ Timeline management and editing capabilities for video projects.
4
+
5
+ ## Overview
6
+
7
+ This package provides a comprehensive timeline editor with CRUD operations for managing video tracks and elements. It uses the visitor pattern to handle different element types consistently and offers a fluent interface for timeline manipulation.
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ npm install @twick/timeline
13
+ # or
14
+ pnpm add @twick/timeline
15
+ ```
16
+
17
+ ## Quick Start
18
+
19
+ ```typescript
20
+ import { TimelineEditor, TimelineOperationContext } from '@twick/timeline';
21
+
22
+ // Create editor with context
23
+ const context: TimelineOperationContext = {
24
+ contextId: 'my-editor',
25
+ setTotalDuration: (duration) => console.log('Duration:', duration),
26
+ setPresent: (data) => console.log('Present:', data),
27
+ handleUndo: () => console.log('Undo'),
28
+ handleRedo: () => console.log('Redo'),
29
+ handleResetHistory: () => console.log('Reset History'),
30
+ setLatestProjectVersion: (version) => console.log('Version:', version),
31
+ setTimelineAction: (action, payload) => console.log('Action:', action, payload),
32
+ };
33
+
34
+ const editor = new TimelineEditor(context);
35
+ const track = editor.addTrack('My Video Track');
36
+ ```
37
+
38
+ ## Timeline Editor CRUD Operations
39
+
40
+ The TimelineEditor provides a clean interface for managing tracks and elements using the visitor pattern.
41
+
42
+ ### Track Operations
43
+
44
+ ```typescript
45
+ import { TimelineEditor, TimelineOperationContext } from '@twick/timeline';
46
+
47
+ // Create editor with context
48
+ const context: TimelineOperationContext = {
49
+ contextId: 'my-editor',
50
+ setTotalDuration: (duration) => console.log('Duration:', duration),
51
+ setPresent: (data) => console.log('Present:', data),
52
+ handleUndo: () => console.log('Undo'),
53
+ handleRedo: () => console.log('Redo'),
54
+ handleResetHistory: () => console.log('Reset History'),
55
+ setLatestProjectVersion: (version) => console.log('Version:', version),
56
+ setTimelineAction: (action, payload) => console.log('Action:', action, payload),
57
+ };
58
+
59
+ const editor = new TimelineEditor(context);
60
+
61
+ // Create a new track
62
+ const track = editor.addTrack('My Video Track');
63
+
64
+ // Get track by ID
65
+ const trackById = editor.getTrackById(track.getId());
66
+
67
+ // Get track by name
68
+ const trackByName = editor.getTrackByName('My Video Track');
69
+
70
+ // Remove track
71
+ editor.removeTrackById(track.getId());
72
+ ```
73
+
74
+ ### Element Operations (Using Visitor Pattern)
75
+
76
+ The TimelineEditor uses the visitor pattern to handle different element types consistently:
77
+
78
+ ```typescript
79
+ import {
80
+ TimelineEditor,
81
+ TextElement,
82
+ VideoElement,
83
+ ImageElement,
84
+ AudioElement,
85
+ TrackElement
86
+ } from '@twick/timeline';
87
+
88
+ // Add elements to track
89
+ const textElement = new TextElement('Hello World')
90
+ .setStart(0)
91
+ .setEnd(5)
92
+ .setName('Welcome Text');
93
+
94
+ const videoElement = new VideoElement('video.mp4', { width: 720, height: 480 })
95
+ .setStart(0)
96
+ .setEnd(30)
97
+ .setName('Main Video');
98
+
99
+ // Add elements using visitor pattern
100
+ await editor.addElementToTrack(track.getId(), textElement);
101
+ await editor.addElementToTrack(track.getId(), videoElement);
102
+
103
+ // Update elements
104
+ const updatedTextElement = new TextElement('Updated Text')
105
+ .setId(textElement.getId()) // Keep same ID
106
+ .setStart(0)
107
+ .setEnd(8)
108
+ .setName('Updated Welcome Text');
109
+
110
+ editor.updateElementInTrack(track.getId(), updatedTextElement);
111
+
112
+ // Remove elements
113
+ editor.removeElementFromTrack(track.getId(), textElement);
114
+ ```
115
+
116
+ ### Complete CRUD Example
117
+
118
+ ```typescript
119
+ // Create editor and track
120
+ const editor = new TimelineEditor(context);
121
+ const track = editor.addTrack('Demo Track');
122
+
123
+ // Create elements
124
+ const textElement = new TextElement('Sample Text')
125
+ .setStart(0)
126
+ .setEnd(5)
127
+ .setName('Sample Text Element');
128
+
129
+ const imageElement = new ImageElement('image.jpg', { width: 300, height: 200 })
130
+ .setStart(5)
131
+ .setEnd(10)
132
+ .setName('Sample Image');
133
+
134
+ // Add elements
135
+ await editor.addElementToTrack(track.getId(), textElement);
136
+ await editor.addElementToTrack(track.getId(), imageElement);
137
+
138
+ // Update element
139
+ const updatedText = new TextElement('Updated Sample Text')
140
+ .setId(textElement.getId())
141
+ .setStart(0)
142
+ .setEnd(8)
143
+ .setName('Updated Text Element');
144
+
145
+ editor.updateElementInTrack(track.getId(), updatedText);
146
+
147
+ // Remove element
148
+ editor.removeElementFromTrack(track.getId(), imageElement);
149
+
150
+ // Get timeline data
151
+ const timelineData = editor.getTimelineData();
152
+ console.log('Timeline:', timelineData);
153
+ ```
154
+
155
+ ### Utility Functions
156
+
157
+ ```typescript
158
+ import {
159
+ getCurrentElements,
160
+ getTotalDuration,
161
+ generateShortUuid,
162
+ isElementId,
163
+ isTrackId
164
+ } from '@twick/timeline';
165
+
166
+ // Get elements currently playing at a specific time
167
+ const currentElements = getCurrentElements(currentTime, tracks);
168
+
169
+ // Get total duration of all tracks
170
+ const totalDuration = getTotalDuration(trackData);
171
+
172
+ // Generate unique IDs
173
+ const elementId = generateShortUuid(); // "e-xxxxxxxxxxxx"
174
+ const trackId = generateShortUuid(); // "t-xxxxxxxxxxxx"
175
+
176
+ // Check ID types
177
+ isElementId('e-123456789abc'); // true
178
+ isTrackId('t-123456789abc'); // true
179
+ ```
180
+
181
+ ### Visitor Pattern Benefits
182
+
183
+ - **Type Safety**: Each element type is handled specifically
184
+ - **Extensibility**: Easy to add new element types
185
+ - **Consistency**: Same pattern for all CRUD operations
186
+ - **Maintainability**: Clean separation of concerns
187
+
188
+ ### React Hook Usage
189
+
190
+ ```typescript
191
+ import { useTimelineContext } from '@twick/timeline';
192
+
193
+ function MyComponent() {
194
+ const { editor } = useTimelineContext();
195
+
196
+ // Use editor methods
197
+ const track = editor.addTrack('My Track');
198
+
199
+ // Add elements
200
+ const textElement = new TextElement('Hello World')
201
+ .setStart(0)
202
+ .setEnd(5);
203
+
204
+ await editor.addElementToTrack(track.getId(), textElement);
205
+
206
+ return <div>Timeline Editor Ready</div>;
207
+ }
208
+ ```
209
+
210
+ ## API Reference
211
+
212
+ ### Core Classes
213
+
214
+ - `TimelineEditor`: Main timeline editor class
215
+ - `TextElement`: Text element implementation
216
+ - `VideoElement`: Video element implementation
217
+ - `ImageElement`: Image element implementation
218
+ - `AudioElement`: Audio element implementation
219
+
220
+ ### Hooks
221
+
222
+ - `useTimelineContext`: React hook for timeline context
223
+
224
+ ### Utility Functions
225
+
226
+ - `getCurrentElements`: Get elements at specific time
227
+ - `getTotalDuration`: Calculate total timeline duration
228
+ - `generateShortUuid`: Generate unique IDs
229
+ - `isElementId`: Check if ID is element type
230
+ - `isTrackId`: Check if ID is track type
231
+
232
+ ### Types
233
+
234
+ - `TimelineOperationContext`: Context interface for timeline operations
235
+ - `TrackElement`: Base track element interface
236
+
237
+ For complete API documentation, refer to the generated documentation.
238
+
239
+ ## Browser Support
240
+
241
+ This package requires a browser environment with support for:
242
+ - Modern JavaScript features (ES2020+)
243
+ - Promise and async/await support
244
+
245
+ ## Documentation
246
+
247
+ For complete documentation, refer to the project documentation site.
248
+
249
+ ## License
250
+
251
+ This package is licensed under the **Sustainable Use License (SUL) Version 1.0**.
252
+
253
+ - Free for use in commercial and non-commercial apps
254
+ - Can be modified and self-hosted
255
+ - Cannot be sold, rebranded, or distributed as a standalone SDK
256
+
257
+ For commercial licensing inquiries, contact: contact@kifferai.com
258
+
259
+ For full license terms, see the main LICENSE.md file in the project root.
260
+
261
+
@@ -3,31 +3,134 @@ import { TrackElement } from '../core/elements/base.element';
3
3
  import { ProjectJSON, TrackJSON } from '../types';
4
4
  import { TimelineEditor } from '../core/editor/timeline.editor';
5
5
 
6
+ /**
7
+ * Type definition for the Timeline context.
8
+ * Contains all the state and functions needed to manage a timeline instance.
9
+ * Provides access to the timeline editor, selected items, undo/redo functionality,
10
+ * and timeline actions.
11
+ *
12
+ * @example
13
+ * ```js
14
+ * const {
15
+ * editor,
16
+ * selectedItem,
17
+ * totalDuration,
18
+ * canUndo,
19
+ * canRedo,
20
+ * setSelectedItem,
21
+ * setTimelineAction
22
+ * } = useTimelineContext();
23
+ * ```
24
+ */
6
25
  export type TimelineContextType = {
26
+ /** Unique identifier for this timeline context */
7
27
  contextId: string;
28
+ /** The timeline editor instance for this context */
8
29
  editor: TimelineEditor;
30
+ /** Currently selected track or element */
9
31
  selectedItem: Track | TrackElement | null;
32
+ /** Change counter for tracking modifications */
10
33
  changeLog: number;
34
+ /** Current timeline action being performed */
11
35
  timelineAction: {
12
36
  type: string;
13
37
  payload: any;
14
38
  };
39
+ /** Total duration of the timeline in seconds */
15
40
  totalDuration: number;
41
+ /** Current project state */
16
42
  present: ProjectJSON | null;
43
+ /** Whether undo operation is available */
17
44
  canUndo: boolean;
45
+ /** Whether redo operation is available */
18
46
  canRedo: boolean;
47
+ /** Function to set the selected item */
19
48
  setSelectedItem: (item: Track | TrackElement | null) => void;
49
+ /** Function to set timeline actions */
20
50
  setTimelineAction: (type: string, payload: any) => void;
21
51
  };
52
+ /**
53
+ * Props for the TimelineProvider component.
54
+ * Defines the configuration options for timeline context initialization.
55
+ *
56
+ * @example
57
+ * ```jsx
58
+ * <TimelineProvider
59
+ * contextId="my-timeline"
60
+ * initialData={{ tracks: [], version: 1 }}
61
+ * undoRedoPersistenceKey="timeline-state"
62
+ * maxHistorySize={50}
63
+ * >
64
+ * <YourApp />
65
+ * </TimelineProvider>
66
+ * ```
67
+ */
22
68
  export interface TimelineProviderProps {
69
+ /** React children to wrap with timeline context */
23
70
  children: React.ReactNode;
71
+ /** Unique identifier for this timeline context */
24
72
  contextId: string;
73
+ /** Initial timeline data to load */
25
74
  initialData?: {
26
75
  tracks: TrackJSON[];
27
76
  version: number;
28
77
  };
78
+ /** Key for persisting undo/redo state */
29
79
  undoRedoPersistenceKey?: string;
80
+ /** Maximum number of history states to keep */
30
81
  maxHistorySize?: number;
31
82
  }
83
+ /**
84
+ * Provider component for the Timeline context.
85
+ * Wraps the timeline functionality with PostHog analytics and undo/redo support.
86
+ * Manages the global state for timeline instances including tracks, elements,
87
+ * playback state, and history management.
88
+ *
89
+ * @param props - Timeline provider configuration
90
+ * @returns Context provider with timeline state management
91
+ *
92
+ * @example
93
+ * ```jsx
94
+ * <TimelineProvider
95
+ * contextId="my-timeline"
96
+ * initialData={{ tracks: [], version: 1 }}
97
+ * undoRedoPersistenceKey="timeline-state"
98
+ * >
99
+ * <YourApp />
100
+ * </TimelineProvider>
101
+ * ```
102
+ */
32
103
  export declare const TimelineProvider: ({ contextId, children, initialData, undoRedoPersistenceKey, maxHistorySize, }: TimelineProviderProps) => import("react/jsx-runtime").JSX.Element;
104
+ /**
105
+ * Hook to access the Timeline context.
106
+ * Provides access to timeline state, editor instance, and timeline management functions.
107
+ * Must be used within a TimelineProvider component.
108
+ *
109
+ * @returns TimelineContextType object with all timeline state and controls
110
+ * @throws Error if used outside of TimelineProvider
111
+ *
112
+ * @example
113
+ * ```js
114
+ * const {
115
+ * editor,
116
+ * selectedItem,
117
+ * totalDuration,
118
+ * canUndo,
119
+ * canRedo,
120
+ * setSelectedItem,
121
+ * setTimelineAction
122
+ * } = useTimelineContext();
123
+ *
124
+ * // Access the timeline editor
125
+ * const tracks = editor.getTracks();
126
+ *
127
+ * // Check if undo is available
128
+ * if (canUndo) {
129
+ * editor.undo();
130
+ * }
131
+ *
132
+ * // Set timeline action
133
+ * setTimelineAction(TIMELINE_ACTION.SET_PLAYER_STATE, { playing: true });
134
+ * ```
135
+ */
33
136
  export declare const useTimelineContext: () => TimelineContextType;
@@ -14,11 +14,11 @@ export declare class ElementAnimation {
14
14
  getAnimate(): "enter" | "exit" | "both" | undefined;
15
15
  getMode(): "in" | "out" | undefined;
16
16
  getDirection(): "left" | "center" | "right" | "up" | "down" | undefined;
17
- setInterval(interval?: number): void;
18
- setIntensity(intensity?: number): void;
19
- setAnimate(animate?: "enter" | "exit" | "both"): void;
20
- setMode(mode?: "in" | "out"): void;
21
- setDirection(direction?: "up" | "down" | "left" | "right" | "center"): void;
17
+ setInterval(interval?: number): this;
18
+ setIntensity(intensity?: number): this;
19
+ setAnimate(animate?: "enter" | "exit" | "both"): this;
20
+ setMode(mode?: "in" | "out"): this;
21
+ setDirection(direction?: "up" | "down" | "left" | "right" | "center"): this;
22
22
  toJSON(): Animation;
23
23
  static fromJSON(json: Animation): ElementAnimation;
24
24
  }
@@ -5,10 +5,12 @@ export declare class ElementFrameEffect {
5
5
  private e;
6
6
  private props;
7
7
  constructor(start: number, end: number);
8
- setProps(props: FrameEffectProps): void;
8
+ setProps(props: FrameEffectProps): this;
9
9
  getProps(): FrameEffectProps;
10
10
  getStart(): number;
11
11
  getEnd(): number;
12
+ setStart(start: number): this;
13
+ setEnd(end: number): this;
12
14
  toJSON(): FrameEffect;
13
15
  static fromJSON(json: FrameEffect): ElementFrameEffect;
14
16
  }
@@ -10,10 +10,9 @@ export declare class ElementTextEffect {
10
10
  getDuration(): number | undefined;
11
11
  getDelay(): number | undefined;
12
12
  getBufferTime(): number | undefined;
13
- setName(name: string): void;
14
- setDuration(duration?: number): void;
15
- setDelay(delay?: number): void;
16
- setBufferTime(bufferTime?: number): void;
13
+ setDuration(duration?: number): this;
14
+ setDelay(delay?: number): this;
15
+ setBufferTime(bufferTime?: number): this;
17
16
  toJSON(): TextEffect;
18
17
  static fromJSON(json: TextEffect): ElementTextEffect;
19
18
  }
@@ -26,6 +26,7 @@ export interface TimelineOperationContext {
26
26
  */
27
27
  export declare class TimelineEditor {
28
28
  private context;
29
+ private totalDuration;
29
30
  constructor(context: TimelineOperationContext);
30
31
  getContext(): TimelineOperationContext;
31
32
  pauseVideo(): void;
@@ -91,4 +92,5 @@ export declare class TimelineEditor {
91
92
  tracks: TrackJSON[];
92
93
  version: number;
93
94
  }): void;
95
+ getVideoAudio(): Promise<string>;
94
96
  }
@@ -8,6 +8,10 @@ export declare class AudioElement extends TrackElement {
8
8
  constructor(src: string);
9
9
  getMediaDuration(): number;
10
10
  getStartAt(): number;
11
+ getEndAt(): number;
12
+ getSrc(): string;
13
+ getPlaybackRate(): number;
14
+ getVolume(): number;
11
15
  updateAudioMeta(): Promise<void>;
12
16
  setSrc(src: string): Promise<this>;
13
17
  setMediaDuration(mediaDuration: number): this;
@@ -20,6 +20,10 @@ export declare class VideoElement extends TrackElement {
20
20
  getObjectFit(): ObjectFit;
21
21
  getMediaDuration(): number;
22
22
  getStartAt(): number;
23
+ getEndAt(): number;
24
+ getSrc(): string;
25
+ getPlaybackRate(): number;
26
+ getVolume(): number;
23
27
  getPosition(): Position;
24
28
  updateVideoMeta(updateFrame?: boolean): Promise<void>;
25
29
  setPosition(position: Position): this;
@@ -28,7 +32,6 @@ export declare class VideoElement extends TrackElement {
28
32
  setParentSize(parentSize: Size): this;
29
33
  setObjectFit(objectFit: ObjectFit): this;
30
34
  setFrame(frame: Frame): this;
31
- setPlay(play: boolean): this;
32
35
  setPlaybackRate(playbackRate: number): this;
33
36
  setStartAt(time: number): this;
34
37
  setMediaFilter(mediaFilter: string): this;