@pixerate/editor-svelte 0.62.0 → 0.63.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.
@@ -2,16 +2,32 @@
2
2
  import {
3
3
  findVideoClip,
4
4
  formatVideoTimecode,
5
+ VIDEO_CLIP_ANIMATION_EFFECTS,
6
+ VIDEO_CLIP_ANIMATION_LABELS,
7
+ normalizeVideoGrade,
8
+ VIDEO_GRADE_CONTROLS,
9
+ VIDEO_GRADE_PRESET_NAMES,
10
+ videoGradePreset,
11
+ VIDEO_BLEND_MODE_LABELS,
12
+ VIDEO_BLEND_MODES,
5
13
  VIDEO_FADE_CURVE_LABELS,
6
14
  VIDEO_FADE_CURVES,
15
+ VIDEO_TRANSITION_LABELS,
7
16
  VIDEO_TRANSITION_TYPES,
17
+ VIDEO_WIPE_DIRECTIONS,
18
+ videoTransitionHasDirection,
8
19
  videoKeyframeRows,
20
+ videoTransitionAudioCurve,
9
21
  videoKeyframeToggleEdit,
10
22
  videoKeyframeValueEdit,
11
23
  type VideoEdit,
12
24
  type VideoEditorController,
25
+ type VideoFadeCurve,
26
+ type VideoGradeControl,
27
+ type VideoGradePreset,
13
28
  type VideoKeyframeRow,
14
- type VideoTransitionType
29
+ type VideoTransitionType,
30
+ type VideoWipeDirection
15
31
  } from '@pixerate/editor/video-editor';
16
32
  import { videoEditorStateOf } from './createVideoEditor.svelte.js';
17
33
 
@@ -88,6 +104,27 @@
88
104
  if (!type) apply({ op: 'set_transition', clip: clip.id, transition: null }, 'Remove transition');
89
105
  else apply({ op: 'set_transition', clip: clip.id, transition: { ...clip.transition, type: type as VideoTransitionType, duration: clip.transition?.duration ?? 500 } }, 'Set transition');
90
106
  }
