@editframe/create 0.44.0 → 0.45.1
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/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 +1 -1
- package/tsdown.config.ts +4 -0
- package/dist/detectAgent.js +0 -89
- package/dist/detectAgent.js.map +0 -1
|
@@ -0,0 +1,634 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Overlay Item Element
|
|
3
|
+
description: Individual overlay element that tracks a specific composition element, following its position and size during playback.
|
|
4
|
+
type: reference
|
|
5
|
+
nav:
|
|
6
|
+
parent: "Overlay System"
|
|
7
|
+
priority: 11
|
|
8
|
+
api:
|
|
9
|
+
attributes:
|
|
10
|
+
- name: element-id
|
|
11
|
+
type: string
|
|
12
|
+
description: Element ID to track (searches data-element-id or data-timegroup-id)
|
|
13
|
+
- name: target
|
|
14
|
+
type: "string | HTMLElement"
|
|
15
|
+
description: CSS selector or element reference to track
|
|
16
|
+
events:
|
|
17
|
+
- name: position-changed
|
|
18
|
+
detail: "OverlayItemPosition"
|
|
19
|
+
description: Fired when overlay position updates
|
|
20
|
+
types:
|
|
21
|
+
- name: OverlayItemPosition
|
|
22
|
+
type: interface
|
|
23
|
+
definition: |
|
|
24
|
+
interface OverlayItemPosition {
|
|
25
|
+
x: number; // Left position relative to overlay layer
|
|
26
|
+
y: number; // Top position relative to overlay layer
|
|
27
|
+
width: number; // Width matching target element
|
|
28
|
+
height: number; // Height matching target element
|
|
29
|
+
rotation: number; // Rotation in degrees (parsed from transform)
|
|
30
|
+
}
|
|
31
|
+
methods:
|
|
32
|
+
- name: updatePosition()
|
|
33
|
+
signature: "updatePosition(): void"
|
|
34
|
+
description: Update position based on target element (called by parent layer)
|
|
35
|
+
react:
|
|
36
|
+
generate: true
|
|
37
|
+
componentName: OverlayItem
|
|
38
|
+
importPath: "@editframe/react"
|
|
39
|
+
propMapping:
|
|
40
|
+
element-id: elementId
|
|
41
|
+
position-changed: onPositionChanged
|
|
42
|
+
additionalProps:
|
|
43
|
+
- name: className
|
|
44
|
+
type: string
|
|
45
|
+
description: CSS classes for styling
|
|
46
|
+
- name: children
|
|
47
|
+
type: ReactNode
|
|
48
|
+
description: Content to render in the overlay
|
|
49
|
+
nav:
|
|
50
|
+
parent: "Components / Overlay System"
|
|
51
|
+
priority: 51
|
|
52
|
+
related: ["overlay-layer", "transform-handles"]
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
<!-- html-only -->
|
|
56
|
+
# ef-overlay-item
|
|
57
|
+
<!-- /html-only -->
|
|
58
|
+
<!-- react-only -->
|
|
59
|
+
# OverlayItem
|
|
60
|
+
<!-- /react-only -->
|
|
61
|
+
|
|
62
|
+
Individual overlay that tracks and follows a target element's position.
|
|
63
|
+
|
|
64
|
+
<!-- react-only -->
|
|
65
|
+
## Import
|
|
66
|
+
|
|
67
|
+
```tsx
|
|
68
|
+
import { OverlayItem } from "@editframe/react";
|
|
69
|
+
import type { OverlayItemProps } from "@editframe/react";
|
|
70
|
+
```
|
|
71
|
+
<!-- /react-only -->
|
|
72
|
+
|
|
73
|
+
## Basic Usage
|
|
74
|
+
|
|
75
|
+
<!-- html-only -->
|
|
76
|
+
Track an element with an overlay:
|
|
77
|
+
|
|
78
|
+
```html live
|
|
79
|
+
<div class="relative w-[600px] h-[400px] border border-gray-300 rounded overflow-hidden">
|
|
80
|
+
<ef-overlay-layer class="absolute inset-0 pointer-events-none">
|
|
81
|
+
<ef-overlay-item target="#box-1" class="border-2 border-blue-500 pointer-events-auto">
|
|
82
|
+
<div class="absolute -top-6 left-0 bg-blue-500 text-white text-xs px-2 py-1 rounded whitespace-nowrap">
|
|
83
|
+
Selected Box
|
|
84
|
+
</div>
|
|
85
|
+
</ef-overlay-item>
|
|
86
|
+
</ef-overlay-layer>
|
|
87
|
+
|
|
88
|
+
<div id="box-1" class="absolute top-12 left-12 w-40 h-32 bg-blue-100 border-2 border-blue-300 rounded"></div>
|
|
89
|
+
<div id="box-2" class="absolute top-48 left-48 w-40 h-32 bg-green-100 border-2 border-green-300 rounded"></div>
|
|
90
|
+
</div>
|
|
91
|
+
```
|
|
92
|
+
<!-- /html-only -->
|
|
93
|
+
<!-- react-only -->
|
|
94
|
+
```tsx
|
|
95
|
+
import { OverlayLayer, OverlayItem, Timegroup, Video } from "@editframe/react";
|
|
96
|
+
|
|
97
|
+
export const App = () => {
|
|
98
|
+
return (
|
|
99
|
+
<div className="relative">
|
|
100
|
+
<OverlayLayer className="absolute inset-0">
|
|
101
|
+
<OverlayItem elementId="my-video">
|
|
102
|
+
<div className="border-2 border-blue-500" />
|
|
103
|
+
</OverlayItem>
|
|
104
|
+
</OverlayLayer>
|
|
105
|
+
|
|
106
|
+
<Timegroup mode="contain" className="w-[1920px] h-[1080px]">
|
|
107
|
+
<Video id="my-video" src="/assets/video.mp4" className="size-full" />
|
|
108
|
+
</Timegroup>
|
|
109
|
+
</div>
|
|
110
|
+
);
|
|
111
|
+
};
|
|
112
|
+
```
|
|
113
|
+
<!-- /react-only -->
|
|
114
|
+
|
|
115
|
+
## Target Selection
|
|
116
|
+
|
|
117
|
+
<!-- html-only -->
|
|
118
|
+
Overlay items support multiple ways to specify targets:
|
|
119
|
+
|
|
120
|
+
### CSS Selector
|
|
121
|
+
|
|
122
|
+
Use any valid CSS selector:
|
|
123
|
+
|
|
124
|
+
```html
|
|
125
|
+
<ef-overlay-item target="#my-element"></ef-overlay-item>
|
|
126
|
+
<ef-overlay-item target=".selected"></ef-overlay-item>
|
|
127
|
+
<ef-overlay-item target="ef-video[src*='intro']"></ef-overlay-item>
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Element Reference
|
|
131
|
+
|
|
132
|
+
Pass element directly via JavaScript:
|
|
133
|
+
|
|
134
|
+
```javascript
|
|
135
|
+
const overlay = document.querySelector('ef-overlay-item');
|
|
136
|
+
const element = document.getElementById('my-element');
|
|
137
|
+
overlay.target = element;
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Element ID Attribute
|
|
141
|
+
|
|
142
|
+
Use element-id for canvas elements with data attributes:
|
|
143
|
+
|
|
144
|
+
```html
|
|
145
|
+
<ef-canvas>
|
|
146
|
+
<div data-element-id="element-1"></div>
|
|
147
|
+
<ef-timegroup data-timegroup-id="group-1"></ef-timegroup>
|
|
148
|
+
</ef-canvas>
|
|
149
|
+
|
|
150
|
+
<ef-overlay-layer>
|
|
151
|
+
<ef-overlay-item element-id="element-1"></ef-overlay-item>
|
|
152
|
+
<ef-overlay-item element-id="group-1"></ef-overlay-item>
|
|
153
|
+
</ef-overlay-layer>
|
|
154
|
+
```
|
|
155
|
+
<!-- /html-only -->
|
|
156
|
+
<!-- react-only -->
|
|
157
|
+
### By Element ID
|
|
158
|
+
|
|
159
|
+
Use `elementId` for Editframe elements with data attributes:
|
|
160
|
+
|
|
161
|
+
```tsx
|
|
162
|
+
<OverlayItem elementId="my-video">
|
|
163
|
+
<div className="border-2 border-blue-500" />
|
|
164
|
+
</OverlayItem>
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Custom Target Selector
|
|
168
|
+
|
|
169
|
+
```tsx
|
|
170
|
+
import { OverlayItem } from "@editframe/react";
|
|
171
|
+
|
|
172
|
+
export const CustomTarget = () => {
|
|
173
|
+
return (
|
|
174
|
+
<OverlayLayer className="absolute inset-0">
|
|
175
|
+
{/* Track by custom selector */}
|
|
176
|
+
<OverlayItem target=".my-custom-class">
|
|
177
|
+
<div className="border-2 border-red-500" />
|
|
178
|
+
</OverlayItem>
|
|
179
|
+
|
|
180
|
+
{/* Track by direct element reference */}
|
|
181
|
+
<OverlayItem target={elementRef.current}>
|
|
182
|
+
<div className="border-2 border-green-500" />
|
|
183
|
+
</OverlayItem>
|
|
184
|
+
</OverlayLayer>
|
|
185
|
+
);
|
|
186
|
+
};
|
|
187
|
+
```
|
|
188
|
+
<!-- /react-only -->
|
|
189
|
+
|
|
190
|
+
## Overlay Content
|
|
191
|
+
|
|
192
|
+
<!-- html-only -->
|
|
193
|
+
Add any content inside the overlay item:
|
|
194
|
+
|
|
195
|
+
### Selection Border
|
|
196
|
+
|
|
197
|
+
```html
|
|
198
|
+
<ef-overlay-item target="#element" class="border-2 border-blue-500 rounded"></ef-overlay-item>
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Labels and Badges
|
|
202
|
+
|
|
203
|
+
```html live
|
|
204
|
+
<div class="relative w-[600px] h-[400px] border border-gray-300 rounded overflow-hidden bg-gray-50">
|
|
205
|
+
<ef-overlay-layer class="absolute inset-0 pointer-events-none">
|
|
206
|
+
<ef-overlay-item target="#video-element" class="pointer-events-none">
|
|
207
|
+
<div class="absolute -top-7 left-0 bg-purple-600 text-white text-xs px-2 py-1 rounded-t flex items-center gap-1">
|
|
208
|
+
<svg class="w-3 h-3" fill="currentColor" viewBox="0 0 20 20">
|
|
209
|
+
<path d="M2 6a2 2 0 012-2h6a2 2 0 012 2v8a2 2 0 01-2 2H4a2 2 0 01-2-2V6zm12.553 1.106A1 1 0 0014 8v4a1 1 0 00.553.894l2 1A1 1 0 0018 13V7a1 1 0 00-1.447-.894l-2 1z" />
|
|
210
|
+
</svg>
|
|
211
|
+
Video
|
|
212
|
+
</div>
|
|
213
|
+
<div class="absolute -bottom-6 right-0 bg-gray-800 text-white text-xs px-2 py-1 rounded">
|
|
214
|
+
320x240
|
|
215
|
+
</div>
|
|
216
|
+
</ef-overlay-item>
|
|
217
|
+
</ef-overlay-layer>
|
|
218
|
+
|
|
219
|
+
<div id="video-element" class="absolute top-16 left-16 w-64 h-48 bg-black rounded shadow-lg flex items-center justify-center text-gray-400">
|
|
220
|
+
Video Player
|
|
221
|
+
</div>
|
|
222
|
+
</div>
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### Handles and Controls
|
|
226
|
+
|
|
227
|
+
```html
|
|
228
|
+
<ef-overlay-item target="#element" class="pointer-events-auto">
|
|
229
|
+
<button class="absolute top-0 right-0 w-4 h-4 bg-blue-500 rounded-full -mt-2 -mr-2"></button>
|
|
230
|
+
<button class="absolute bottom-0 right-0 w-4 h-4 bg-blue-500 rounded-full -mb-2 -mr-2"></button>
|
|
231
|
+
</ef-overlay-item>
|
|
232
|
+
```
|
|
233
|
+
<!-- /html-only -->
|
|
234
|
+
<!-- react-only -->
|
|
235
|
+
### Selection Highlight
|
|
236
|
+
|
|
237
|
+
```tsx
|
|
238
|
+
import { OverlayLayer, OverlayItem } from "@editframe/react";
|
|
239
|
+
|
|
240
|
+
export const SelectionHighlight = () => {
|
|
241
|
+
const [selectedId, setSelectedId] = useState<string | null>("video-1");
|
|
242
|
+
|
|
243
|
+
return (
|
|
244
|
+
<div className="relative">
|
|
245
|
+
<OverlayLayer className="absolute inset-0">
|
|
246
|
+
{selectedId && (
|
|
247
|
+
<OverlayItem elementId={selectedId}>
|
|
248
|
+
<div className="border-2 border-blue-500 bg-blue-500/10">
|
|
249
|
+
<div className="absolute -top-6 left-0 bg-blue-500 text-white px-2 py-1 text-xs rounded">
|
|
250
|
+
Selected
|
|
251
|
+
</div>
|
|
252
|
+
</div>
|
|
253
|
+
</OverlayItem>
|
|
254
|
+
)}
|
|
255
|
+
</OverlayLayer>
|
|
256
|
+
|
|
257
|
+
<Timegroup mode="sequence" className="w-[1920px] h-[1080px]">
|
|
258
|
+
<Video
|
|
259
|
+
id="video-1"
|
|
260
|
+
src="/assets/video1.mp4"
|
|
261
|
+
onClick={() => setSelectedId("video-1")}
|
|
262
|
+
/>
|
|
263
|
+
<Video
|
|
264
|
+
id="video-2"
|
|
265
|
+
src="/assets/video2.mp4"
|
|
266
|
+
onClick={() => setSelectedId("video-2")}
|
|
267
|
+
/>
|
|
268
|
+
</Timegroup>
|
|
269
|
+
</div>
|
|
270
|
+
);
|
|
271
|
+
};
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### Multiple Overlays Per Element
|
|
275
|
+
|
|
276
|
+
```tsx
|
|
277
|
+
import { OverlayItem } from "@editframe/react";
|
|
278
|
+
|
|
279
|
+
export const MultipleOverlays = () => {
|
|
280
|
+
return (
|
|
281
|
+
<OverlayLayer className="absolute inset-0">
|
|
282
|
+
{/* Border highlight */}
|
|
283
|
+
<OverlayItem elementId="element-1">
|
|
284
|
+
<div className="border-2 border-blue-500" />
|
|
285
|
+
</OverlayItem>
|
|
286
|
+
|
|
287
|
+
{/* Label */}
|
|
288
|
+
<OverlayItem elementId="element-1">
|
|
289
|
+
<div className="absolute -top-8 left-0 bg-black text-white px-2 py-1 text-xs rounded">
|
|
290
|
+
Layer 1
|
|
291
|
+
</div>
|
|
292
|
+
</OverlayItem>
|
|
293
|
+
|
|
294
|
+
{/* Transform handles */}
|
|
295
|
+
<OverlayItem elementId="element-1">
|
|
296
|
+
<TransformHandles bounds={bounds} />
|
|
297
|
+
</OverlayItem>
|
|
298
|
+
</OverlayLayer>
|
|
299
|
+
);
|
|
300
|
+
};
|
|
301
|
+
```
|
|
302
|
+
<!-- /react-only -->
|
|
303
|
+
|
|
304
|
+
## Position Updates
|
|
305
|
+
|
|
306
|
+
<!-- html-only -->
|
|
307
|
+
Overlay items are updated by their parent layer's RAF loop:
|
|
308
|
+
|
|
309
|
+
```javascript
|
|
310
|
+
const overlay = document.querySelector('ef-overlay-item');
|
|
311
|
+
|
|
312
|
+
// Listen for position changes
|
|
313
|
+
overlay.addEventListener('position-changed', (e) => {
|
|
314
|
+
const { x, y, width, height, rotation } = e.detail;
|
|
315
|
+
console.log('Overlay moved to:', x, y);
|
|
316
|
+
console.log('Size:', width, height);
|
|
317
|
+
console.log('Rotation:', rotation);
|
|
318
|
+
});
|
|
319
|
+
```
|
|
320
|
+
<!-- /html-only -->
|
|
321
|
+
<!-- react-only -->
|
|
322
|
+
```tsx
|
|
323
|
+
import { OverlayItem } from "@editframe/react";
|
|
324
|
+
import type { OverlayItemPosition } from "@editframe/elements";
|
|
325
|
+
|
|
326
|
+
export const PositionTracker = () => {
|
|
327
|
+
const [position, setPosition] = useState<OverlayItemPosition | null>(null);
|
|
328
|
+
|
|
329
|
+
const handlePositionChange = (e: CustomEvent<OverlayItemPosition>) => {
|
|
330
|
+
setPosition(e.detail);
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
return (
|
|
334
|
+
<div className="relative">
|
|
335
|
+
<OverlayLayer className="absolute inset-0">
|
|
336
|
+
<OverlayItem
|
|
337
|
+
elementId="tracked-element"
|
|
338
|
+
onPositionChanged={handlePositionChange}
|
|
339
|
+
>
|
|
340
|
+
<div className="border-2 border-green-500">
|
|
341
|
+
{position && (
|
|
342
|
+
<div className="absolute -top-16 left-0 bg-black text-white p-2 text-xs font-mono">
|
|
343
|
+
x: {position.x.toFixed(0)}, y: {position.y.toFixed(0)}<br />
|
|
344
|
+
w: {position.width.toFixed(0)}, h: {position.height.toFixed(0)}<br />
|
|
345
|
+
rotation: {position.rotation.toFixed(1)}deg
|
|
346
|
+
</div>
|
|
347
|
+
)}
|
|
348
|
+
</div>
|
|
349
|
+
</OverlayItem>
|
|
350
|
+
</OverlayLayer>
|
|
351
|
+
|
|
352
|
+
<Timegroup mode="fixed" duration="5s" className="w-[1920px] h-[1080px]">
|
|
353
|
+
<Text
|
|
354
|
+
id="tracked-element"
|
|
355
|
+
duration="5s"
|
|
356
|
+
className="absolute"
|
|
357
|
+
style={{ transform: "rotate(15deg)" }}
|
|
358
|
+
>
|
|
359
|
+
Tracked Text
|
|
360
|
+
</Text>
|
|
361
|
+
</Timegroup>
|
|
362
|
+
</div>
|
|
363
|
+
);
|
|
364
|
+
};
|
|
365
|
+
```
|
|
366
|
+
<!-- /react-only -->
|
|
367
|
+
|
|
368
|
+
## Rotation Support
|
|
369
|
+
|
|
370
|
+
<!-- html-only -->
|
|
371
|
+
Overlay items automatically track element rotation:
|
|
372
|
+
|
|
373
|
+
```html live
|
|
374
|
+
<div class="relative w-[600px] h-[400px] border border-gray-300 rounded overflow-hidden bg-gray-50">
|
|
375
|
+
<ef-overlay-layer class="absolute inset-0 pointer-events-none">
|
|
376
|
+
<ef-overlay-item target="#rotated-box" class="border-2 border-red-500"></ef-overlay-item>
|
|
377
|
+
</ef-overlay-layer>
|
|
378
|
+
|
|
379
|
+
<div id="rotated-box" class="absolute top-24 left-24 w-40 h-32 bg-red-100 rounded shadow" style="transform: rotate(15deg)">
|
|
380
|
+
<div class="p-4 text-center">Rotated Element</div>
|
|
381
|
+
</div>
|
|
382
|
+
</div>
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
The overlay automatically rotates to match its target.
|
|
386
|
+
<!-- /html-only -->
|
|
387
|
+
<!-- react-only -->
|
|
388
|
+
Overlay items automatically track element rotation. The overlay rotates to match its target's transform.
|
|
389
|
+
<!-- /react-only -->
|
|
390
|
+
|
|
391
|
+
## Visibility
|
|
392
|
+
|
|
393
|
+
Overlay items automatically hide when target is not found:
|
|
394
|
+
|
|
395
|
+
<!-- html-only -->
|
|
396
|
+
```javascript
|
|
397
|
+
const overlay = document.querySelector('ef-overlay-item');
|
|
398
|
+
|
|
399
|
+
// Target exists - overlay visible
|
|
400
|
+
overlay.target = '#existing-element';
|
|
401
|
+
|
|
402
|
+
// Target not found - overlay hidden (display: none)
|
|
403
|
+
overlay.target = '#nonexistent-element';
|
|
404
|
+
|
|
405
|
+
// Target removed - overlay hidden
|
|
406
|
+
const element = document.getElementById('existing-element');
|
|
407
|
+
element.remove();
|
|
408
|
+
```
|
|
409
|
+
<!-- /html-only -->
|
|
410
|
+
<!-- react-only -->
|
|
411
|
+
- When `elementId` or `target` resolves to an element, the overlay is visible
|
|
412
|
+
- When the target element is not found or removed, the overlay hides automatically
|
|
413
|
+
- If the element is re-added to the DOM, the overlay reappears on the next frame
|
|
414
|
+
<!-- /react-only -->
|
|
415
|
+
|
|
416
|
+
## Pointer Events
|
|
417
|
+
|
|
418
|
+
<!-- html-only -->
|
|
419
|
+
Enable pointer events for interactive overlays:
|
|
420
|
+
|
|
421
|
+
```html
|
|
422
|
+
<ef-overlay-item target="#element" class="pointer-events-auto cursor-move">
|
|
423
|
+
<!-- Interactive content -->
|
|
424
|
+
</ef-overlay-item>
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
Overlay layer has `pointer-events: none`, so explicitly enable on items that need interaction.
|
|
428
|
+
<!-- /html-only -->
|
|
429
|
+
<!-- react-only -->
|
|
430
|
+
Parent OverlayLayer has `pointer-events: none` by default. Enable pointer events on individual items that need interaction by adding appropriate className.
|
|
431
|
+
<!-- /react-only -->
|
|
432
|
+
|
|
433
|
+
## Coordinate System
|
|
434
|
+
|
|
435
|
+
Overlay items use absolute positioning relative to their parent overlay layer:
|
|
436
|
+
|
|
437
|
+
- **x, y**: Top-left position in layer coordinates
|
|
438
|
+
- **width, height**: Match target element dimensions
|
|
439
|
+
- **rotation**: Parsed from target element's transform
|
|
440
|
+
|
|
441
|
+
The parent layer handles transform synchronization with pan/zoom.
|
|
442
|
+
|
|
443
|
+
## Update Frequency
|
|
444
|
+
|
|
445
|
+
Position updates happen every animation frame (60fps) via the parent layer's RAF loop. No throttling or change detection - updates are always fresh.
|
|
446
|
+
|
|
447
|
+
## Performance
|
|
448
|
+
|
|
449
|
+
Overlay items are passive - they don't run their own RAF loops. The parent layer manages all updates in a single synchronized loop, preventing RAF proliferation.
|
|
450
|
+
|
|
451
|
+
<!-- html-only -->
|
|
452
|
+
## Target Validation
|
|
453
|
+
|
|
454
|
+
Overlay items verify target is still in the DOM:
|
|
455
|
+
|
|
456
|
+
```javascript
|
|
457
|
+
const overlay = document.querySelector('ef-overlay-item');
|
|
458
|
+
const element = document.getElementById('my-element');
|
|
459
|
+
|
|
460
|
+
overlay.target = element; // Works - element in DOM
|
|
461
|
+
|
|
462
|
+
element.remove(); // Element removed
|
|
463
|
+
// Overlay automatically hides
|
|
464
|
+
|
|
465
|
+
document.body.appendChild(element); // Element re-added
|
|
466
|
+
// Overlay reappears on next frame
|
|
467
|
+
```
|
|
468
|
+
<!-- /html-only -->
|
|
469
|
+
|
|
470
|
+
## CSS Styling
|
|
471
|
+
|
|
472
|
+
<!-- html-only -->
|
|
473
|
+
Style the overlay item container:
|
|
474
|
+
|
|
475
|
+
```css
|
|
476
|
+
ef-overlay-item {
|
|
477
|
+
/* Border and background */
|
|
478
|
+
border: 2px solid blue;
|
|
479
|
+
background: rgba(0, 0, 255, 0.1);
|
|
480
|
+
|
|
481
|
+
/* Pointer interaction */
|
|
482
|
+
pointer-events: auto;
|
|
483
|
+
cursor: pointer;
|
|
484
|
+
|
|
485
|
+
/* Transform origin (rotation center) */
|
|
486
|
+
transform-origin: center;
|
|
487
|
+
}
|
|
488
|
+
```
|
|
489
|
+
<!-- /html-only -->
|
|
490
|
+
<!-- react-only -->
|
|
491
|
+
### Hover State Overlay
|
|
492
|
+
|
|
493
|
+
```tsx
|
|
494
|
+
import { OverlayLayer, OverlayItem } from "@editframe/react";
|
|
495
|
+
|
|
496
|
+
export const HoverOverlay = () => {
|
|
497
|
+
const [hoveredId, setHoveredId] = useState<string | null>(null);
|
|
498
|
+
|
|
499
|
+
return (
|
|
500
|
+
<div className="relative">
|
|
501
|
+
<OverlayLayer className="absolute inset-0 pointer-events-none">
|
|
502
|
+
{hoveredId && (
|
|
503
|
+
<OverlayItem elementId={hoveredId}>
|
|
504
|
+
<div className="border-2 border-yellow-500 bg-yellow-500/5" />
|
|
505
|
+
</OverlayItem>
|
|
506
|
+
)}
|
|
507
|
+
</OverlayLayer>
|
|
508
|
+
|
|
509
|
+
<Timegroup mode="sequence" className="w-[1920px] h-[1080px]">
|
|
510
|
+
<Video
|
|
511
|
+
id="video-1"
|
|
512
|
+
src="/assets/video1.mp4"
|
|
513
|
+
onMouseEnter={() => setHoveredId("video-1")}
|
|
514
|
+
onMouseLeave={() => setHoveredId(null)}
|
|
515
|
+
/>
|
|
516
|
+
<Video
|
|
517
|
+
id="video-2"
|
|
518
|
+
src="/assets/video2.mp4"
|
|
519
|
+
onMouseEnter={() => setHoveredId("video-2")}
|
|
520
|
+
onMouseLeave={() => setHoveredId(null)}
|
|
521
|
+
/>
|
|
522
|
+
</Timegroup>
|
|
523
|
+
</div>
|
|
524
|
+
);
|
|
525
|
+
};
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
### Styled Overlays
|
|
529
|
+
|
|
530
|
+
```tsx
|
|
531
|
+
import { OverlayItem } from "@editframe/react";
|
|
532
|
+
|
|
533
|
+
export const StyledOverlays = () => {
|
|
534
|
+
return (
|
|
535
|
+
<OverlayLayer className="absolute inset-0">
|
|
536
|
+
{/* Corner indicators */}
|
|
537
|
+
<OverlayItem elementId="element-1">
|
|
538
|
+
<div className="relative">
|
|
539
|
+
<div className="absolute top-0 left-0 w-4 h-4 border-l-2 border-t-2 border-blue-500" />
|
|
540
|
+
<div className="absolute top-0 right-0 w-4 h-4 border-r-2 border-t-2 border-blue-500" />
|
|
541
|
+
<div className="absolute bottom-0 left-0 w-4 h-4 border-l-2 border-b-2 border-blue-500" />
|
|
542
|
+
<div className="absolute bottom-0 right-0 w-4 h-4 border-r-2 border-b-2 border-blue-500" />
|
|
543
|
+
</div>
|
|
544
|
+
</OverlayItem>
|
|
545
|
+
|
|
546
|
+
{/* Glow effect */}
|
|
547
|
+
<OverlayItem elementId="element-2">
|
|
548
|
+
<div className="border-2 border-purple-500 shadow-lg shadow-purple-500/50" />
|
|
549
|
+
</OverlayItem>
|
|
550
|
+
</OverlayLayer>
|
|
551
|
+
);
|
|
552
|
+
};
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
## TypeScript Usage
|
|
556
|
+
|
|
557
|
+
```tsx
|
|
558
|
+
import { OverlayItem } from "@editframe/react";
|
|
559
|
+
import type { OverlayItemProps } from "@editframe/react";
|
|
560
|
+
import type { OverlayItemPosition } from "@editframe/elements";
|
|
561
|
+
|
|
562
|
+
interface CustomOverlayProps extends OverlayItemProps {
|
|
563
|
+
label?: string;
|
|
564
|
+
color?: string;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
export const CustomOverlay: React.FC<CustomOverlayProps> = ({
|
|
568
|
+
elementId,
|
|
569
|
+
label,
|
|
570
|
+
color = "blue",
|
|
571
|
+
...props
|
|
572
|
+
}) => {
|
|
573
|
+
const handlePositionChange = (e: CustomEvent<OverlayItemPosition>) => {
|
|
574
|
+
console.log("Position:", e.detail);
|
|
575
|
+
};
|
|
576
|
+
|
|
577
|
+
return (
|
|
578
|
+
<OverlayItem
|
|
579
|
+
elementId={elementId}
|
|
580
|
+
onPositionChanged={handlePositionChange}
|
|
581
|
+
{...props}
|
|
582
|
+
>
|
|
583
|
+
<div className={`border-2 border-${color}-500`}>
|
|
584
|
+
{label && (
|
|
585
|
+
<div className="absolute -top-6 left-0 bg-black text-white px-2 py-1 text-xs">
|
|
586
|
+
{label}
|
|
587
|
+
</div>
|
|
588
|
+
)}
|
|
589
|
+
</div>
|
|
590
|
+
</OverlayItem>
|
|
591
|
+
);
|
|
592
|
+
};
|
|
593
|
+
```
|
|
594
|
+
<!-- /react-only -->
|
|
595
|
+
|
|
596
|
+
## Position Change Event
|
|
597
|
+
|
|
598
|
+
<!-- html-only -->
|
|
599
|
+
The `position-changed` event provides:
|
|
600
|
+
<!-- /html-only -->
|
|
601
|
+
<!-- react-only -->
|
|
602
|
+
The `onPositionChanged` callback receives an event with this detail structure:
|
|
603
|
+
<!-- /react-only -->
|
|
604
|
+
|
|
605
|
+
```typescript
|
|
606
|
+
interface OverlayItemPosition {
|
|
607
|
+
x: number; // Left position relative to OverlayLayer
|
|
608
|
+
y: number; // Top position relative to OverlayLayer
|
|
609
|
+
width: number; // Element width
|
|
610
|
+
height: number; // Element height
|
|
611
|
+
rotation: number; // Element rotation in degrees
|
|
612
|
+
}
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
## Important Notes
|
|
616
|
+
|
|
617
|
+
<!-- html-only -->
|
|
618
|
+
- Must be a child of an ef-overlay-layer element
|
|
619
|
+
- Updates position continuously in sync with parent's RAF loop
|
|
620
|
+
- Automatically handles element rotation transforms
|
|
621
|
+
- Hidden when target element is not found
|
|
622
|
+
- Position is relative to the overlay layer container
|
|
623
|
+
- Use `element-id` for canvas elements with data attributes
|
|
624
|
+
- Use `target` for custom DOM elements
|
|
625
|
+
<!-- /html-only -->
|
|
626
|
+
<!-- react-only -->
|
|
627
|
+
- Must be a child of OverlayLayer component
|
|
628
|
+
- Updates position continuously in sync with parent's RAF loop
|
|
629
|
+
- Automatically handles element rotation transforms
|
|
630
|
+
- Hidden when target element is not found
|
|
631
|
+
- Position is relative to the OverlayLayer container
|
|
632
|
+
- Use `elementId` for Editframe elements with data attributes
|
|
633
|
+
- Use `target` prop for custom DOM elements
|
|
634
|
+
<!-- /react-only -->
|