@pixerate/editor-svelte 0.101.4 → 0.103.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/agentTools.svelte.d.ts +4 -2
- package/dist/agentTools.svelte.js +8 -1
- package/dist/animation-editor/AnimationEditor.svelte +35 -3
- package/dist/animation-editor/AnimationEditor.svelte.d.ts +10 -0
- package/dist/canvas/createCanvasPlaybackSurface.svelte.d.ts +30 -0
- package/dist/canvas/createCanvasPlaybackSurface.svelte.js +43 -0
- package/dist/canvas/index.d.ts +2 -0
- package/dist/canvas/index.js +4 -1
- package/dist/chart/ChartEditor.svelte +85 -4
- package/dist/chart/ChartEditor.svelte.d.ts +11 -0
- package/dist/image-editor/ImageEditor.svelte +91 -1
- package/dist/image-editor/ImageEditor.svelte.d.ts +10 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/paint-editor/PaintEditor.svelte +92 -10
- package/dist/paint-editor/PaintEditor.svelte.d.ts +12 -1
- package/dist/parameters/ParametersPanel.svelte +31 -2
- package/dist/parameters/ParametersPanel.svelte.d.ts +10 -0
- package/dist/playback/PresenceLayer.svelte +65 -0
- package/dist/playback/PresenceLayer.svelte.d.ts +22 -0
- package/dist/playback/index.d.ts +2 -0
- package/dist/playback/index.js +2 -0
- package/dist/playback/playback.svelte.d.ts +32 -0
- package/dist/playback/playback.svelte.js +91 -0
- package/dist/spreadsheet/SpreadsheetEditor.svelte +63 -3
- package/dist/spreadsheet/SpreadsheetEditor.svelte.d.ts +10 -0
- package/dist/vector/VectorCanvas.svelte +54 -1
- package/dist/vector/VectorCanvas.svelte.d.ts +10 -0
- package/dist/video-editor/VideoEditor.svelte +8 -3
- package/dist/video-editor/VideoEditor.svelte.d.ts +5 -0
- package/dist/video-editor/VideoTimeline.svelte +64 -2
- package/dist/video-editor/VideoTimeline.svelte.d.ts +10 -0
- package/package.json +2 -2
|
@@ -14,8 +14,12 @@
|
|
|
14
14
|
toVectorKeyInput,
|
|
15
15
|
toVectorPointerInput,
|
|
16
16
|
vectorDiamondPath,
|
|
17
|
+
createVectorPlaybackLocator,
|
|
17
18
|
type VectorEditorController
|
|
18
19
|
} from '@pixerate/editor/vector';
|
|
20
|
+
import type { AgentPlayback } from '@pixerate/editor/tools';
|
|
21
|
+
import { createPlaybackSurface, getAgentPlayback } from '../playback/playback.svelte.js';
|
|
22
|
+
import PresenceLayer from '../playback/PresenceLayer.svelte';
|
|
19
23
|
import VectorGradientDefs from './VectorGradientDefs.svelte';
|
|
20
24
|
import VectorFilterDefs from './VectorFilterDefs.svelte';
|
|
21
25
|
import VectorGradientAnnotator from './VectorGradientAnnotator.svelte';
|
|
@@ -39,6 +43,15 @@
|
|
|
39
43
|
style?: string;
|
|
40
44
|
/** Accessible label (default "Vector canvas"). */
|
|
41
45
|
'aria-label'?: string;
|
|
46
|
+
/**
|
|
47
|
+
* Agent playback: act out the vector commands' calls here with the agent's cursor (default:
|
|
48
|
+
* `setAgentPlayback` above; `null` turns it off).
|
|
49
|
+
*/
|
|
50
|
+
playback?: AgentPlayback | null;
|
|
51
|
+
/** The playback surface id (default `vector`, where the vector commands play). */
|
|
52
|
+
playbackId?: string;
|
|
53
|
+
/** Bring the canvas on screen (switch to its tab) before the agent acts. */
|
|
54
|
+
onplaybackreveal?: () => void | Promise<void>;
|
|
42
55
|
}
|
|
43
56
|
|
|
44
57
|
let {
|
|
@@ -50,7 +63,10 @@
|
|
|
50
63
|
idPrefix = `ve${++nextId}-`,
|
|
51
64
|
class: className = '',
|
|
52
65
|
style = '',
|
|
53
|
-
'aria-label': ariaLabel = 'Vector canvas'
|
|
66
|
+
'aria-label': ariaLabel = 'Vector canvas',
|
|
67
|
+
playback,
|
|
68
|
+
playbackId = 'vector',
|
|
69
|
+
onplaybackreveal
|
|
54
70
|
}: Props = $props();
|
|
55
71
|
|
|
56
72
|
const store = vectorStateOf(() => controller);
|
|
@@ -70,6 +86,35 @@
|
|
|
70
86
|
const as = THEME.anchorSize;
|
|
71
87
|
|
|
72
88
|
let svg: SVGSVGElement | undefined = $state();
|
|
89
|
+
|
|
90
|
+
// Agent playback: the agent's cursor in document units, drawn through the viewport.
|
|
91
|
+
const ambientPlayback = getAgentPlayback();
|
|
92
|
+
const playing = $derived((playback === undefined ? ambientPlayback : playback) ?? null);
|
|
93
|
+
const svgBox = () => svg?.getBoundingClientRect() ?? null;
|
|
94
|
+
const presence = createPlaybackSurface(() => playing, () => playbackId, () => ({
|
|
95
|
+
defaultKind: 'vector',
|
|
96
|
+
locate: createVectorPlaybackLocator(controller),
|
|
97
|
+
bounds: () => {
|
|
98
|
+
const r = svgBox();
|
|
99
|
+
const v = controller.getState().viewport;
|
|
100
|
+
return r && r.width > 0 ? { x: -v.x / v.zoom, y: -v.y / v.zoom, width: r.width / v.zoom, height: r.height / v.zoom } : null;
|
|
101
|
+
},
|
|
102
|
+
visible: () => {
|
|
103
|
+
const r = svgBox();
|
|
104
|
+
return !!r && r.width > 0 && r.height > 0 && !(typeof document !== 'undefined' && document.visibilityState === 'hidden');
|
|
105
|
+
},
|
|
106
|
+
toViewport: (p) => {
|
|
107
|
+
const r = svgBox();
|
|
108
|
+
const v = controller.getState().viewport;
|
|
109
|
+
return { x: (r?.left ?? 0) + p.x * v.zoom + v.x, y: (r?.top ?? 0) + p.y * v.zoom + v.y };
|
|
110
|
+
},
|
|
111
|
+
fromViewport: (p) => {
|
|
112
|
+
const r = svgBox();
|
|
113
|
+
const v = controller.getState().viewport;
|
|
114
|
+
return { x: (p.x - (r?.left ?? 0) - v.x) / v.zoom, y: (p.y - (r?.top ?? 0) - v.y) / v.zoom };
|
|
115
|
+
},
|
|
116
|
+
reveal: () => onplaybackreveal?.()
|
|
117
|
+
}));
|
|
73
118
|
$effect(() => {
|
|
74
119
|
const el = svg;
|
|
75
120
|
if (!el || typeof ResizeObserver === 'undefined') return;
|
|
@@ -611,4 +656,12 @@
|
|
|
611
656
|
{/key}
|
|
612
657
|
</foreignObject>
|
|
613
658
|
{/if}
|
|
659
|
+
{#if playing}
|
|
660
|
+
<!-- The agent's cursor (agent playback), over everything and never in the way. -->
|
|
661
|
+
<foreignObject data-vector-presence="" x="0" y="0" width="100%" height="100%" pointer-events="none" style="overflow:visible;pointer-events:none">
|
|
662
|
+
<div style="position:relative;width:100%;height:100%">
|
|
663
|
+
<PresenceLayer {presence} viewport={view.viewport} />
|
|
664
|
+
</div>
|
|
665
|
+
</foreignObject>
|
|
666
|
+
{/if}
|
|
614
667
|
</svg>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type VectorEditorController } from '@pixerate/editor/vector';
|
|
2
|
+
import type { AgentPlayback } from '@pixerate/editor/tools';
|
|
2
3
|
interface Props {
|
|
3
4
|
controller: VectorEditorController;
|
|
4
5
|
/** Fit the artboard into the canvas when it first gets a size (default `true`). */
|
|
@@ -15,6 +16,15 @@ interface Props {
|
|
|
15
16
|
style?: string;
|
|
16
17
|
/** Accessible label (default "Vector canvas"). */
|
|
17
18
|
'aria-label'?: string;
|
|
19
|
+
/**
|
|
20
|
+
* Agent playback: act out the vector commands' calls here with the agent's cursor (default:
|
|
21
|
+
* `setAgentPlayback` above; `null` turns it off).
|
|
22
|
+
*/
|
|
23
|
+
playback?: AgentPlayback | null;
|
|
24
|
+
/** The playback surface id (default `vector`, where the vector commands play). */
|
|
25
|
+
playbackId?: string;
|
|
26
|
+
/** Bring the canvas on screen (switch to its tab) before the agent acts. */
|
|
27
|
+
onplaybackreveal?: () => void | Promise<void>;
|
|
18
28
|
}
|
|
19
29
|
declare const VectorCanvas: import("svelte").Component<Props, {}, "">;
|
|
20
30
|
type VectorCanvas = ReturnType<typeof VectorCanvas>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import type { AgentPlayback } from '@pixerate/editor/tools';
|
|
2
3
|
import { onDestroy } from 'svelte';
|
|
3
4
|
import { VideoEditorController, type VideoEditorOptions } from '@pixerate/editor/video-editor';
|
|
4
5
|
import ClipInspector from './ClipInspector.svelte';
|
|
@@ -40,9 +41,13 @@
|
|
|
40
41
|
/** Show the effects panel (default: when a provider is given or the project has effects). */
|
|
41
42
|
showEffects?: boolean;
|
|
42
43
|
class?: string;
|
|
44
|
+
/** Agent playback on the timeline (see `<VideoTimeline playback>`; default: `setAgentPlayback` above). */
|
|
45
|
+
playback?: AgentPlayback | null;
|
|
46
|
+
/** Bring the editor on screen (switch to its tab) before the agent acts. */
|
|
47
|
+
onplaybackreveal?: () => void | Promise<void>;
|
|
43
48
|
}
|
|
44
49
|
|
|
45
|
-
let { controller, options, editable = true, pxPerSecond = $bindable(100), showIssues = true, showTranscript = true, showScopes = false, effects, showEffects, class: className = '' }: Props = $props();
|
|
50
|
+
let { controller, options, editable = true, pxPerSecond = $bindable(100), showIssues = true, showTranscript = true, showScopes = false, effects, showEffects, class: className = '', playback, onplaybackreveal }: Props = $props();
|
|
46
51
|
let owned: VideoEditorController | null = null;
|
|
47
52
|
// A controller is made only when none is passed, and kept for the component's lifetime.
|
|
48
53
|
const ctl = $derived(controller ?? (owned ??= new VideoEditorController(options)));
|
|
@@ -73,7 +78,7 @@
|
|
|
73
78
|
<VideoPreview controller={ctl} class="rounded-md" />
|
|
74
79
|
<VideoTransport controller={ctl} editable={false} />
|
|
75
80
|
{#if showScopes}<VideoScopes controller={ctl} />{/if}
|
|
76
|
-
<VideoTimeline controller={ctl} bind:pxPerSecond editable={false} />
|
|
81
|
+
<VideoTimeline controller={ctl} bind:pxPerSecond editable={false} {playback} {onplaybackreveal} />
|
|
77
82
|
{#if showTranscript}<TranscriptPanel controller={ctl} editable={false} />{/if}
|
|
78
83
|
{@render issueList()}
|
|
79
84
|
</div>
|
|
@@ -90,7 +95,7 @@
|
|
|
90
95
|
{#if effectsShown}<VideoEffectsPanel controller={ctl} class="min-w-0" />{/if}
|
|
91
96
|
</div>
|
|
92
97
|
<div class="flex min-w-0 flex-col gap-2 lg:col-span-3">
|
|
93
|
-
<VideoTimeline controller={ctl} bind:pxPerSecond />
|
|
98
|
+
<VideoTimeline controller={ctl} bind:pxPerSecond {playback} {onplaybackreveal} />
|
|
94
99
|
{#if showTranscript}<TranscriptPanel controller={ctl} />{/if}
|
|
95
100
|
{@render issueList()}
|
|
96
101
|
</div>
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { AgentPlayback } from '@pixerate/editor/tools';
|
|
1
2
|
import { VideoEditorController, type VideoEditorOptions } from '@pixerate/editor/video-editor';
|
|
2
3
|
import type { EffectProvider } from '@pixerate/editor/effects';
|
|
3
4
|
interface Props {
|
|
@@ -27,6 +28,10 @@ interface Props {
|
|
|
27
28
|
/** Show the effects panel (default: when a provider is given or the project has effects). */
|
|
28
29
|
showEffects?: boolean;
|
|
29
30
|
class?: string;
|
|
31
|
+
/** Agent playback on the timeline (see `<VideoTimeline playback>`; default: `setAgentPlayback` above). */
|
|
32
|
+
playback?: AgentPlayback | null;
|
|
33
|
+
/** Bring the editor on screen (switch to its tab) before the agent acts. */
|
|
34
|
+
onplaybackreveal?: () => void | Promise<void>;
|
|
30
35
|
}
|
|
31
36
|
declare const VideoEditor: import("svelte").Component<Props, {}, "pxPerSecond">;
|
|
32
37
|
type VideoEditor = ReturnType<typeof VideoEditor>;
|
|
@@ -20,7 +20,11 @@
|
|
|
20
20
|
type VideoMediaClip,
|
|
21
21
|
type VideoTrack,
|
|
22
22
|
type VideoWaveformMode,
|
|
23
|
+
parseVideoTimeRef,
|
|
23
24
|
} from '@pixerate/editor/video-editor';
|
|
25
|
+
import type { AgentPlayback, PlaybackRect, PlaybackRef } from '@pixerate/editor/tools';
|
|
26
|
+
import { createPlaybackSurface, getAgentPlayback } from '../playback/playback.svelte.js';
|
|
27
|
+
import PresenceLayer from '../playback/PresenceLayer.svelte';
|
|
24
28
|
import { onDestroy, untrack } from 'svelte';
|
|
25
29
|
import { videoEditorStateOf } from './createVideoEditor.svelte.js';
|
|
26
30
|
|
|
@@ -35,9 +39,18 @@
|
|
|
35
39
|
/** Draw waveforms in audio clips (default), in every clip with sound (`all`), or not at all. Sound is decoded once per asset through `controller.audioPeaks`. */
|
|
36
40
|
waveforms?: VideoWaveformMode;
|
|
37
41
|
class?: string;
|
|
42
|
+
/**
|
|
43
|
+
* Agent playback: act out the video tools' calls here with the agent's cursor (default:
|
|
44
|
+
* `setAgentPlayback` above; `null` turns it off).
|
|
45
|
+
*/
|
|
46
|
+
playback?: AgentPlayback | null;
|
|
47
|
+
/** The playback surface id (default `video`, where the video tool providers play). */
|
|
48
|
+
playbackId?: string;
|
|
49
|
+
/** Bring the timeline on screen (switch to its tab) before the agent acts. */
|
|
50
|
+
onplaybackreveal?: () => void | Promise<void>;
|
|
38
51
|
}
|
|
39
52
|
|
|
40
|
-
let { controller, pxPerSecond = $bindable(100), onpxpersecondchange, editable = true, waveforms = 'audio', class: className = '' }: Props = $props();
|
|
53
|
+
let { controller, pxPerSecond = $bindable(100), onpxpersecondchange, editable = true, waveforms = 'audio', class: className = '', playback, playbackId = 'video', onplaybackreveal }: Props = $props();
|
|
41
54
|
/** Bumped when more sound peaks have loaded, so waveforms redraw. */
|
|
42
55
|
let peaksVersion = $state(0);
|
|
43
56
|
$effect(() => controller.audioPeaks.subscribe(() => peaksVersion++));
|
|
@@ -90,6 +103,51 @@
|
|
|
90
103
|
const btn = 'rounded border border-border px-1.5 py-0.5 text-[11px] disabled:opacity-40';
|
|
91
104
|
|
|
92
105
|
let container: HTMLDivElement | undefined = $state();
|
|
106
|
+
|
|
107
|
+
// Agent playback: the agent's cursor in pixels of the timeline's box, finding clips, tracks and times.
|
|
108
|
+
const ambientPlayback = getAgentPlayback();
|
|
109
|
+
const playing = $derived((playback === undefined ? ambientPlayback : playback) ?? null);
|
|
110
|
+
const rectIn = (el: Element | null | undefined): PlaybackRect | null => {
|
|
111
|
+
const box = container?.getBoundingClientRect();
|
|
112
|
+
const r = el?.getBoundingClientRect();
|
|
113
|
+
return box && r && r.width > 0 ? { x: r.left - box.left, y: r.top - box.top, width: r.width, height: r.height } : null;
|
|
114
|
+
};
|
|
115
|
+
const q = (selector: string) => container?.querySelector(selector);
|
|
116
|
+
const agentPresence = createPlaybackSurface(() => playing, () => playbackId, () => ({
|
|
117
|
+
defaultKind: 'clip',
|
|
118
|
+
locate: (ref: PlaybackRef) => {
|
|
119
|
+
if (ref.kind === 'clip') return rectIn(q(`[data-clip="${CSS.escape(ref.id)}"]`));
|
|
120
|
+
if (ref.kind === 'track') return rectIn(q(`[data-track-lane="${CSS.escape(ref.id)}"]`));
|
|
121
|
+
if (ref.kind === 'marker') return rectIn(q(`[data-marker="${CSS.escape(ref.id)}"]`));
|
|
122
|
+
const at = parseVideoTimeRef(ref);
|
|
123
|
+
if (!at) return null;
|
|
124
|
+
// The row: the named track, the row of the named clip, else the ruler.
|
|
125
|
+
const lane = at.track
|
|
126
|
+
? q(`[data-track-lane="${CSS.escape(at.track)}"]`)
|
|
127
|
+
: at.clip
|
|
128
|
+
? q(`[data-clip="${CSS.escape(at.clip)}"]`)?.closest('[data-track-lane]')
|
|
129
|
+
: ruler;
|
|
130
|
+
const row = rectIn(lane);
|
|
131
|
+
return row ? { x: row.x + (at.time * px) / 1000 - 3, y: row.y, width: 6, height: row.height } : null;
|
|
132
|
+
},
|
|
133
|
+
bounds: () => {
|
|
134
|
+
const r = container?.getBoundingClientRect();
|
|
135
|
+
return r && r.width > 0 ? { x: 0, y: 0, width: r.width, height: r.height } : null;
|
|
136
|
+
},
|
|
137
|
+
visible: () => {
|
|
138
|
+
const r = container?.getBoundingClientRect();
|
|
139
|
+
return !!r && r.width > 0 && r.height > 0 && !(typeof document !== 'undefined' && document.visibilityState === 'hidden');
|
|
140
|
+
},
|
|
141
|
+
toViewport: (p: { x: number; y: number }) => {
|
|
142
|
+
const r = container?.getBoundingClientRect();
|
|
143
|
+
return { x: (r?.left ?? 0) + p.x, y: (r?.top ?? 0) + p.y };
|
|
144
|
+
},
|
|
145
|
+
fromViewport: (p: { x: number; y: number }) => {
|
|
146
|
+
const r = container?.getBoundingClientRect();
|
|
147
|
+
return { x: p.x - (r?.left ?? 0), y: p.y - (r?.top ?? 0) };
|
|
148
|
+
},
|
|
149
|
+
reveal: () => onplaybackreveal?.()
|
|
150
|
+
}));
|
|
93
151
|
let ruler: HTMLDivElement | undefined = $state();
|
|
94
152
|
|
|
95
153
|
interface Drag {
|
|
@@ -262,7 +320,7 @@
|
|
|
262
320
|
<!-- svelte-ignore a11y_no_noninteractive_tabindex, a11y_no_noninteractive_element_interactions -->
|
|
263
321
|
<div
|
|
264
322
|
bind:this={container}
|
|
265
|
-
class="flex flex-col gap-1 text-xs outline-none focus-visible:ring-1 focus-visible:ring-rose-500 {className}"
|
|
323
|
+
class="relative flex flex-col gap-1 text-xs outline-none focus-visible:ring-1 focus-visible:ring-rose-500 {className}"
|
|
266
324
|
tabindex="0"
|
|
267
325
|
role="group"
|
|
268
326
|
aria-label="Timeline"
|
|
@@ -346,6 +404,7 @@
|
|
|
346
404
|
class="relative shrink-0 {track.locked ? 'bg-muted/60' : ''} {track.hidden || track.muted ? 'opacity-60' : ''}"
|
|
347
405
|
style="width:{width}px"
|
|
348
406
|
data-lane={track.id}
|
|
407
|
+
data-track-lane={track.id}
|
|
349
408
|
onpointerdown={(e) => {
|
|
350
409
|
if (e.button === 0 && !(e.shiftKey || e.metaKey || e.ctrlKey)) controller.select(null);
|
|
351
410
|
}}
|
|
@@ -394,4 +453,7 @@
|
|
|
394
453
|
{#if editor.error}
|
|
395
454
|
<p class="text-red-500" role="alert" data-edit-error="">{editor.error}</p>
|
|
396
455
|
{/if}
|
|
456
|
+
{#if playing}
|
|
457
|
+
<PresenceLayer presence={agentPresence} />
|
|
458
|
+
{/if}
|
|
397
459
|
</div>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type VideoEditorController, type VideoWaveformMode } from '@pixerate/editor/video-editor';
|
|
2
|
+
import type { AgentPlayback } from '@pixerate/editor/tools';
|
|
2
3
|
interface Props {
|
|
3
4
|
controller: VideoEditorController;
|
|
4
5
|
/** Zoom: pixels per second of timeline (default 100). Bindable. */
|
|
@@ -10,6 +11,15 @@ interface Props {
|
|
|
10
11
|
/** Draw waveforms in audio clips (default), in every clip with sound (`all`), or not at all. Sound is decoded once per asset through `controller.audioPeaks`. */
|
|
11
12
|
waveforms?: VideoWaveformMode;
|
|
12
13
|
class?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Agent playback: act out the video tools' calls here with the agent's cursor (default:
|
|
16
|
+
* `setAgentPlayback` above; `null` turns it off).
|
|
17
|
+
*/
|
|
18
|
+
playback?: AgentPlayback | null;
|
|
19
|
+
/** The playback surface id (default `video`, where the video tool providers play). */
|
|
20
|
+
playbackId?: string;
|
|
21
|
+
/** Bring the timeline on screen (switch to its tab) before the agent acts. */
|
|
22
|
+
onplaybackreveal?: () => void | Promise<void>;
|
|
13
23
|
}
|
|
14
24
|
declare const VideoTimeline: import("svelte").Component<Props, {}, "pxPerSecond">;
|
|
15
25
|
type VideoTimeline = ReturnType<typeof VideoTimeline>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pixerate/editor-svelte",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.103.1",
|
|
4
4
|
"description": "Svelte bindings and prompt/rich-text components for @pixerate/editor",
|
|
5
5
|
"author": "Pixerate",
|
|
6
6
|
"license": "MIT",
|
|
@@ -144,7 +144,7 @@
|
|
|
144
144
|
"@tiptap/extension-bubble-menu": "^2.27.3",
|
|
145
145
|
"@tiptap/extension-placeholder": "^2.27.3",
|
|
146
146
|
"@tiptap/starter-kit": "^2.27.3",
|
|
147
|
-
"@pixerate/editor": "0.
|
|
147
|
+
"@pixerate/editor": "0.142.1"
|
|
148
148
|
},
|
|
149
149
|
"peerDependencies": {
|
|
150
150
|
"@dagrejs/dagre": "^1.1.4",
|