107
+ function gradeValue(c: VideoGradeControl, raw: string) {
108
+ if (!clip) return;
109
+ const n = raw.trim() ? Number(raw) : 0;
110
+ if (!Number.isFinite(n)) {
111
+ localError = { text: `${c.label} must be a number from ${c.min} to ${c.max}.`, revision: editor.revision };
112
+ return;
113
+ }
114
+ // Out-of-range values are clamped to the control's range.
115
+ set('grade', normalizeVideoGrade({ ...clip.grade, [c.key]: n }), `Change ${c.label.toLowerCase()}`);
116
+ }
117
+ function gradePreset(name: string) {
118
+ const grade = clip && name ? videoGradePreset(name as VideoGradePreset) : undefined;
119
+ if (clip && grade) apply({ op: 'update_clip', clip: clip.id, set: { grade } }, `Apply ${name} look`);
120
+ }
121
+ function transitionAudioCurve(curve: string) {
122
+ if (!clip?.transition) return;
123
+ const { audioCurve: _, ...rest } = clip.transition;
124
+ // The type's own default is stored as no curve, so it follows the type if that changes.
125
+ const next = curve === videoTransitionAudioCurve(rest) ? rest : { ...rest, audioCurve: curve as VideoFadeCurve };
126
+ apply({ op: 'set_transition', clip: clip.id, transition: next }, 'Change transition sound');
127
+ }
91
128
  function transitionDuration(raw: string) {
92
129
  if (!clip?.transition) return;
93
130
  const n = Number(raw);
@@ -125,6 +162,38 @@
125
162
  <span class="tabular-nums" data-field="start">{formatVideoTimecode(clip.start, fps)}</span>
126
163
  <span class="text-muted-foreground">Duration</span>
127
164
  <span class="tabular-nums" data-field="duration">{formatVideoTimecode(clip.duration, fps)} ({(clip.duration / 1000).toFixed(2)} s)</span>
165
+ {#if at?.track.kind === 'video'}
166
+ <span class="text-muted-foreground">Blend</span>
167
+ <select class={input} aria-label="Blend mode" {disabled} value={clip.blend ?? 'normal'} onchange={(e) => set('blend', e.currentTarget.value === 'normal' ? undefined : e.currentTarget.value, 'Change blend mode')} data-field="blend">
168
+ {#each VIDEO_BLEND_MODES as m (m)}
169
+ <option value={m}>{VIDEO_BLEND_MODE_LABELS[m]}</option>
170
+ {/each}
171
+ </select>
172
+ {/if}
173
+ {#if at?.track.kind === 'video'}
174
+ <span class="text-muted-foreground">Look</span>
175
+ <select class={input} aria-label="Apply a look" {disabled} value="" onchange={(e) => gradePreset(e.currentTarget.value)} data-field="gradePreset">
176
+ <option value="">{clip.grade ? 'graded' : 'none'}</option>
177
+ {#each VIDEO_GRADE_PRESET_NAMES as name (name)}
178
+ <option value={name}>{name.replace(/-/g, ' ')}</option>
179
+ {/each}
180
+ </select>
181
+ {#each VIDEO_GRADE_CONTROLS as c (c.key)}
182
+ <span class="text-muted-foreground">{c.label}</span>
183
+ <input class={input} type="number" min={c.min} max={c.max} step={c.step} placeholder="0" aria-label={c.label} {disabled} value={clip.grade?.[c.key] ?? ''} onchange={(e) => gradeValue(c, e.currentTarget.value)} data-field="grade.{c.key}" />
184
+ {/each}
185
+ {/if}
186
+ {#if at?.track.kind === 'video'}
187
+ {#each [{ key: 'animateIn', label: 'Animate in', change: 'Change entrance' }, { key: 'animateOut', label: 'Animate out', change: 'Change exit' }] as const as row (row.key)}
188
+ <span class="text-muted-foreground">{row.label}</span>
189
+ <select class={input} aria-label={row.label} {disabled} value={clip[row.key]?.effect ?? ''} onchange={(e) => set(row.key, e.currentTarget.value ? { ...clip?.[row.key], effect: e.currentTarget.value } : undefined, row.change)} data-field={row.key}>
190
+ <option value="">none</option>
191
+ {#each VIDEO_CLIP_ANIMATION_EFFECTS as effect (effect)}
192
+ <option value={effect}>{VIDEO_CLIP_ANIMATION_LABELS[effect]}</option>
193
+ {/each}
194
+ </select>
195
+ {/each}
196
+ {/if}
128
197
  <span class="text-muted-foreground">Fade in</span>
129
198
  <input class={input} type="number" min="0" step="100" placeholder="0 ms" aria-label="Fade in" {disabled} value={clip.fadeIn ?? ''} onchange={(e) => number('fadeIn', e.currentTarget.value, 'Change fade in', { min: 0, what: 'Fade in must be a number of ms, 0 or more.' })} data-field="fadeIn" />
130
199
  <span class="text-muted-foreground">Fade out</span>
@@ -179,7 +248,7 @@
179
248
  <select class={input} aria-label="Transition" {disabled} value={clip.transition?.type ?? ''} onchange={(e) => setTransition(e.currentTarget.value)} data-field="transition">
180
249
  <option value="">none</option>
181
250
  {#each VIDEO_TRANSITION_TYPES as t (t)}
182
- <option value={t}>{t}</option>
251
+ <option value={t}>{VIDEO_TRANSITION_LABELS[t]}</option>
183
252
  {/each}
184
253
  </select>
185
254
  {#if clip.transition}
@@ -187,6 +256,22 @@
187
256
  <span class="text-[10px] text-muted-foreground">ms</span>
188
257
  {/if}
189
258
  </div>
259
+ {#if clip.transition && videoTransitionHasDirection(clip.transition.type)}
260
+ <span class="text-muted-foreground">Direction</span>
261
+ <select class={input} aria-label="Transition direction" {disabled} value={clip.transition.direction ?? 'right'} onchange={(e) => clip?.transition && apply({ op: 'set_transition', clip: clip.id, transition: { ...clip.transition, direction: e.currentTarget.value as VideoWipeDirection } }, 'Change transition direction')} data-field="transitionDirection">
262
+ {#each VIDEO_WIPE_DIRECTIONS as d (d)}
263
+ <option value={d}>{d}</option>
264
+ {/each}
265
+ </select>
266
+ {/if}
267
+ {#if clip.transition}
268
+ <span class="text-muted-foreground">Transition sound</span>
269
+ <select class={input} aria-label="Transition sound curve" {disabled} value={videoTransitionAudioCurve(clip.transition)} onchange={(e) => transitionAudioCurve(e.currentTarget.value)} data-field="transitionAudioCurve">
270
+ {#each VIDEO_FADE_CURVES as c (c)}
271
+ <option value={c}>{VIDEO_FADE_CURVE_LABELS[c]}</option>
272
+ {/each}
273
+ </select>
274
+ {/if}
190
275
  </div>
191
276
  {/if}
192
277
  {#if message}
@@ -1 +1 @@
1
- {"version":3,"file":"ClipInspector.svelte.d.ts","sourceRoot":"","sources":["../../src/video-editor/ClipInspector.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,EAUH,KAAK,qBAAqB,EAG3B,MAAM,+BAA+B,CAAC;AAIvC,UAAU,KAAK;IACb,UAAU,EAAE,qBAAqB,CAAC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAuKH,QAAA,MAAM,aAAa,2CAAwC,CAAC;AAC5D,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AACtD,eAAe,aAAa,CAAC"}
1
+ {"version":3,"file":"ClipInspector.svelte.d.ts","sourceRoot":"","sources":["../../src/video-editor/ClipInspector.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,EAsBH,KAAK,qBAAqB,EAO3B,MAAM,+BAA+B,CAAC;AAIvC,UAAU,KAAK;IACb,UAAU,EAAE,qBAAqB,CAAC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA4OH,QAAA,MAAM,aAAa,2CAAwC,CAAC;AAC5D,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AACtD,eAAe,aAAa,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pixerate/editor-svelte",
3
- "version": "0.62.0",
3
+ "version": "0.63.0",
4
4
  "description": "Svelte bindings and prompt/rich-text components for @pixerate/editor",
5
5
  "author": "Pixerate",
6
6
  "license": "MIT",
@@ -131,7 +131,7 @@
131
131
  "@tiptap/extension-bubble-menu": "^2.11.5",
132
132
  "@tiptap/extension-placeholder": "^2.11.5",
133
133
  "@tiptap/starter-kit": "^2.11.5",
134
- "@pixerate/editor": "0.83.0"
134
+ "@pixerate/editor": "0.84.0"
135
135
  },
136
136
  "peerDependencies": {
137
137
  "@dagrejs/dagre": "^1.1.4",