@editframe/create 0.43.0 → 0.45.0
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 +11 -0
- package/dist/index.js +16 -28
- package/dist/index.js.map +1 -1
- package/dist/skills/editframe-brand-video-generator/README.md +155 -0
- package/dist/skills/editframe-brand-video-generator/SKILL.md +207 -0
- package/dist/skills/editframe-brand-video-generator/references/brand-examples.md +178 -0
- package/dist/skills/editframe-brand-video-generator/references/color-psychology.md +227 -0
- package/dist/skills/editframe-brand-video-generator/references/composition-patterns.md +383 -0
- package/dist/skills/editframe-brand-video-generator/references/editing.md +66 -0
- package/dist/skills/editframe-brand-video-generator/references/emotional-arcs.md +496 -0
- package/dist/skills/editframe-brand-video-generator/references/genre-selection.md +135 -0
- package/dist/skills/editframe-brand-video-generator/references/transition-styles.md +611 -0
- package/dist/skills/editframe-brand-video-generator/references/typography-personalities.md +326 -0
- package/dist/skills/editframe-brand-video-generator/references/video-archetypes.md +86 -0
- package/dist/skills/editframe-brand-video-generator/references/video-fundamentals.md +169 -0
- package/dist/skills/editframe-brand-video-generator/references/visual-metaphors.md +50 -0
- package/dist/skills/editframe-composition/SKILL.md +169 -0
- package/dist/skills/editframe-composition/references/audio.md +483 -0
- package/dist/skills/editframe-composition/references/captions.md +844 -0
- package/dist/skills/editframe-composition/references/composition-model.md +73 -0
- package/dist/skills/editframe-composition/references/configuration.md +403 -0
- package/dist/skills/editframe-composition/references/css-parts.md +105 -0
- package/dist/skills/editframe-composition/references/css-variables.md +640 -0
- package/dist/skills/editframe-composition/references/entry-points.md +810 -0
- package/dist/skills/editframe-composition/references/events.md +499 -0
- package/dist/skills/editframe-composition/references/getting-started.md +259 -0
- package/dist/skills/editframe-composition/references/hooks.md +234 -0
- package/dist/skills/editframe-composition/references/image.md +241 -0
- package/dist/skills/editframe-composition/references/r3f.md +580 -0
- package/dist/skills/editframe-composition/references/render-api.md +484 -0
- package/dist/skills/editframe-composition/references/render-strategies.md +119 -0
- package/dist/skills/editframe-composition/references/render-to-video.md +1101 -0
- package/dist/skills/editframe-composition/references/scripting.md +606 -0
- package/dist/skills/editframe-composition/references/sequencing.md +116 -0
- package/dist/skills/editframe-composition/references/server-rendering.md +753 -0
- package/dist/skills/editframe-composition/references/surface.md +329 -0
- package/dist/skills/editframe-composition/references/text.md +627 -0
- package/dist/skills/editframe-composition/references/time-model.md +99 -0
- package/dist/skills/editframe-composition/references/timegroup-modes.md +102 -0
- package/dist/skills/editframe-composition/references/timegroup.md +457 -0
- package/dist/skills/editframe-composition/references/timeline-root.md +398 -0
- package/dist/skills/editframe-composition/references/transcription.md +47 -0
- package/dist/skills/editframe-composition/references/transitions.md +608 -0
- package/dist/skills/editframe-composition/references/use-media-info.md +357 -0
- package/dist/skills/editframe-composition/references/video.md +506 -0
- package/dist/skills/editframe-composition/references/waveform.md +327 -0
- package/dist/skills/editframe-editor-gui/SKILL.md +152 -0
- package/dist/skills/editframe-editor-gui/references/active-root-temporal.md +657 -0
- package/dist/skills/editframe-editor-gui/references/canvas.md +947 -0
- package/dist/skills/editframe-editor-gui/references/controls.md +366 -0
- package/dist/skills/editframe-editor-gui/references/dial.md +756 -0
- package/dist/skills/editframe-editor-gui/references/editor-toolkit.md +587 -0
- package/dist/skills/editframe-editor-gui/references/filmstrip.md +460 -0
- package/dist/skills/editframe-editor-gui/references/fit-scale.md +772 -0
- package/dist/skills/editframe-editor-gui/references/focus-overlay.md +561 -0
- package/dist/skills/editframe-editor-gui/references/hierarchy.md +544 -0
- package/dist/skills/editframe-editor-gui/references/overlay-item.md +634 -0
- package/dist/skills/editframe-editor-gui/references/overlay-layer.md +429 -0
- package/dist/skills/editframe-editor-gui/references/pan-zoom.md +568 -0
- package/dist/skills/editframe-editor-gui/references/pause.md +397 -0
- package/dist/skills/editframe-editor-gui/references/play.md +370 -0
- package/dist/skills/editframe-editor-gui/references/preview.md +391 -0
- package/dist/skills/editframe-editor-gui/references/resizable-box.md +749 -0
- package/dist/skills/editframe-editor-gui/references/scrubber.md +588 -0
- package/dist/skills/editframe-editor-gui/references/thumbnail-strip.md +566 -0
- package/dist/skills/editframe-editor-gui/references/time-display.md +492 -0
- package/dist/skills/editframe-editor-gui/references/timeline-ruler.md +489 -0
- package/dist/skills/editframe-editor-gui/references/timeline.md +604 -0
- package/dist/skills/editframe-editor-gui/references/toggle-loop.md +618 -0
- package/dist/skills/editframe-editor-gui/references/toggle-play.md +526 -0
- package/dist/skills/editframe-editor-gui/references/transform-handles.md +924 -0
- package/dist/skills/editframe-editor-gui/references/trim-handles.md +725 -0
- package/dist/skills/editframe-editor-gui/references/workbench.md +453 -0
- package/dist/skills/editframe-motion-design/SKILL.md +101 -0
- package/dist/skills/editframe-motion-design/references/0-editframe.md +299 -0
- package/dist/skills/editframe-motion-design/references/1-intent.md +201 -0
- package/dist/skills/editframe-motion-design/references/2-physics-model.md +405 -0
- package/dist/skills/editframe-motion-design/references/3-attention.md +350 -0
- package/dist/skills/editframe-motion-design/references/4-process.md +418 -0
- package/dist/skills/editframe-vite-plugin/SKILL.md +75 -0
- package/dist/skills/editframe-vite-plugin/references/file-api.md +111 -0
- package/dist/skills/editframe-vite-plugin/references/getting-started.md +96 -0
- package/dist/skills/editframe-vite-plugin/references/jit-transcoding.md +91 -0
- package/dist/skills/editframe-vite-plugin/references/local-assets.md +75 -0
- package/dist/skills/editframe-vite-plugin/references/visual-testing.md +136 -0
- package/dist/skills/editframe-webhooks/SKILL.md +126 -0
- package/dist/skills/editframe-webhooks/references/events.md +382 -0
- package/dist/skills/editframe-webhooks/references/getting-started.md +232 -0
- package/dist/skills/editframe-webhooks/references/security.md +418 -0
- package/dist/skills/editframe-webhooks/references/testing.md +409 -0
- package/dist/skills/editframe-webhooks/references/troubleshooting.md +457 -0
- package/dist/templates/html/AGENTS.md +13 -0
- package/dist/templates/react/AGENTS.md +13 -0
- package/dist/utils.js +15 -16
- package/dist/utils.js.map +1 -1
- package/package.json +2 -2
- package/tsdown.config.ts +4 -0
- package/dist/detectAgent.js +0 -89
- package/dist/detectAgent.js.map +0 -1
|
@@ -0,0 +1,588 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Scrubber Element
|
|
3
|
+
description: Timeline scrubber with horizontal seek and vertical zoom modes, keyboard shortcuts, and frame-accurate time control.
|
|
4
|
+
type: reference
|
|
5
|
+
nav:
|
|
6
|
+
parent: "Timeline"
|
|
7
|
+
priority: 12
|
|
8
|
+
api:
|
|
9
|
+
attributes:
|
|
10
|
+
- name: target
|
|
11
|
+
type: string
|
|
12
|
+
description: ID of target temporal element to control
|
|
13
|
+
- name: orientation
|
|
14
|
+
type: string
|
|
15
|
+
default: horizontal
|
|
16
|
+
description: Layout orientation ("horizontal" or "vertical")
|
|
17
|
+
- name: current-time-ms
|
|
18
|
+
type: number
|
|
19
|
+
description: Current playback time in milliseconds
|
|
20
|
+
- name: duration-ms
|
|
21
|
+
type: number
|
|
22
|
+
description: Total duration in milliseconds
|
|
23
|
+
- name: zoom-scale
|
|
24
|
+
type: number
|
|
25
|
+
default: 1.0
|
|
26
|
+
description: Zoom level for vertical timeline mode
|
|
27
|
+
- name: fps
|
|
28
|
+
type: number
|
|
29
|
+
description: Frame rate for frame-snapping behavior
|
|
30
|
+
parts:
|
|
31
|
+
- name: scrubber
|
|
32
|
+
description: Main scrubber container
|
|
33
|
+
- name: progress
|
|
34
|
+
description: Progress bar fill (horizontal mode only)
|
|
35
|
+
- name: handle
|
|
36
|
+
description: Draggable handle (horizontal mode only)
|
|
37
|
+
- name: playhead
|
|
38
|
+
description: Vertical playhead line (vertical mode only)
|
|
39
|
+
events:
|
|
40
|
+
- name: seek
|
|
41
|
+
detail: number
|
|
42
|
+
description: Emitted when user seeks to a new time position
|
|
43
|
+
react:
|
|
44
|
+
generate: true
|
|
45
|
+
componentName: Scrubber
|
|
46
|
+
importPath: "@editframe/react"
|
|
47
|
+
propMapping:
|
|
48
|
+
current-time-ms: currentTimeMs
|
|
49
|
+
duration-ms: durationMs
|
|
50
|
+
zoom-scale: zoomScale
|
|
51
|
+
additionalProps:
|
|
52
|
+
- name: className
|
|
53
|
+
type: string
|
|
54
|
+
description: CSS classes for styling
|
|
55
|
+
- name: containerWidth
|
|
56
|
+
type: number
|
|
57
|
+
description: Container width for calculations
|
|
58
|
+
- name: rawScrubTimeMs
|
|
59
|
+
type: "number | null"
|
|
60
|
+
description: Raw scrub time without frame snapping
|
|
61
|
+
- name: scrollContainerRef
|
|
62
|
+
type: React.RefObject<HTMLElement>
|
|
63
|
+
description: Reference to scroll container for timeline sync
|
|
64
|
+
- name: isScrubbingRef
|
|
65
|
+
type: React.MutableRefObject<boolean>
|
|
66
|
+
description: Ref to track scrubbing state
|
|
67
|
+
- name: onSeek
|
|
68
|
+
type: "(time: number) => void"
|
|
69
|
+
description: Callback fired when seeking to a new time
|
|
70
|
+
nav:
|
|
71
|
+
parent: "Components / Timeline Controls"
|
|
72
|
+
priority: 60
|
|
73
|
+
related: ["time-display", "controls"]
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
<!-- html-only -->
|
|
77
|
+
# ef-scrubber
|
|
78
|
+
<!-- /html-only -->
|
|
79
|
+
<!-- react-only -->
|
|
80
|
+
# Scrubber
|
|
81
|
+
<!-- /react-only -->
|
|
82
|
+
|
|
83
|
+
Timeline scrubber control for navigating playback time. Supports both horizontal progress bar mode and vertical timeline mode with zoom.
|
|
84
|
+
|
|
85
|
+
<!-- react-only -->
|
|
86
|
+
## Import
|
|
87
|
+
|
|
88
|
+
```tsx
|
|
89
|
+
import { Scrubber } from "@editframe/react";
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Also available: `ScrubberProps` type for TypeScript.
|
|
93
|
+
<!-- /react-only -->
|
|
94
|
+
|
|
95
|
+
## Basic Usage
|
|
96
|
+
|
|
97
|
+
<!-- html-only -->
|
|
98
|
+
Horizontal scrubber with progress bar.
|
|
99
|
+
|
|
100
|
+
```html live
|
|
101
|
+
<ef-timegroup mode="contain" class="w-[720px] h-[480px] bg-black" id="scrubber-demo">
|
|
102
|
+
<ef-video src="https://assets.editframe.com/bars-n-tone.mp4" class="size-full object-contain"></ef-video>
|
|
103
|
+
</ef-timegroup>
|
|
104
|
+
<div class="flex flex-col gap-2 p-4 bg-gray-900 rounded-lg mt-4">
|
|
105
|
+
<ef-scrubber target="scrubber-demo"></ef-scrubber>
|
|
106
|
+
<ef-controls target="scrubber-demo" class="flex gap-2 items-center">
|
|
107
|
+
<ef-toggle-play class="px-3 py-1 bg-blue-600 text-white rounded"></ef-toggle-play>
|
|
108
|
+
<ef-time-display class="text-white text-sm"></ef-time-display>
|
|
109
|
+
</ef-controls>
|
|
110
|
+
</div>
|
|
111
|
+
```
|
|
112
|
+
<!-- /html-only -->
|
|
113
|
+
<!-- react-only -->
|
|
114
|
+
```tsx
|
|
115
|
+
import { Preview, Scrubber } from "@editframe/react";
|
|
116
|
+
|
|
117
|
+
<div className="flex flex-col gap-2">
|
|
118
|
+
<Preview className="w-full h-[600px]" />
|
|
119
|
+
<Scrubber className="w-full h-2 bg-gray-700 rounded cursor-pointer" />
|
|
120
|
+
</div>
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
The scrubber automatically connects to the nearest timeline context via Preview or Controls.
|
|
124
|
+
<!-- /react-only -->
|
|
125
|
+
|
|
126
|
+
<!-- react-only -->
|
|
127
|
+
## In Control Bar
|
|
128
|
+
|
|
129
|
+
Typical control bar layout:
|
|
130
|
+
|
|
131
|
+
```tsx
|
|
132
|
+
import { TogglePlay, Scrubber, TimeDisplay } from "@editframe/react";
|
|
133
|
+
|
|
134
|
+
export const ControlBar = () => {
|
|
135
|
+
return (
|
|
136
|
+
<div className="bg-gray-800 p-4 flex items-center gap-4">
|
|
137
|
+
<TogglePlay>
|
|
138
|
+
<button slot="play" className="w-10 h-10 text-white">▶</button>
|
|
139
|
+
<button slot="pause" className="w-10 h-10 text-white">⏸</button>
|
|
140
|
+
</TogglePlay>
|
|
141
|
+
|
|
142
|
+
<TimeDisplay className="text-white text-sm font-mono" />
|
|
143
|
+
<Scrubber className="flex-1 h-2" />
|
|
144
|
+
</div>
|
|
145
|
+
);
|
|
146
|
+
};
|
|
147
|
+
```
|
|
148
|
+
<!-- /react-only -->
|
|
149
|
+
|
|
150
|
+
## Vertical Timeline Mode
|
|
151
|
+
|
|
152
|
+
<!-- html-only -->
|
|
153
|
+
Vertical scrubber displays a playhead line that moves across a timeline. Used in `ef-timeline` and `ef-filmstrip` components.
|
|
154
|
+
|
|
155
|
+
```html live
|
|
156
|
+
<ef-timegroup mode="contain" class="w-[720px] h-[480px] bg-black" id="vertical-demo">
|
|
157
|
+
<ef-video src="https://assets.editframe.com/bars-n-tone.mp4" class="size-full object-contain"></ef-video>
|
|
158
|
+
</ef-timegroup>
|
|
159
|
+
<div class="mt-4 h-[120px] relative overflow-hidden bg-gray-900 rounded-lg">
|
|
160
|
+
<ef-scrubber
|
|
161
|
+
target="vertical-demo"
|
|
162
|
+
orientation="vertical"
|
|
163
|
+
zoom-scale="2"
|
|
164
|
+
class="absolute inset-0"
|
|
165
|
+
></ef-scrubber>
|
|
166
|
+
<div class="absolute top-0 left-0 right-0 h-6 bg-gray-800 text-white text-xs flex items-center justify-center">
|
|
167
|
+
Timeline (scroll to see full width)
|
|
168
|
+
</div>
|
|
169
|
+
</div>
|
|
170
|
+
<div class="mt-2 flex gap-2">
|
|
171
|
+
<ef-controls target="vertical-demo">
|
|
172
|
+
<ef-toggle-play class="px-3 py-1 bg-blue-600 text-white rounded"></ef-toggle-play>
|
|
173
|
+
</ef-controls>
|
|
174
|
+
</div>
|
|
175
|
+
```
|
|
176
|
+
<!-- /html-only -->
|
|
177
|
+
<!-- react-only -->
|
|
178
|
+
Use vertical orientation for timeline views:
|
|
179
|
+
|
|
180
|
+
```tsx
|
|
181
|
+
<Scrubber
|
|
182
|
+
orientation="vertical"
|
|
183
|
+
className="w-full h-full"
|
|
184
|
+
/>
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Vertical scrubbers are typically used in filmstrip/timeline views where the playhead moves vertically.
|
|
188
|
+
<!-- /react-only -->
|
|
189
|
+
|
|
190
|
+
## Frame Snapping
|
|
191
|
+
|
|
192
|
+
When `fps` is set, scrubbing snaps to frame boundaries.
|
|
193
|
+
|
|
194
|
+
<!-- html-only -->
|
|
195
|
+
```html live
|
|
196
|
+
<ef-timegroup mode="contain" class="w-[720px] h-[480px] bg-black" id="snap-demo" fps="30">
|
|
197
|
+
<ef-video src="https://assets.editframe.com/bars-n-tone.mp4" class="size-full object-contain"></ef-video>
|
|
198
|
+
</ef-timegroup>
|
|
199
|
+
<div class="flex flex-col gap-2 p-4 bg-gray-900 rounded-lg mt-4">
|
|
200
|
+
<div class="text-white text-sm mb-2">Scrubbing snaps to 30fps frame boundaries:</div>
|
|
201
|
+
<ef-scrubber target="snap-demo" fps="30"></ef-scrubber>
|
|
202
|
+
<ef-controls target="snap-demo" class="flex gap-2 items-center">
|
|
203
|
+
<ef-toggle-play class="px-3 py-1 bg-blue-600 text-white rounded"></ef-toggle-play>
|
|
204
|
+
<ef-time-display class="text-white text-sm"></ef-time-display>
|
|
205
|
+
</ef-controls>
|
|
206
|
+
</div>
|
|
207
|
+
```
|
|
208
|
+
<!-- /html-only -->
|
|
209
|
+
<!-- react-only -->
|
|
210
|
+
Enable frame-accurate seeking:
|
|
211
|
+
|
|
212
|
+
```tsx
|
|
213
|
+
<Scrubber
|
|
214
|
+
fps={30}
|
|
215
|
+
className="w-full h-2"
|
|
216
|
+
/>
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
When `fps` is provided, the scrubber snaps to frame boundaries during seeking.
|
|
220
|
+
<!-- /react-only -->
|
|
221
|
+
|
|
222
|
+
## Custom Styling
|
|
223
|
+
|
|
224
|
+
<!-- html-only -->
|
|
225
|
+
### CSS Parts
|
|
226
|
+
|
|
227
|
+
Style scrubber appearance using `::part()` selectors.
|
|
228
|
+
|
|
229
|
+
```html live
|
|
230
|
+
<ef-timegroup mode="contain" class="w-[720px] h-[480px] bg-black" id="styled-scrubber">
|
|
231
|
+
<ef-video src="https://assets.editframe.com/bars-n-tone.mp4" class="size-full object-contain"></ef-video>
|
|
232
|
+
</ef-timegroup>
|
|
233
|
+
<div class="flex flex-col gap-2 p-4 bg-gray-900 rounded-lg mt-4">
|
|
234
|
+
<ef-scrubber target="styled-scrubber" id="custom-scrubber"></ef-scrubber>
|
|
235
|
+
<ef-controls target="styled-scrubber" class="flex gap-2 items-center">
|
|
236
|
+
<ef-toggle-play class="px-3 py-1 bg-blue-600 text-white rounded"></ef-toggle-play>
|
|
237
|
+
<ef-time-display class="text-white text-sm"></ef-time-display>
|
|
238
|
+
</ef-controls>
|
|
239
|
+
</div>
|
|
240
|
+
|
|
241
|
+
<style>
|
|
242
|
+
#custom-scrubber::part(scrubber) {
|
|
243
|
+
background: linear-gradient(to right, #1e293b, #334155);
|
|
244
|
+
height: 8px;
|
|
245
|
+
border-radius: 4px;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
#custom-scrubber::part(progress) {
|
|
249
|
+
background: linear-gradient(to right, #3b82f6, #8b5cf6);
|
|
250
|
+
border-radius: 4px;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
#custom-scrubber::part(handle) {
|
|
254
|
+
width: 16px;
|
|
255
|
+
height: 16px;
|
|
256
|
+
background: white;
|
|
257
|
+
box-shadow: 0 2px 4px rgba(0,0,0,0.3);
|
|
258
|
+
}
|
|
259
|
+
</style>
|
|
260
|
+
```
|
|
261
|
+
<!-- /html-only -->
|
|
262
|
+
<!-- react-only -->
|
|
263
|
+
Style the scrubber track and handle:
|
|
264
|
+
|
|
265
|
+
```tsx
|
|
266
|
+
<Scrubber
|
|
267
|
+
className="w-full h-1.5 bg-white/20 rounded-full cursor-pointer"
|
|
268
|
+
/>
|
|
269
|
+
```
|
|
270
|
+
<!-- /react-only -->
|
|
271
|
+
|
|
272
|
+
## CSS Custom Properties
|
|
273
|
+
|
|
274
|
+
Control scrubber appearance through CSS variables:
|
|
275
|
+
|
|
276
|
+
<!-- html-only -->
|
|
277
|
+
```css
|
|
278
|
+
ef-scrubber {
|
|
279
|
+
--ef-scrubber-height: 4px;
|
|
280
|
+
--ef-scrubber-background: rgba(255, 255, 255, 0.2);
|
|
281
|
+
--ef-scrubber-progress-color: #fff;
|
|
282
|
+
--ef-scrubber-handle-size: 12px;
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
<!-- /html-only -->
|
|
286
|
+
<!-- react-only -->
|
|
287
|
+
```tsx
|
|
288
|
+
<Scrubber
|
|
289
|
+
className="w-full"
|
|
290
|
+
style={{
|
|
291
|
+
'--ef-scrubber-height': '6px',
|
|
292
|
+
'--ef-scrubber-background': 'rgba(255, 255, 255, 0.2)',
|
|
293
|
+
'--ef-scrubber-progress-color': '#3b82f6',
|
|
294
|
+
'--ef-scrubber-handle-size': '16px',
|
|
295
|
+
} as React.CSSProperties}
|
|
296
|
+
/>
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### Available CSS Variables
|
|
300
|
+
|
|
301
|
+
| Variable | Default | Description |
|
|
302
|
+
|----------|---------|-------------|
|
|
303
|
+
| `--ef-scrubber-height` | `4px` | Track height |
|
|
304
|
+
| `--ef-scrubber-background` | `rgba(255, 255, 255, 0.2)` | Track background color |
|
|
305
|
+
| `--ef-scrubber-progress-color` | `#fff` | Progress bar and handle color |
|
|
306
|
+
| `--ef-scrubber-handle-size` | `12px` | Handle diameter |
|
|
307
|
+
<!-- /react-only -->
|
|
308
|
+
|
|
309
|
+
<!-- react-only -->
|
|
310
|
+
## CSS Shadow Parts
|
|
311
|
+
|
|
312
|
+
Style internal elements using `::part()`:
|
|
313
|
+
|
|
314
|
+
```tsx
|
|
315
|
+
<Scrubber
|
|
316
|
+
className={`
|
|
317
|
+
w-full h-1.5 bg-white/20 rounded-full cursor-pointer
|
|
318
|
+
[&::part(progress)]:bg-red-500
|
|
319
|
+
[&::part(progress)]:rounded-full
|
|
320
|
+
[&::part(handle)]:bg-white
|
|
321
|
+
[&::part(handle)]:w-3
|
|
322
|
+
[&::part(handle)]:h-3
|
|
323
|
+
[&::part(handle)]:rounded-full
|
|
324
|
+
[&::part(handle)]:shadow-lg
|
|
325
|
+
`}
|
|
326
|
+
/>
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
### Available Parts
|
|
330
|
+
|
|
331
|
+
| Part | Description |
|
|
332
|
+
|------|-------------|
|
|
333
|
+
| `scrubber` | The track container |
|
|
334
|
+
| `progress` | The filled progress bar |
|
|
335
|
+
| `handle` | The draggable seek handle |
|
|
336
|
+
<!-- /react-only -->
|
|
337
|
+
|
|
338
|
+
## Seek Events
|
|
339
|
+
|
|
340
|
+
<!-- html-only -->
|
|
341
|
+
```html
|
|
342
|
+
<ef-scrubber target="my-video" id="my-scrubber"></ef-scrubber>
|
|
343
|
+
|
|
344
|
+
<script>
|
|
345
|
+
const scrubber = document.getElementById('my-scrubber');
|
|
346
|
+
scrubber.addEventListener('seek', (e) => {
|
|
347
|
+
console.log('Seeking to:', e.detail, 'ms');
|
|
348
|
+
});
|
|
349
|
+
</script>
|
|
350
|
+
```
|
|
351
|
+
<!-- /html-only -->
|
|
352
|
+
<!-- react-only -->
|
|
353
|
+
Listen to seek events:
|
|
354
|
+
|
|
355
|
+
```tsx
|
|
356
|
+
import { Scrubber } from "@editframe/react";
|
|
357
|
+
|
|
358
|
+
<Scrubber
|
|
359
|
+
onSeek={(time) => {
|
|
360
|
+
console.log('Seeking to:', time, 'ms');
|
|
361
|
+
}}
|
|
362
|
+
className="w-full h-2"
|
|
363
|
+
/>
|
|
364
|
+
```
|
|
365
|
+
<!-- /react-only -->
|
|
366
|
+
|
|
367
|
+
<!-- react-only -->
|
|
368
|
+
## With Timeline Sync
|
|
369
|
+
|
|
370
|
+
Sync scrubber with a scrollable timeline:
|
|
371
|
+
|
|
372
|
+
```tsx
|
|
373
|
+
import { useRef, useState } from "react";
|
|
374
|
+
import { Scrubber } from "@editframe/react";
|
|
375
|
+
|
|
376
|
+
export const TimelineWithScrubber = () => {
|
|
377
|
+
const scrollContainerRef = useRef<HTMLDivElement>(null);
|
|
378
|
+
const isScrubbingRef = useRef(false);
|
|
379
|
+
const [zoomScale, setZoomScale] = useState(1);
|
|
380
|
+
|
|
381
|
+
return (
|
|
382
|
+
<div>
|
|
383
|
+
<div
|
|
384
|
+
ref={scrollContainerRef}
|
|
385
|
+
className="overflow-x-auto"
|
|
386
|
+
>
|
|
387
|
+
{/* Timeline content */}
|
|
388
|
+
</div>
|
|
389
|
+
|
|
390
|
+
<Scrubber
|
|
391
|
+
orientation="vertical"
|
|
392
|
+
zoomScale={zoomScale}
|
|
393
|
+
scrollContainerRef={scrollContainerRef}
|
|
394
|
+
isScrubbingRef={isScrubbingRef}
|
|
395
|
+
className="w-full h-full"
|
|
396
|
+
/>
|
|
397
|
+
</div>
|
|
398
|
+
);
|
|
399
|
+
};
|
|
400
|
+
```
|
|
401
|
+
<!-- /react-only -->
|
|
402
|
+
|
|
403
|
+
<!-- react-only -->
|
|
404
|
+
## TypeScript Types
|
|
405
|
+
|
|
406
|
+
```tsx
|
|
407
|
+
import type { ScrubberProps } from "@editframe/react";
|
|
408
|
+
|
|
409
|
+
const scrubberConfig: ScrubberProps = {
|
|
410
|
+
orientation: "horizontal",
|
|
411
|
+
zoomScale: 1.5,
|
|
412
|
+
fps: 30,
|
|
413
|
+
className: "w-full h-2",
|
|
414
|
+
onSeek: (time) => console.log(time),
|
|
415
|
+
};
|
|
416
|
+
```
|
|
417
|
+
<!-- /react-only -->
|
|
418
|
+
|
|
419
|
+
<!-- react-only -->
|
|
420
|
+
## Styled Examples
|
|
421
|
+
|
|
422
|
+
### Gradient Progress
|
|
423
|
+
|
|
424
|
+
```tsx
|
|
425
|
+
<Scrubber
|
|
426
|
+
className="w-full h-2"
|
|
427
|
+
style={{
|
|
428
|
+
'--ef-scrubber-background': 'rgba(0, 0, 0, 0.2)',
|
|
429
|
+
'--ef-scrubber-progress-color': 'linear-gradient(to right, #3b82f6, #8b5cf6)',
|
|
430
|
+
} as React.CSSProperties}
|
|
431
|
+
/>
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
### Large Handle
|
|
435
|
+
|
|
436
|
+
```tsx
|
|
437
|
+
<Scrubber
|
|
438
|
+
className="w-full h-3"
|
|
439
|
+
style={{
|
|
440
|
+
'--ef-scrubber-height': '12px',
|
|
441
|
+
'--ef-scrubber-handle-size': '20px',
|
|
442
|
+
'--ef-scrubber-progress-color': '#10b981',
|
|
443
|
+
} as React.CSSProperties}
|
|
444
|
+
/>
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
### Minimal Scrubber
|
|
448
|
+
|
|
449
|
+
```tsx
|
|
450
|
+
<Scrubber
|
|
451
|
+
className="w-full h-0.5"
|
|
452
|
+
style={{
|
|
453
|
+
'--ef-scrubber-height': '2px',
|
|
454
|
+
'--ef-scrubber-handle-size': '0px',
|
|
455
|
+
'--ef-scrubber-background': 'transparent',
|
|
456
|
+
'--ef-scrubber-progress-color': '#ef4444',
|
|
457
|
+
} as React.CSSProperties}
|
|
458
|
+
/>
|
|
459
|
+
```
|
|
460
|
+
<!-- /react-only -->
|
|
461
|
+
|
|
462
|
+
<!-- react-only -->
|
|
463
|
+
## Full Editor Example
|
|
464
|
+
|
|
465
|
+
Complete video editor with styled scrubber:
|
|
466
|
+
|
|
467
|
+
```tsx
|
|
468
|
+
import {
|
|
469
|
+
Preview,
|
|
470
|
+
TogglePlay,
|
|
471
|
+
ToggleLoop,
|
|
472
|
+
Scrubber,
|
|
473
|
+
TimeDisplay,
|
|
474
|
+
} from "@editframe/react";
|
|
475
|
+
|
|
476
|
+
export const VideoEditor = () => {
|
|
477
|
+
return (
|
|
478
|
+
<div className="h-screen flex flex-col bg-gray-900">
|
|
479
|
+
<div className="flex-1 flex items-center justify-center p-8">
|
|
480
|
+
<Preview className="w-full max-w-[1280px] aspect-video bg-black rounded-lg" />
|
|
481
|
+
</div>
|
|
482
|
+
|
|
483
|
+
<div className="bg-gray-800 border-t border-gray-700">
|
|
484
|
+
<div className="flex items-center gap-4 px-6 py-3">
|
|
485
|
+
<TogglePlay>
|
|
486
|
+
<button slot="play" className="w-8 h-8 text-white hover:text-blue-400">
|
|
487
|
+
▶
|
|
488
|
+
</button>
|
|
489
|
+
<button slot="pause" className="w-8 h-8 text-white hover:text-gray-400">
|
|
490
|
+
⏸
|
|
491
|
+
</button>
|
|
492
|
+
</TogglePlay>
|
|
493
|
+
|
|
494
|
+
<TimeDisplay className="text-white text-sm font-mono min-w-[120px]" />
|
|
495
|
+
|
|
496
|
+
<div className="flex-1">
|
|
497
|
+
<Scrubber
|
|
498
|
+
className="w-full"
|
|
499
|
+
style={{
|
|
500
|
+
'--ef-scrubber-height': '6px',
|
|
501
|
+
'--ef-scrubber-background': 'rgba(255, 255, 255, 0.15)',
|
|
502
|
+
'--ef-scrubber-progress-color': '#3b82f6',
|
|
503
|
+
'--ef-scrubber-handle-size': '14px',
|
|
504
|
+
} as React.CSSProperties}
|
|
505
|
+
/>
|
|
506
|
+
</div>
|
|
507
|
+
|
|
508
|
+
<ToggleLoop>
|
|
509
|
+
<button slot="off" className="w-8 h-8 text-gray-400 hover:text-white">
|
|
510
|
+
🔁
|
|
511
|
+
</button>
|
|
512
|
+
<button slot="on" className="w-8 h-8 text-green-400 hover:text-green-300">
|
|
513
|
+
🔁
|
|
514
|
+
</button>
|
|
515
|
+
</ToggleLoop>
|
|
516
|
+
</div>
|
|
517
|
+
</div>
|
|
518
|
+
</div>
|
|
519
|
+
);
|
|
520
|
+
};
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
## Minimal Controls
|
|
524
|
+
|
|
525
|
+
Compact control layout:
|
|
526
|
+
|
|
527
|
+
```tsx
|
|
528
|
+
<div className="flex items-center gap-2 p-2 bg-black/80 rounded">
|
|
529
|
+
<TogglePlay className="w-6 h-6 text-white">
|
|
530
|
+
<button slot="play">▶</button>
|
|
531
|
+
<button slot="pause">⏸</button>
|
|
532
|
+
</TogglePlay>
|
|
533
|
+
<Scrubber className="flex-1 h-1" />
|
|
534
|
+
</div>
|
|
535
|
+
```
|
|
536
|
+
<!-- /react-only -->
|
|
537
|
+
|
|
538
|
+
## Usage Modes
|
|
539
|
+
|
|
540
|
+
**Horizontal mode** — Compact progress bar for playback controls:
|
|
541
|
+
- Shows progress fill and draggable handle
|
|
542
|
+
- Best for control panels and compact UIs
|
|
543
|
+
- Automatically reads duration from context
|
|
544
|
+
|
|
545
|
+
**Vertical mode** — Timeline scrubber for editing:
|
|
546
|
+
- Shows vertical playhead line
|
|
547
|
+
<!-- html-only -->
|
|
548
|
+
- Requires `zoom-scale` for proper positioning
|
|
549
|
+
- Used internally by `ef-timeline` and `ef-filmstrip`
|
|
550
|
+
<!-- /html-only -->
|
|
551
|
+
<!-- react-only -->
|
|
552
|
+
- Requires `zoomScale` for proper positioning
|
|
553
|
+
- Used internally by Timeline and Filmstrip components
|
|
554
|
+
<!-- /react-only -->
|
|
555
|
+
- Supports scrollable timelines with edge detection
|
|
556
|
+
|
|
557
|
+
## Interaction
|
|
558
|
+
|
|
559
|
+
The scrubber supports:
|
|
560
|
+
- **Click:** Jump to position
|
|
561
|
+
- **Drag:** Scrub through timeline
|
|
562
|
+
- **Touch:** Mobile-friendly touch controls
|
|
563
|
+
|
|
564
|
+
All interactions automatically update the connected timeline's playback position.
|
|
565
|
+
|
|
566
|
+
## Accessibility
|
|
567
|
+
|
|
568
|
+
The scrubber is keyboard accessible and supports:
|
|
569
|
+
- Click to seek
|
|
570
|
+
- Drag to scrub
|
|
571
|
+
- Touch gestures on mobile devices
|
|
572
|
+
|
|
573
|
+
For enhanced accessibility, consider wrapping in a labeled container:
|
|
574
|
+
|
|
575
|
+
<!-- html-only -->
|
|
576
|
+
```html
|
|
577
|
+
<div role="group" aria-label="Video scrubber">
|
|
578
|
+
<ef-scrubber target="my-video"></ef-scrubber>
|
|
579
|
+
</div>
|
|
580
|
+
```
|
|
581
|
+
<!-- /html-only -->
|
|
582
|
+
<!-- react-only -->
|
|
583
|
+
```tsx
|
|
584
|
+
<div role="group" aria-label="Video scrubber">
|
|
585
|
+
<Scrubber className="w-full h-2" />
|
|
586
|
+
</div>
|
|
587
|
+
```
|
|
588
|
+
<!-- /react-only -->
|