@twick/studio 0.14.6 → 0.14.8
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 +73 -6
- package/dist/components/container/element-panel-container.d.ts +26 -1
- package/dist/components/container/subtitles-panel-container.d.ts +1 -0
- package/dist/components/panel/audio-panel.d.ts +1 -1
- package/dist/components/panel/image-panel.d.ts +1 -1
- package/dist/components/panel/subtitles-panel.d.ts +37 -18
- package/dist/components/panel/video-panel.d.ts +1 -1
- package/dist/components/shared/index.d.ts +1 -0
- package/dist/components/shared/url-input.d.ts +6 -0
- package/dist/helpers/constant.d.ts +52 -0
- package/dist/hooks/use-studio-manager.d.ts +1 -1
- package/dist/hooks/use-subtitles-panel.d.ts +13 -0
- package/dist/index.js +413 -248
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +415 -250
- package/dist/index.mjs.map +1 -1
- package/dist/studio.css +17 -3
- package/dist/types/media-panel.d.ts +11 -6
- package/package.json +5 -3
package/README.md
CHANGED
|
@@ -34,12 +34,32 @@ export default function App() {
|
|
|
34
34
|
initialData={INITIAL_TIMELINE_DATA}
|
|
35
35
|
contextId={"studio-demo"}
|
|
36
36
|
>
|
|
37
|
-
<TwickStudio
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
37
|
+
<TwickStudio
|
|
38
|
+
studioConfig={{
|
|
39
|
+
videoProps: {
|
|
40
|
+
width: 720,
|
|
41
|
+
height: 1280,
|
|
42
|
+
},
|
|
43
|
+
// Optional: Customize timeline tick marks
|
|
44
|
+
timelineTickConfigs: [
|
|
45
|
+
{ durationThreshold: 30, majorInterval: 5, minorTicks: 5 },
|
|
46
|
+
{ durationThreshold: 300, majorInterval: 30, minorTicks: 6 }
|
|
47
|
+
],
|
|
48
|
+
// Optional: Customize zoom behavior
|
|
49
|
+
timelineZoomConfig: {
|
|
50
|
+
min: 0.5, max: 2.0, step: 0.25, default: 1.0
|
|
51
|
+
},
|
|
52
|
+
// Optional: Customize element colors
|
|
53
|
+
elementColors: {
|
|
54
|
+
video: "#8B5FBF",
|
|
55
|
+
audio: "#3D8B8B",
|
|
56
|
+
image: "#D4956C",
|
|
57
|
+
text: "#A78EC8",
|
|
58
|
+
caption: "#9B8ACE",
|
|
59
|
+
fragment: "#1A1A1A"
|
|
60
|
+
}
|
|
61
|
+
}}
|
|
62
|
+
/>
|
|
43
63
|
</TimelineProvider>
|
|
44
64
|
</LivePlayerProvider>
|
|
45
65
|
);
|
|
@@ -59,6 +79,24 @@ The main studio component that provides a complete video editing interface.
|
|
|
59
79
|
width: 1920,
|
|
60
80
|
height: 1080
|
|
61
81
|
},
|
|
82
|
+
// Optional: Customize timeline tick marks
|
|
83
|
+
timelineTickConfigs: [
|
|
84
|
+
{ durationThreshold: 30, majorInterval: 5, minorTicks: 5 },
|
|
85
|
+
{ durationThreshold: 300, majorInterval: 30, minorTicks: 6 }
|
|
86
|
+
],
|
|
87
|
+
// Optional: Customize zoom behavior
|
|
88
|
+
timelineZoomConfig: {
|
|
89
|
+
min: 0.5, max: 2.0, step: 0.25, default: 1.0
|
|
90
|
+
},
|
|
91
|
+
// Optional: Customize element colors
|
|
92
|
+
elementColors: {
|
|
93
|
+
video: "#8B5FBF",
|
|
94
|
+
audio: "#3D8B8B",
|
|
95
|
+
image: "#D4956C",
|
|
96
|
+
text: "#A78EC8",
|
|
97
|
+
caption: "#9B8ACE",
|
|
98
|
+
fragment: "#1A1A1A"
|
|
99
|
+
},
|
|
62
100
|
saveProject: async (project, fileName) => {
|
|
63
101
|
// Custom save logic
|
|
64
102
|
return { status: true, message: "Project saved" };
|
|
@@ -85,10 +123,39 @@ interface StudioConfig {
|
|
|
85
123
|
width: number;
|
|
86
124
|
height: number;
|
|
87
125
|
};
|
|
126
|
+
// Timeline tick configuration
|
|
127
|
+
timelineTickConfigs?: TimelineTickConfig[];
|
|
128
|
+
// Zoom configuration
|
|
129
|
+
timelineZoomConfig?: TimelineZoomConfig;
|
|
130
|
+
// Element colors
|
|
131
|
+
elementColors?: ElementColors;
|
|
132
|
+
// Project management callbacks
|
|
88
133
|
saveProject?: (project: ProjectJSON, fileName: string) => Promise<Result>;
|
|
89
134
|
loadProject?: () => Promise<ProjectJSON>;
|
|
90
135
|
exportVideo?: (project: ProjectJSON, videoSettings: VideoSettings) => Promise<Result>;
|
|
91
136
|
}
|
|
137
|
+
|
|
138
|
+
interface TimelineTickConfig {
|
|
139
|
+
durationThreshold: number; // Applies when duration < threshold
|
|
140
|
+
majorInterval: number; // Major tick interval in seconds
|
|
141
|
+
minorTicks: number; // Number of minor ticks between majors
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
interface TimelineZoomConfig {
|
|
145
|
+
min: number; // Minimum zoom level
|
|
146
|
+
max: number; // Maximum zoom level
|
|
147
|
+
step: number; // Zoom step increment/decrement
|
|
148
|
+
default: number; // Default zoom level
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
interface ElementColors {
|
|
152
|
+
video: string;
|
|
153
|
+
audio: string;
|
|
154
|
+
image: string;
|
|
155
|
+
text: string;
|
|
156
|
+
caption: string;
|
|
157
|
+
fragment: string;
|
|
158
|
+
}
|
|
92
159
|
```
|
|
93
160
|
|
|
94
161
|
### Individual Panels
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { Size, TrackElement } from '@twick/timeline';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Props interface for the ElementPanelContainer component.
|
|
5
|
+
* Defines the configuration and callback functions for element management.
|
|
6
|
+
*/
|
|
3
7
|
interface ElementPanelContainerProps {
|
|
4
8
|
selectedTool: string;
|
|
5
9
|
selectedElement: TrackElement | null;
|
|
@@ -8,5 +12,26 @@ interface ElementPanelContainerProps {
|
|
|
8
12
|
addElement: (element: TrackElement) => void;
|
|
9
13
|
updateElement: (element: TrackElement) => void;
|
|
10
14
|
}
|
|
11
|
-
|
|
15
|
+
/**
|
|
16
|
+
* ElementPanelContainer component that renders the appropriate element panel
|
|
17
|
+
* based on the currently selected tool. Provides a unified interface for
|
|
18
|
+
* managing different types of timeline elements including media, text, shapes,
|
|
19
|
+
* and subtitles. Shows an empty state when no tool is selected.
|
|
20
|
+
*
|
|
21
|
+
* @param props - Component props for element panel configuration
|
|
22
|
+
* @returns JSX element containing the appropriate element panel or empty state
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```tsx
|
|
26
|
+
* <ElementPanelContainer
|
|
27
|
+
* selectedTool="text"
|
|
28
|
+
* selectedElement={currentElement}
|
|
29
|
+
* videoResolution={{ width: 1920, height: 1080 }}
|
|
30
|
+
* setSelectedTool={setTool}
|
|
31
|
+
* addElement={addToTimeline}
|
|
32
|
+
* updateElement={updateInTimeline}
|
|
33
|
+
* />
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
declare const ElementPanelContainer: ({ selectedTool, videoResolution, selectedElement, addElement, updateElement, }: ElementPanelContainerProps) => JSX.Element;
|
|
12
37
|
export default ElementPanelContainer;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function SubtitlesPanelContainer(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { AudioPanelProps } from '../../types/media-panel';
|
|
2
2
|
|
|
3
|
-
export declare const AudioPanel: ({ items,
|
|
3
|
+
export declare const AudioPanel: ({ items, onItemSelect, onFileUpload, acceptFileTypes, onUrlAdd, }: AudioPanelProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { ImagePanelProps } from '../../types/media-panel';
|
|
2
2
|
|
|
3
|
-
export declare function ImagePanel({ items,
|
|
3
|
+
export declare function ImagePanel({ items, onItemSelect, onFileUpload, acceptFileTypes, onUrlAdd, }: ImagePanelProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,27 +1,46 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* SubtitlesPanel Component
|
|
3
3
|
*
|
|
4
|
-
* A panel for managing
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* A presentational panel for managing subtitle entries in the studio.
|
|
5
|
+
* Renders a list of subtitle items, each with a text input and two actions:
|
|
6
|
+
* Split and Delete. A single Add button appears below the list.
|
|
7
|
+
*
|
|
8
|
+
* State is controlled by the parent via props; this component is stateless.
|
|
9
|
+
*
|
|
10
|
+
* Entry shape (SubtitleEntry):
|
|
11
|
+
* - `s`: start time (seconds)
|
|
12
|
+
* - `e`: end time (seconds)
|
|
13
|
+
* - `t`: subtitle text
|
|
14
|
+
*
|
|
15
|
+
* Props:
|
|
16
|
+
* - `subtitles`: SubtitleEntry[] — ordered list of subtitles
|
|
17
|
+
* - `addSubtitle()`: add a new subtitle at the end
|
|
18
|
+
* - `splitSubtitle(index)`: split the subtitle at `index`
|
|
19
|
+
* - `deleteSubtitle(index)`: remove the subtitle at `index`
|
|
20
|
+
* - `updateSubtitle(index, subtitle)`: update the subtitle at `index`
|
|
7
21
|
*
|
|
8
22
|
* @component
|
|
9
23
|
* @example
|
|
10
24
|
* ```tsx
|
|
11
|
-
* <SubtitlesPanel
|
|
25
|
+
* <SubtitlesPanel
|
|
26
|
+
* subtitles={subtitles}
|
|
27
|
+
* addSubtitle={addSubtitle}
|
|
28
|
+
* splitSubtitle={splitSubtitle}
|
|
29
|
+
* deleteSubtitle={deleteSubtitle}
|
|
30
|
+
* updateSubtitle={updateSubtitle}
|
|
31
|
+
* />
|
|
12
32
|
* ```
|
|
13
|
-
*
|
|
14
|
-
* Features:
|
|
15
|
-
* - Add/delete subtitle entries
|
|
16
|
-
* - Set start/end times
|
|
17
|
-
* - Edit subtitle text
|
|
18
|
-
* - Automatic subtitle generation (planned)
|
|
19
|
-
* - Save subtitles to timeline
|
|
20
|
-
*
|
|
21
|
-
* Each subtitle entry includes:
|
|
22
|
-
* - Start time (in seconds)
|
|
23
|
-
* - End time (in seconds)
|
|
24
|
-
* - Subtitle text
|
|
25
|
-
* - Delete and save actions
|
|
26
33
|
*/
|
|
27
|
-
|
|
34
|
+
interface SubtitleEntry {
|
|
35
|
+
s: number;
|
|
36
|
+
e: number;
|
|
37
|
+
t: string;
|
|
38
|
+
}
|
|
39
|
+
export declare function SubtitlesPanel({ subtitles, addSubtitle, splitSubtitle, deleteSubtitle, updateSubtitle, }: {
|
|
40
|
+
subtitles: SubtitleEntry[];
|
|
41
|
+
addSubtitle: () => void;
|
|
42
|
+
splitSubtitle: (index: number) => void;
|
|
43
|
+
deleteSubtitle: (index: number) => void;
|
|
44
|
+
updateSubtitle: (index: number, subtitle: SubtitleEntry) => void;
|
|
45
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
46
|
+
export {};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { VideoPanelProps } from '../../types/media-panel';
|
|
2
2
|
|
|
3
|
-
export declare function VideoPanel({ items,
|
|
3
|
+
export declare function VideoPanel({ items, onItemSelect, onFileUpload, acceptFileTypes, onUrlAdd, }: VideoPanelProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export declare const CAPTION_PROPS: {
|
|
2
|
+
highlight_bg: {
|
|
3
|
+
font: {
|
|
4
|
+
size: number;
|
|
5
|
+
weight: number;
|
|
6
|
+
family: string;
|
|
7
|
+
};
|
|
8
|
+
colors: {
|
|
9
|
+
text: string;
|
|
10
|
+
highlight: string;
|
|
11
|
+
bgColor: string;
|
|
12
|
+
};
|
|
13
|
+
lineWidth: number;
|
|
14
|
+
stroke: string;
|
|
15
|
+
fontWeight: number;
|
|
16
|
+
shadowOffset: number[];
|
|
17
|
+
shadowColor: string;
|
|
18
|
+
};
|
|
19
|
+
word_by_word: {
|
|
20
|
+
font: {
|
|
21
|
+
size: number;
|
|
22
|
+
weight: number;
|
|
23
|
+
family: string;
|
|
24
|
+
};
|
|
25
|
+
colors: {
|
|
26
|
+
text: string;
|
|
27
|
+
highlight: string;
|
|
28
|
+
bgColor: string;
|
|
29
|
+
};
|
|
30
|
+
lineWidth: number;
|
|
31
|
+
stroke: string;
|
|
32
|
+
shadowOffset: number[];
|
|
33
|
+
shadowColor: string;
|
|
34
|
+
shadowBlur: number;
|
|
35
|
+
};
|
|
36
|
+
word_by_word_with_bg: {
|
|
37
|
+
font: {
|
|
38
|
+
size: number;
|
|
39
|
+
weight: number;
|
|
40
|
+
family: string;
|
|
41
|
+
};
|
|
42
|
+
colors: {
|
|
43
|
+
text: string;
|
|
44
|
+
highlight: string;
|
|
45
|
+
bgColor: string;
|
|
46
|
+
};
|
|
47
|
+
lineWidth: number;
|
|
48
|
+
shadowOffset: number[];
|
|
49
|
+
shadowColor: string;
|
|
50
|
+
shadowBlur: number;
|
|
51
|
+
};
|
|
52
|
+
};
|
|
@@ -6,6 +6,6 @@ export declare const useStudioManager: () => {
|
|
|
6
6
|
selectedTool: string;
|
|
7
7
|
setSelectedTool: import('react').Dispatch<import('react').SetStateAction<string>>;
|
|
8
8
|
selectedElement: TrackElement | null;
|
|
9
|
-
addElement: (element: TrackElement) => void
|
|
9
|
+
addElement: (element: TrackElement) => Promise<void>;
|
|
10
10
|
updateElement: (element: TrackElement) => void;
|
|
11
11
|
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
interface SubtitleEntry {
|
|
2
|
+
s: number;
|
|
3
|
+
e: number;
|
|
4
|
+
t: string;
|
|
5
|
+
}
|
|
6
|
+
export declare const useSubtitlesPanel: () => {
|
|
7
|
+
subtitles: SubtitleEntry[];
|
|
8
|
+
addSubtitle: () => void;
|
|
9
|
+
splitSubtitle: (index: number) => Promise<void>;
|
|
10
|
+
deleteSubtitle: (index: number) => void;
|
|
11
|
+
updateSubtitle: (index: number, subtitle: SubtitleEntry) => void;
|
|
12
|
+
};
|
|
13
|
+
export {};
|