@pixerate/editor 0.231.1 → 0.233.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/dist/animation-editor/compile.d.cts +3 -0
- package/dist/animation-editor/compile.d.ts +3 -0
- package/dist/animation-editor/controller.d.cts +67 -2
- package/dist/animation-editor/controller.d.ts +67 -2
- package/dist/animation-editor/edit.d.cts +1 -1
- package/dist/animation-editor/edit.d.ts +1 -1
- package/dist/animation-editor/evaluate.d.cts +8 -1
- package/dist/animation-editor/evaluate.d.ts +8 -1
- package/dist/animation-editor/index.cjs +1202 -371
- package/dist/animation-editor/index.d.cts +3 -0
- package/dist/animation-editor/index.d.ts +3 -0
- package/dist/animation-editor/index.js +1032 -201
- package/dist/animation-editor/issues.d.cts +28 -0
- package/dist/animation-editor/issues.d.ts +28 -0
- package/dist/animation-editor/layer-edit.d.cts +55 -0
- package/dist/animation-editor/layer-edit.d.ts +55 -0
- package/dist/animation-editor/layer-tools.d.cts +11 -0
- package/dist/animation-editor/layer-tools.d.ts +11 -0
- package/dist/animation-editor/layers.d.cts +166 -0
- package/dist/animation-editor/layers.d.ts +166 -0
- package/dist/animation-editor/parse.d.cts +2 -0
- package/dist/animation-editor/parse.d.ts +2 -0
- package/dist/animation-editor/types.d.cts +44 -1
- package/dist/animation-editor/types.d.ts +44 -1
- package/dist/canvas/index.cjs +10 -10
- package/dist/canvas/index.js +4 -4
- package/dist/chunk-6RZVFYGJ.cjs +255 -0
- package/dist/{chunk-C73U5UI3.cjs → chunk-A7PQNIBX.cjs} +14 -14
- package/dist/{chunk-ERJA5CGT.cjs → chunk-DGWOGQJ5.cjs} +8 -1
- package/dist/{chunk-TYCJGFCF.js → chunk-EUKY4KFX.js} +8 -1
- package/dist/chunk-I277KJLQ.js +255 -0
- package/dist/{chunk-OPSK22DL.cjs → chunk-JAOSL334.cjs} +24 -7
- package/dist/{chunk-TCZ2J7PR.js → chunk-SIK3LT6M.js} +26 -9
- package/dist/{chunk-SBPGIZQN.js → chunk-TEFQISBY.js} +1 -1
- package/dist/{chunk-CSM5T6SE.js → chunk-WDDUPWVG.js} +1 -1
- package/dist/{chunk-5T3H7CGG.cjs → chunk-ZQIWBJGH.cjs} +7 -7
- package/dist/effects/conformance.d.cts +4 -1
- package/dist/effects/conformance.d.ts +4 -1
- package/dist/effects/errors.d.cts +6 -1
- package/dist/effects/errors.d.ts +6 -1
- package/dist/effects/fake-templates.d.cts +17 -0
- package/dist/effects/fake-templates.d.ts +17 -0
- package/dist/effects/fake.d.cts +6 -1
- package/dist/effects/fake.d.ts +6 -1
- package/dist/effects/index.cjs +322 -67
- package/dist/effects/index.d.cts +1 -0
- package/dist/effects/index.d.ts +1 -0
- package/dist/effects/index.js +258 -3
- package/dist/effects/templates.d.cts +56 -0
- package/dist/effects/templates.d.ts +56 -0
- package/dist/effects/types.d.cts +212 -0
- package/dist/effects/types.d.ts +212 -0
- package/dist/image-editor/index.cjs +16 -16
- package/dist/image-editor/index.js +4 -4
- package/dist/paint-editor/index.cjs +10 -10
- package/dist/paint-editor/index.js +5 -5
- package/dist/vector/index.cjs +6 -6
- package/dist/vector/index.js +1 -1
- package/dist/video-editor/index.cjs +339 -339
- package/dist/video-editor/index.js +5 -5
- package/package.json +1 -1
- package/skills/pixerate-animation-editor/SKILL.md +37 -0
package/dist/effects/index.d.cts
CHANGED
package/dist/effects/index.d.ts
CHANGED
package/dist/effects/index.js
CHANGED
|
@@ -3,7 +3,28 @@ import {
|
|
|
3
3
|
} from "../chunk-N4ZXW3WB.js";
|
|
4
4
|
import {
|
|
5
5
|
createEffectAuthoringSession
|
|
6
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-TEFQISBY.js";
|
|
7
|
+
import {
|
|
8
|
+
EFFECT_LAYER_USES,
|
|
9
|
+
EFFECT_SEQUENCE_NAME,
|
|
10
|
+
checkEffectSequence,
|
|
11
|
+
checkTemplateValues,
|
|
12
|
+
effectLayerInput,
|
|
13
|
+
effectLayerOffered,
|
|
14
|
+
effectLayerRole,
|
|
15
|
+
effectSequenceEffects,
|
|
16
|
+
effectSequenceSlots,
|
|
17
|
+
effectSubjectKind,
|
|
18
|
+
effectSubjectProblem,
|
|
19
|
+
isSubjectTemplateSlot,
|
|
20
|
+
searchTemplateSummaries,
|
|
21
|
+
templateDefaultValues,
|
|
22
|
+
templateSlotSchema,
|
|
23
|
+
templateSlotSummary,
|
|
24
|
+
templateSlotTakes,
|
|
25
|
+
templateValueProblem,
|
|
26
|
+
templateValuesSchema
|
|
27
|
+
} from "../chunk-I277KJLQ.js";
|
|
7
28
|
import {
|
|
8
29
|
EffectRendererPool
|
|
9
30
|
} from "../chunk-EHLOCVWB.js";
|
|
@@ -12,6 +33,10 @@ import {
|
|
|
12
33
|
CAMERA_MOVE_ROLES,
|
|
13
34
|
EFFECT_ERROR_CODES,
|
|
14
35
|
EFFECT_KINDS,
|
|
36
|
+
EFFECT_LAYER_ROLES,
|
|
37
|
+
EFFECT_SUBJECT_KINDS,
|
|
38
|
+
EFFECT_TEMPLATE_SLOT_TYPES,
|
|
39
|
+
EFFECT_TRANSITION_MS,
|
|
15
40
|
EFFECT_USES,
|
|
16
41
|
EffectControlError,
|
|
17
42
|
EffectDisposedError,
|
|
@@ -20,6 +45,7 @@ import {
|
|
|
20
45
|
EffectsSlot,
|
|
21
46
|
NoEffectsProviderError,
|
|
22
47
|
UnknownEffectError,
|
|
48
|
+
UnknownTemplateError,
|
|
23
49
|
applyEffectMask,
|
|
24
50
|
cameraBoxOfView,
|
|
25
51
|
cameraMoveField,
|
|
@@ -45,7 +71,7 @@ import {
|
|
|
45
71
|
sampleEffectCameraMove,
|
|
46
72
|
searchEffectSummaries,
|
|
47
73
|
srgbToLinear
|
|
48
|
-
} from "../chunk-
|
|
74
|
+
} from "../chunk-SIK3LT6M.js";
|
|
49
75
|
import "../chunk-V2ZCJRDM.js";
|
|
50
76
|
import "../chunk-RNSANXPT.js";
|
|
51
77
|
import {
|
|
@@ -191,6 +217,87 @@ async function checkCamera(provider, d, issues) {
|
|
|
191
217
|
}
|
|
192
218
|
}
|
|
193
219
|
}
|
|
220
|
+
var wrongValue = (slot) => slot.type === "number" ? "not a number" : slot.type === "text" ? 42 : slot.type === "color" ? "blue" : 42;
|
|
221
|
+
function checkSlot(templateId, slot, issues) {
|
|
222
|
+
const at = (message) => issues.push({ templateId, message: `slot ${JSON.stringify(slot?.name)}: ${message}` });
|
|
223
|
+
if (!slot || typeof slot.name !== "string" || !/^[A-Za-z][\w-]*$/.test(slot.name)) return at('needs a name of letters, digits, "-" and "_", starting with a letter');
|
|
224
|
+
if (!EFFECT_TEMPLATE_SLOT_TYPES.includes(slot.type)) return at(`type "${slot.type}" is not one of ${EFFECT_TEMPLATE_SLOT_TYPES.join(", ")}`);
|
|
225
|
+
if (typeof slot.label !== "string" || !slot.label) at("needs a label");
|
|
226
|
+
if (isSubjectTemplateSlot(slot)) {
|
|
227
|
+
if (typeof slot.hasDefault !== "boolean") at("a subject slot needs hasDefault (a boolean)");
|
|
228
|
+
if ("default" in slot) at("a subject slot describes hasDefault, not its default");
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
const fallback = slot.default;
|
|
232
|
+
if (fallback === void 0) return at("needs a default");
|
|
233
|
+
const problem = templateValueProblem(slot, fallback);
|
|
234
|
+
if (problem) at(`its default does not fit: ${problem}`);
|
|
235
|
+
if (slot.type === "number" && slot.min !== void 0 && slot.max !== void 0 && slot.min > slot.max) at("min is above max");
|
|
236
|
+
}
|
|
237
|
+
async function checkTemplates(provider, list, issues) {
|
|
238
|
+
const top = (message) => issues.push({ message });
|
|
239
|
+
const templates = await provider.listTemplates();
|
|
240
|
+
if (!Array.isArray(templates)) return top("listTemplates did not return a list");
|
|
241
|
+
const seen = /* @__PURE__ */ new Set();
|
|
242
|
+
for (const t of templates) if (seen.has(t.id)) top(`duplicate template id "${t.id}"`);
|
|
243
|
+
else seen.add(t.id);
|
|
244
|
+
const unknownDescribe = await rejectsWith("unknown_template", () => provider.describeTemplate("__no_such_template__"));
|
|
245
|
+
if (unknownDescribe) top(`describeTemplate of an unknown id ${unknownDescribe}`);
|
|
246
|
+
const unknownFill = await rejectsWith("unknown_template", () => provider.instantiateTemplate("__no_such_template__"));
|
|
247
|
+
if (unknownFill) top(`instantiateTemplate of an unknown id ${unknownFill}`);
|
|
248
|
+
for (const summary of templates) {
|
|
249
|
+
const id = summary.id;
|
|
250
|
+
const at = (message) => issues.push({ templateId: id, message });
|
|
251
|
+
if (!id || typeof id !== "string") top("a template has no id");
|
|
252
|
+
if (!summary.name) at("template has no name");
|
|
253
|
+
if (!summary.description) at("template has no description");
|
|
254
|
+
if (!(Number.isInteger(summary.shots) && summary.shots >= 1)) at("shots must be a whole number \u2265 1");
|
|
255
|
+
if (summary.durationMs !== void 0 && !(summary.durationMs > 0)) at("durationMs must be > 0 when present");
|
|
256
|
+
let slots;
|
|
257
|
+
try {
|
|
258
|
+
const d = await provider.describeTemplate(id);
|
|
259
|
+
if (d.id !== id) at(`describeTemplate returned id "${d.id}"`);
|
|
260
|
+
if (!Array.isArray(d.slots)) {
|
|
261
|
+
at("describeTemplate gave no slots list");
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
slots = d.slots;
|
|
265
|
+
const names = /* @__PURE__ */ new Set();
|
|
266
|
+
for (const slot of slots) {
|
|
267
|
+
if (names.has(slot?.name)) at(`slot "${slot.name}" is declared twice`);
|
|
268
|
+
names.add(slot?.name);
|
|
269
|
+
checkSlot(id, slot, issues);
|
|
270
|
+
}
|
|
271
|
+
} catch (e) {
|
|
272
|
+
at(`describeTemplate failed: ${codeOf(e)}`);
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
try {
|
|
276
|
+
const result = await provider.instantiateTemplate(id);
|
|
277
|
+
if (!result.ok) at(`instantiateTemplate with the defaults failed: ${result.errors.join(" ")}`);
|
|
278
|
+
else {
|
|
279
|
+
for (const p of checkEffectSequence(result.sequence, list)) at(`with the defaults, ${p}`);
|
|
280
|
+
if (result.sequence?.shots?.length !== summary.shots) at(`listTemplates says ${summary.shots} shots; the sequence has ${result.sequence?.shots?.length}`);
|
|
281
|
+
if (!Array.isArray(result.openSlots) || !Array.isArray(result.notes)) at("instantiateTemplate needs openSlots and notes lists");
|
|
282
|
+
else {
|
|
283
|
+
const open = Array.isArray(result.sequence?.shots) ? effectSequenceSlots(result.sequence) : [];
|
|
284
|
+
if (open.some((s) => !result.openSlots.includes(s))) at(`openSlots ${JSON.stringify(result.openSlots)} misses slots the sequence leaves open (${open.join(", ")})`);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
} catch (e) {
|
|
288
|
+
at(`instantiateTemplate with the defaults failed: ${codeOf(e)}`);
|
|
289
|
+
}
|
|
290
|
+
const bad = { __no_such_slot__: "x", ...slots[0] ? { [slots[0].name]: wrongValue(slots[0]) } : {} };
|
|
291
|
+
try {
|
|
292
|
+
const result = await provider.instantiateTemplate(id, bad);
|
|
293
|
+
if (result.ok) at("instantiateTemplate accepted an unknown slot and a value of the wrong type");
|
|
294
|
+
else if (!result.errors.length || result.errors.some((e) => typeof e !== "string" || !e)) at("instantiateTemplate refused bad values without a sentence for each");
|
|
295
|
+
else if (slots[0] && result.errors.length < 2) at("instantiateTemplate should refuse every bad value at once (an unknown slot and a wrong type gave one error)");
|
|
296
|
+
} catch (e) {
|
|
297
|
+
at(`instantiateTemplate with bad values threw (${codeOf(e)}) instead of returning { ok: false, errors }`);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
194
301
|
async function checkEffectProvider(provider, options = {}) {
|
|
195
302
|
const issues = [];
|
|
196
303
|
const top = (message) => issues.push({ message });
|
|
@@ -205,6 +312,12 @@ async function checkEffectProvider(provider, options = {}) {
|
|
|
205
312
|
if (caps?.supportsCamera !== void 0 && typeof caps.supportsCamera !== "boolean") top("capabilities.supportsCamera is not a boolean");
|
|
206
313
|
if (caps?.supportsCamera && typeof provider.cameraView !== "function") top("supportsCamera is set but cameraView is missing");
|
|
207
314
|
if (provider.sampleCameraMove && typeof provider.cameraView !== "function") top("sampleCameraMove is present but cameraView is missing");
|
|
315
|
+
if (caps?.supportsTemplates !== void 0 && typeof caps.supportsTemplates !== "boolean") top("capabilities.supportsTemplates is not a boolean");
|
|
316
|
+
const templateMethods = ["listTemplates", "describeTemplate", "instantiateTemplate"];
|
|
317
|
+
if (caps?.supportsTemplates) {
|
|
318
|
+
for (const m of templateMethods) if (typeof provider[m] !== "function") top(`supportsTemplates is set but ${m} is missing`);
|
|
319
|
+
}
|
|
320
|
+
if (!caps?.supportsTemplates && templateMethods.some((m) => typeof provider[m] === "function")) top("template methods are present but capabilities.supportsTemplates is not set");
|
|
208
321
|
const list = await provider.list();
|
|
209
322
|
const ids = /* @__PURE__ */ new Set();
|
|
210
323
|
for (const e of list) {
|
|
@@ -307,9 +420,125 @@ async function checkEffectProvider(provider, options = {}) {
|
|
|
307
420
|
}
|
|
308
421
|
}
|
|
309
422
|
}
|
|
423
|
+
if (caps?.supportsTemplates && options.templates !== false && templateMethods.every((m) => typeof provider[m] === "function")) await checkTemplates(provider, list, issues);
|
|
310
424
|
return issues;
|
|
311
425
|
}
|
|
312
426
|
|
|
427
|
+
// src/effects/fake-templates.ts
|
|
428
|
+
var PLACEHOLDER = /\{\{([A-Za-z][\w-]*)\}\}/g;
|
|
429
|
+
var WHOLE = /^\{\{([A-Za-z][\w-]*)\}\}$/;
|
|
430
|
+
var picture = (label, tint) => `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 90" width="160" height="90"><rect width="160" height="90" fill="${tint}"/><text x="80" y="50" text-anchor="middle" font-family="sans-serif" font-size="14" fill="#fff">${label}</text></svg>`;
|
|
431
|
+
var TEMPLATES = [
|
|
432
|
+
{
|
|
433
|
+
summary: { id: "fake.title-sequence", name: "Title sequence", description: "A gradient behind a title with a lower-third bar, then a crossfade to a closing shot with a caption.", tags: ["title", "intro"], shots: 2, durationMs: 4600 },
|
|
434
|
+
slots: [
|
|
435
|
+
{ name: "title", type: "text", label: "Title", default: "Hello", maxLength: 40 },
|
|
436
|
+
{ name: "subtitle", type: "text", label: "Closing caption", default: "See you soon", maxLength: 60 },
|
|
437
|
+
{ name: "accent", type: "color", label: "Accent colour", default: "#0ea5e9" },
|
|
438
|
+
{ name: "holdMs", type: "number", label: "Time on each shot (ms)", default: 2e3, min: 500, max: 1e4, integer: true }
|
|
439
|
+
],
|
|
440
|
+
sequence: {
|
|
441
|
+
name: "title-sequence",
|
|
442
|
+
title: "{{title}}",
|
|
443
|
+
stage: { width: 1280, height: 720 },
|
|
444
|
+
shots: [
|
|
445
|
+
{
|
|
446
|
+
hold: "{{holdMs}}",
|
|
447
|
+
title: "{{title}}",
|
|
448
|
+
layers: [
|
|
449
|
+
{ id: "backdrop", effect: "fake.gradient", role: "background", values: { from: "{{accent}}" }, until: { shots: 1 } },
|
|
450
|
+
{ id: "bar", effect: "fake.bar", role: "overlay", values: { color: "{{accent}}" }, from: 200 }
|
|
451
|
+
]
|
|
452
|
+
},
|
|
453
|
+
{
|
|
454
|
+
hold: "{{holdMs}}",
|
|
455
|
+
caption: "{{subtitle}}",
|
|
456
|
+
transition: { effect: "fake.crossfade", ms: 600 },
|
|
457
|
+
layers: [{ id: "closing", effect: "fake.gradient", role: "background", values: { from: "#111827", to: "{{accent}}" } }]
|
|
458
|
+
}
|
|
459
|
+
]
|
|
460
|
+
}
|
|
461
|
+
},
|
|
462
|
+
{
|
|
463
|
+
summary: { id: "fake.picture-reveal", name: "Picture reveal", description: "A tinted picture, then a crossfade to the picture in full colour with a logo over it and a caption.", tags: ["product", "reveal"], shots: 2, durationMs: 4800 },
|
|
464
|
+
slots: [
|
|
465
|
+
{ name: "picture", type: "image", label: "Picture", description: "The picture to reveal.", hasDefault: true, subjectDefault: picture("Picture", "#64748b") },
|
|
466
|
+
{ name: "logo", type: "image", label: "Logo", description: "A logo shown over the second shot; the host fills it when none is given.", hasDefault: false },
|
|
467
|
+
{ name: "caption", type: "text", label: "Caption", default: "Now in colour", maxLength: 50 },
|
|
468
|
+
{ name: "holdMs", type: "number", label: "Time on each shot (ms)", default: 2e3, min: 500, max: 1e4, integer: true }
|
|
469
|
+
],
|
|
470
|
+
sequence: {
|
|
471
|
+
name: "picture-reveal",
|
|
472
|
+
stage: { width: 1280, height: 720 },
|
|
473
|
+
shots: [
|
|
474
|
+
{ hold: "{{holdMs}}", layers: [{ id: "tinted", effect: "fake.tint", subject: { slot: "picture" }, values: { color: "#704214", amount: 0.6 } }] },
|
|
475
|
+
{
|
|
476
|
+
hold: "{{holdMs}}",
|
|
477
|
+
caption: "{{caption}}",
|
|
478
|
+
transition: { effect: "fake.crossfade", ms: 800 },
|
|
479
|
+
layers: [
|
|
480
|
+
{ id: "picture", subject: { slot: "picture" }, role: "background" },
|
|
481
|
+
{ id: "logo", subject: { slot: "logo" }, role: "overlay", rect: { x: 1040, y: 40, width: 200, height: 112 }, fade: 300 }
|
|
482
|
+
]
|
|
483
|
+
}
|
|
484
|
+
]
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
];
|
|
488
|
+
var describeOf = (t) => ({
|
|
489
|
+
...t.summary,
|
|
490
|
+
slots: t.slots.map(({ subjectDefault: _d, ...slot }) => slot)
|
|
491
|
+
});
|
|
492
|
+
function subjectOf(type, value) {
|
|
493
|
+
if (typeof value !== "string") return value;
|
|
494
|
+
if (value.trimStart().startsWith("<svg") || type === "svg") return { svg: value };
|
|
495
|
+
return type === "video" ? { video: value } : { image: value };
|
|
496
|
+
}
|
|
497
|
+
function fill(t, values) {
|
|
498
|
+
const slots = new Map(t.slots.map((s) => [s.name, s]));
|
|
499
|
+
const valueOf = (name) => {
|
|
500
|
+
const s = slots.get(name);
|
|
501
|
+
return values[name] ?? (isSubjectTemplateSlot(s) ? s.subjectDefault : s.default);
|
|
502
|
+
};
|
|
503
|
+
const walk = (v, key) => {
|
|
504
|
+
if (typeof v === "string") {
|
|
505
|
+
const whole = WHOLE.exec(v);
|
|
506
|
+
if (whole && slots.has(whole[1])) return valueOf(whole[1]);
|
|
507
|
+
return v.replace(PLACEHOLDER, (m, name) => slots.has(name) ? String(valueOf(name)) : m);
|
|
508
|
+
}
|
|
509
|
+
if (Array.isArray(v)) return v.map((x) => walk(x));
|
|
510
|
+
if (!v || typeof v !== "object") return v;
|
|
511
|
+
if (key === "subject" && typeof v.slot === "string") {
|
|
512
|
+
const s = slots.get(v.slot);
|
|
513
|
+
const value = s ? valueOf(s.name) : void 0;
|
|
514
|
+
return s && value !== void 0 ? subjectOf(s.type, value) : v;
|
|
515
|
+
}
|
|
516
|
+
return Object.fromEntries(Object.entries(v).map(([k, x]) => [k, walk(x, k)]));
|
|
517
|
+
};
|
|
518
|
+
return walk(t.sequence);
|
|
519
|
+
}
|
|
520
|
+
function fakeTemplateMethods() {
|
|
521
|
+
const byId = new Map(TEMPLATES.map((t) => [t.summary.id, t]));
|
|
522
|
+
const get = (id) => {
|
|
523
|
+
const t = byId.get(id);
|
|
524
|
+
if (!t) throw new UnknownTemplateError(id, "the fake provider");
|
|
525
|
+
return t;
|
|
526
|
+
};
|
|
527
|
+
return {
|
|
528
|
+
listTemplates: (options) => searchTemplateSummaries(TEMPLATES.map((t) => t.summary), options).map((s) => structuredClone(s)),
|
|
529
|
+
describeTemplate: (id) => structuredClone(describeOf(get(id))),
|
|
530
|
+
instantiateTemplate(id, values = {}, options = {}) {
|
|
531
|
+
const t = get(id);
|
|
532
|
+
const errors = checkTemplateValues(describeOf(t).slots, values);
|
|
533
|
+
if (options.name !== void 0 && (typeof options.name !== "string" || !EFFECT_SEQUENCE_NAME.test(options.name))) errors.push(`The sequence name is lowercase words and dashes (like "${t.summary.id.replace(/^fake\./, "")}").`);
|
|
534
|
+
if (errors.length) return { ok: false, errors };
|
|
535
|
+
const sequence = fill(t, values);
|
|
536
|
+
if (options.name) sequence.name = options.name;
|
|
537
|
+
return { ok: true, sequence, openSlots: effectSequenceSlots(sequence), notes: [] };
|
|
538
|
+
}
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
|
|
313
542
|
// src/effects/fake.ts
|
|
314
543
|
var HEX = "^#[0-9a-fA-F]{6}$";
|
|
315
544
|
var colour = (description) => ({ type: "string", pattern: HEX, description });
|
|
@@ -689,6 +918,7 @@ function createFakeEffectProvider(options = {}) {
|
|
|
689
918
|
supportsVector: true,
|
|
690
919
|
supportsAuthoring,
|
|
691
920
|
...options.camera ? { supportsCamera: true } : {},
|
|
921
|
+
...options.templates ? { supportsTemplates: true } : {},
|
|
692
922
|
maxSize: 8192,
|
|
693
923
|
...options.capabilities
|
|
694
924
|
};
|
|
@@ -775,6 +1005,7 @@ function createFakeEffectProvider(options = {}) {
|
|
|
775
1005
|
return sampleCameraViews((u) => camera(id, { from, to, u, ms, stage }, values), { ms, fps, cut: d.camera?.cut });
|
|
776
1006
|
}
|
|
777
1007
|
} : {},
|
|
1008
|
+
...options.templates ? fakeTemplateMethods() : {},
|
|
778
1009
|
...supportsAuthoring ? {
|
|
779
1010
|
openAuthoring: (from) => createEffectAuthoringSession(from, { provider })
|
|
780
1011
|
} : {}
|
|
@@ -1304,6 +1535,12 @@ export {
|
|
|
1304
1535
|
CAMERA_MOVE_ROLES,
|
|
1305
1536
|
EFFECT_ERROR_CODES,
|
|
1306
1537
|
EFFECT_KINDS,
|
|
1538
|
+
EFFECT_LAYER_ROLES,
|
|
1539
|
+
EFFECT_LAYER_USES,
|
|
1540
|
+
EFFECT_SEQUENCE_NAME,
|
|
1541
|
+
EFFECT_SUBJECT_KINDS,
|
|
1542
|
+
EFFECT_TEMPLATE_SLOT_TYPES,
|
|
1543
|
+
EFFECT_TRANSITION_MS,
|
|
1307
1544
|
EFFECT_USES,
|
|
1308
1545
|
EFFECT_USE_LABELS,
|
|
1309
1546
|
EffectControlError,
|
|
@@ -1314,6 +1551,7 @@ export {
|
|
|
1314
1551
|
EffectsSlot,
|
|
1315
1552
|
NoEffectsProviderError,
|
|
1316
1553
|
UnknownEffectError,
|
|
1554
|
+
UnknownTemplateError,
|
|
1317
1555
|
applyEffectMask,
|
|
1318
1556
|
cameraBoxOfView,
|
|
1319
1557
|
cameraMoveField,
|
|
@@ -1322,6 +1560,8 @@ export {
|
|
|
1322
1560
|
cameraMovesFor,
|
|
1323
1561
|
cameraViewOfBox,
|
|
1324
1562
|
checkEffectProvider,
|
|
1563
|
+
checkEffectSequence,
|
|
1564
|
+
checkTemplateValues,
|
|
1325
1565
|
countEffectTags,
|
|
1326
1566
|
createEffectAuthoringSession,
|
|
1327
1567
|
createEffectAuthoringToolProvider,
|
|
@@ -1331,10 +1571,17 @@ export {
|
|
|
1331
1571
|
effectControlField,
|
|
1332
1572
|
effectFieldValue,
|
|
1333
1573
|
effectFontFamilies,
|
|
1574
|
+
effectLayerInput,
|
|
1575
|
+
effectLayerOffered,
|
|
1576
|
+
effectLayerRole,
|
|
1334
1577
|
effectOffered,
|
|
1335
1578
|
effectParameterFields,
|
|
1336
1579
|
effectSampleInputs,
|
|
1337
1580
|
effectSamplePicture,
|
|
1581
|
+
effectSequenceEffects,
|
|
1582
|
+
effectSequenceSlots,
|
|
1583
|
+
effectSubjectKind,
|
|
1584
|
+
effectSubjectProblem,
|
|
1338
1585
|
effectValueErrors,
|
|
1339
1586
|
encodeEffectFloat,
|
|
1340
1587
|
groupEffectsByCategory,
|
|
@@ -1343,6 +1590,7 @@ export {
|
|
|
1343
1590
|
isEffectError,
|
|
1344
1591
|
isEffectFontControl,
|
|
1345
1592
|
isEffectPixels,
|
|
1593
|
+
isSubjectTemplateSlot,
|
|
1346
1594
|
linearToSrgb,
|
|
1347
1595
|
normaliseEffectTag,
|
|
1348
1596
|
renderEffectThumbnail,
|
|
@@ -1351,5 +1599,12 @@ export {
|
|
|
1351
1599
|
sampleCameraViews,
|
|
1352
1600
|
sampleEffectCameraMove,
|
|
1353
1601
|
searchEffectSummaries,
|
|
1354
|
-
|
|
1602
|
+
searchTemplateSummaries,
|
|
1603
|
+
srgbToLinear,
|
|
1604
|
+
templateDefaultValues,
|
|
1605
|
+
templateSlotSchema,
|
|
1606
|
+
templateSlotSummary,
|
|
1607
|
+
templateSlotTakes,
|
|
1608
|
+
templateValueProblem,
|
|
1609
|
+
templateValuesSchema
|
|
1355
1610
|
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helpers for sequence templates and the sequences they fill to (see `EffectSequence`): the
|
|
3
|
+
* values a template takes as a JSON Schema, checking values before asking the provider, checking
|
|
4
|
+
* a sequence before loading it, and which input a layer's subject feeds. Dependency-free.
|
|
5
|
+
*/
|
|
6
|
+
import type { JsonSchema } from '../tools/schema.cjs';
|
|
7
|
+
import { type EffectDescription, type EffectLayer, type EffectLayerRole, type EffectSequence, type EffectSubjectKind, type EffectSummary, type EffectTemplateSearchOptions, type EffectTemplateSlot, type EffectTemplateSummary } from './types.cjs';
|
|
8
|
+
export declare const EFFECT_SEQUENCE_NAME: RegExp;
|
|
9
|
+
/** True for a subject slot (`image`, `video`, `svg`). */
|
|
10
|
+
export declare const isSubjectTemplateSlot: (slot: Pick<EffectTemplateSlot, "type">) => boolean;
|
|
11
|
+
/** The kind of a subject (`image`, `video`, `svg`, `text`, `slot`), or undefined when it is none of them. */
|
|
12
|
+
export declare function effectSubjectKind(subject: unknown): EffectSubjectKind | undefined;
|
|
13
|
+
/** What a slot takes, in a few words ("words (up to 40 characters)", "a colour like #FF5A36"). */
|
|
14
|
+
export declare function templateSlotTakes(slot: EffectTemplateSlot): string;
|
|
15
|
+
/** The problem with one value for a slot, as a sentence, or undefined when it fits. */
|
|
16
|
+
export declare function templateValueProblem(slot: EffectTemplateSlot, value: unknown): string | undefined;
|
|
17
|
+
/**
|
|
18
|
+
* Every problem with `values` for a template's slots, as sentences: unknown slots, wrong types,
|
|
19
|
+
* out-of-range numbers, text too long. Empty when they fit. Slots left out take their defaults.
|
|
20
|
+
*/
|
|
21
|
+
export declare function checkTemplateValues(slots: readonly EffectTemplateSlot[], values: unknown): string[];
|
|
22
|
+
/** One slot's value as a JSON Schema. */
|
|
23
|
+
export declare function templateSlotSchema(slot: EffectTemplateSlot): JsonSchema;
|
|
24
|
+
/** The values a template takes as a strict JSON Schema (every slot optional; `additionalProperties: false`). */
|
|
25
|
+
export declare function templateValuesSchema(slots: readonly EffectTemplateSlot[]): JsonSchema & {
|
|
26
|
+
type: 'object';
|
|
27
|
+
};
|
|
28
|
+
/** The defaults of a template's text, colour and number slots: an example `values` object to change. */
|
|
29
|
+
export declare function templateDefaultValues(slots: readonly EffectTemplateSlot[]): Record<string, string | number>;
|
|
30
|
+
/** One line on a slot: its name, type, what it takes and its default. */
|
|
31
|
+
export declare function templateSlotSummary(slot: EffectTemplateSlot): string;
|
|
32
|
+
/** Templates matching every word of `query` (in name, id, tags or description) and every tag, best first. */
|
|
33
|
+
export declare function searchTemplateSummaries<T extends EffectTemplateSummary>(catalog: readonly T[], options?: EffectTemplateSearchOptions): T[];
|
|
34
|
+
/** Where a layer sits: its `role`, else `subject` when it has a `rect`, else `background`. */
|
|
35
|
+
export declare const effectLayerRole: (layer: Pick<EffectLayer, "role" | "rect">) => EffectLayerRole;
|
|
36
|
+
/**
|
|
37
|
+
* The image input a layer's subject feeds: `source` when the effect has it, else its first image
|
|
38
|
+
* input; undefined when it takes no picture (a generator: then the layer cannot have a subject).
|
|
39
|
+
*/
|
|
40
|
+
export declare function effectLayerInput(description: Pick<EffectDescription, 'inputs'>): string | undefined;
|
|
41
|
+
/** The uses a layer's effect may have (a transition belongs on `EffectSequenceShot.transition`, a camera move on `camera`). */
|
|
42
|
+
export declare const EFFECT_LAYER_USES: readonly ["generator", "filter", "overlay", "title"];
|
|
43
|
+
/** True for an effect a layer can show. */
|
|
44
|
+
export declare const effectLayerOffered: (e: Pick<EffectSummary, "kind" | "uses">) => boolean;
|
|
45
|
+
/** Problems with one subject, or undefined when it is sound. */
|
|
46
|
+
export declare function effectSubjectProblem(subject: unknown): string | undefined;
|
|
47
|
+
/**
|
|
48
|
+
* Every problem with a sequence's shape, as sentences ("shot 2, layer 1: …"). With `catalog`, also
|
|
49
|
+
* effect ids it does not list, layer effects that cannot be layers and transitions without the
|
|
50
|
+
* use `transition`. Empty when the sequence is sound.
|
|
51
|
+
*/
|
|
52
|
+
export declare function checkEffectSequence(sequence: unknown, catalog?: readonly Pick<EffectSummary, 'id' | 'kind' | 'uses'>[]): string[];
|
|
53
|
+
/** Every effect id a sequence names (layers and transitions), each once. */
|
|
54
|
+
export declare function effectSequenceEffects(sequence: EffectSequence): string[];
|
|
55
|
+
/** Subject slots a sequence leaves for the host (`{ slot }` subjects), each once. */
|
|
56
|
+
export declare function effectSequenceSlots(sequence: EffectSequence): string[];
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helpers for sequence templates and the sequences they fill to (see `EffectSequence`): the
|
|
3
|
+
* values a template takes as a JSON Schema, checking values before asking the provider, checking
|
|
4
|
+
* a sequence before loading it, and which input a layer's subject feeds. Dependency-free.
|
|
5
|
+
*/
|
|
6
|
+
import type { JsonSchema } from '../tools/schema.js';
|
|
7
|
+
import { type EffectDescription, type EffectLayer, type EffectLayerRole, type EffectSequence, type EffectSubjectKind, type EffectSummary, type EffectTemplateSearchOptions, type EffectTemplateSlot, type EffectTemplateSummary } from './types.js';
|
|
8
|
+
export declare const EFFECT_SEQUENCE_NAME: RegExp;
|
|
9
|
+
/** True for a subject slot (`image`, `video`, `svg`). */
|
|
10
|
+
export declare const isSubjectTemplateSlot: (slot: Pick<EffectTemplateSlot, "type">) => boolean;
|
|
11
|
+
/** The kind of a subject (`image`, `video`, `svg`, `text`, `slot`), or undefined when it is none of them. */
|
|
12
|
+
export declare function effectSubjectKind(subject: unknown): EffectSubjectKind | undefined;
|
|
13
|
+
/** What a slot takes, in a few words ("words (up to 40 characters)", "a colour like #FF5A36"). */
|
|
14
|
+
export declare function templateSlotTakes(slot: EffectTemplateSlot): string;
|
|
15
|
+
/** The problem with one value for a slot, as a sentence, or undefined when it fits. */
|
|
16
|
+
export declare function templateValueProblem(slot: EffectTemplateSlot, value: unknown): string | undefined;
|
|
17
|
+
/**
|
|
18
|
+
* Every problem with `values` for a template's slots, as sentences: unknown slots, wrong types,
|
|
19
|
+
* out-of-range numbers, text too long. Empty when they fit. Slots left out take their defaults.
|
|
20
|
+
*/
|
|
21
|
+
export declare function checkTemplateValues(slots: readonly EffectTemplateSlot[], values: unknown): string[];
|
|
22
|
+
/** One slot's value as a JSON Schema. */
|
|
23
|
+
export declare function templateSlotSchema(slot: EffectTemplateSlot): JsonSchema;
|
|
24
|
+
/** The values a template takes as a strict JSON Schema (every slot optional; `additionalProperties: false`). */
|
|
25
|
+
export declare function templateValuesSchema(slots: readonly EffectTemplateSlot[]): JsonSchema & {
|
|
26
|
+
type: 'object';
|
|
27
|
+
};
|
|
28
|
+
/** The defaults of a template's text, colour and number slots: an example `values` object to change. */
|
|
29
|
+
export declare function templateDefaultValues(slots: readonly EffectTemplateSlot[]): Record<string, string | number>;
|
|
30
|
+
/** One line on a slot: its name, type, what it takes and its default. */
|
|
31
|
+
export declare function templateSlotSummary(slot: EffectTemplateSlot): string;
|
|
32
|
+
/** Templates matching every word of `query` (in name, id, tags or description) and every tag, best first. */
|
|
33
|
+
export declare function searchTemplateSummaries<T extends EffectTemplateSummary>(catalog: readonly T[], options?: EffectTemplateSearchOptions): T[];
|
|
34
|
+
/** Where a layer sits: its `role`, else `subject` when it has a `rect`, else `background`. */
|
|
35
|
+
export declare const effectLayerRole: (layer: Pick<EffectLayer, "role" | "rect">) => EffectLayerRole;
|
|
36
|
+
/**
|
|
37
|
+
* The image input a layer's subject feeds: `source` when the effect has it, else its first image
|
|
38
|
+
* input; undefined when it takes no picture (a generator: then the layer cannot have a subject).
|
|
39
|
+
*/
|
|
40
|
+
export declare function effectLayerInput(description: Pick<EffectDescription, 'inputs'>): string | undefined;
|
|
41
|
+
/** The uses a layer's effect may have (a transition belongs on `EffectSequenceShot.transition`, a camera move on `camera`). */
|
|
42
|
+
export declare const EFFECT_LAYER_USES: readonly ["generator", "filter", "overlay", "title"];
|
|
43
|
+
/** True for an effect a layer can show. */
|
|
44
|
+
export declare const effectLayerOffered: (e: Pick<EffectSummary, "kind" | "uses">) => boolean;
|
|
45
|
+
/** Problems with one subject, or undefined when it is sound. */
|
|
46
|
+
export declare function effectSubjectProblem(subject: unknown): string | undefined;
|
|
47
|
+
/**
|
|
48
|
+
* Every problem with a sequence's shape, as sentences ("shot 2, layer 1: …"). With `catalog`, also
|
|
49
|
+
* effect ids it does not list, layer effects that cannot be layers and transitions without the
|
|
50
|
+
* use `transition`. Empty when the sequence is sound.
|
|
51
|
+
*/
|
|
52
|
+
export declare function checkEffectSequence(sequence: unknown, catalog?: readonly Pick<EffectSummary, 'id' | 'kind' | 'uses'>[]): string[];
|
|
53
|
+
/** Every effect id a sequence names (layers and transitions), each once. */
|
|
54
|
+
export declare function effectSequenceEffects(sequence: EffectSequence): string[];
|
|
55
|
+
/** Subject slots a sequence leaves for the host (`{ slot }` subjects), each once. */
|
|
56
|
+
export declare function effectSequenceSlots(sequence: EffectSequence): string[];
|