@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.
Files changed (62) hide show
  1. package/dist/animation-editor/compile.d.cts +3 -0
  2. package/dist/animation-editor/compile.d.ts +3 -0
  3. package/dist/animation-editor/controller.d.cts +67 -2
  4. package/dist/animation-editor/controller.d.ts +67 -2
  5. package/dist/animation-editor/edit.d.cts +1 -1
  6. package/dist/animation-editor/edit.d.ts +1 -1
  7. package/dist/animation-editor/evaluate.d.cts +8 -1
  8. package/dist/animation-editor/evaluate.d.ts +8 -1
  9. package/dist/animation-editor/index.cjs +1202 -371
  10. package/dist/animation-editor/index.d.cts +3 -0
  11. package/dist/animation-editor/index.d.ts +3 -0
  12. package/dist/animation-editor/index.js +1032 -201
  13. package/dist/animation-editor/issues.d.cts +28 -0
  14. package/dist/animation-editor/issues.d.ts +28 -0
  15. package/dist/animation-editor/layer-edit.d.cts +55 -0
  16. package/dist/animation-editor/layer-edit.d.ts +55 -0
  17. package/dist/animation-editor/layer-tools.d.cts +11 -0
  18. package/dist/animation-editor/layer-tools.d.ts +11 -0
  19. package/dist/animation-editor/layers.d.cts +166 -0
  20. package/dist/animation-editor/layers.d.ts +166 -0
  21. package/dist/animation-editor/parse.d.cts +2 -0
  22. package/dist/animation-editor/parse.d.ts +2 -0
  23. package/dist/animation-editor/types.d.cts +44 -1
  24. package/dist/animation-editor/types.d.ts +44 -1
  25. package/dist/canvas/index.cjs +10 -10
  26. package/dist/canvas/index.js +4 -4
  27. package/dist/chunk-6RZVFYGJ.cjs +255 -0
  28. package/dist/{chunk-C73U5UI3.cjs → chunk-A7PQNIBX.cjs} +14 -14
  29. package/dist/{chunk-ERJA5CGT.cjs → chunk-DGWOGQJ5.cjs} +8 -1
  30. package/dist/{chunk-TYCJGFCF.js → chunk-EUKY4KFX.js} +8 -1
  31. package/dist/chunk-I277KJLQ.js +255 -0
  32. package/dist/{chunk-OPSK22DL.cjs → chunk-JAOSL334.cjs} +24 -7
  33. package/dist/{chunk-TCZ2J7PR.js → chunk-SIK3LT6M.js} +26 -9
  34. package/dist/{chunk-SBPGIZQN.js → chunk-TEFQISBY.js} +1 -1
  35. package/dist/{chunk-CSM5T6SE.js → chunk-WDDUPWVG.js} +1 -1
  36. package/dist/{chunk-5T3H7CGG.cjs → chunk-ZQIWBJGH.cjs} +7 -7
  37. package/dist/effects/conformance.d.cts +4 -1
  38. package/dist/effects/conformance.d.ts +4 -1
  39. package/dist/effects/errors.d.cts +6 -1
  40. package/dist/effects/errors.d.ts +6 -1
  41. package/dist/effects/fake-templates.d.cts +17 -0
  42. package/dist/effects/fake-templates.d.ts +17 -0
  43. package/dist/effects/fake.d.cts +6 -1
  44. package/dist/effects/fake.d.ts +6 -1
  45. package/dist/effects/index.cjs +322 -67
  46. package/dist/effects/index.d.cts +1 -0
  47. package/dist/effects/index.d.ts +1 -0
  48. package/dist/effects/index.js +258 -3
  49. package/dist/effects/templates.d.cts +56 -0
  50. package/dist/effects/templates.d.ts +56 -0
  51. package/dist/effects/types.d.cts +212 -0
  52. package/dist/effects/types.d.ts +212 -0
  53. package/dist/image-editor/index.cjs +16 -16
  54. package/dist/image-editor/index.js +4 -4
  55. package/dist/paint-editor/index.cjs +10 -10
  56. package/dist/paint-editor/index.js +5 -5
  57. package/dist/vector/index.cjs +6 -6
  58. package/dist/vector/index.js +1 -1
  59. package/dist/video-editor/index.cjs +339 -339
  60. package/dist/video-editor/index.js +5 -5
  61. package/package.json +1 -1
  62. package/skills/pixerate-animation-editor/SKILL.md +37 -0
@@ -7,6 +7,7 @@
7
7
  export * from './types.cjs';
8
8
  export * from './errors.cjs';
9
9
  export * from './helpers.cjs';
10
+ export * from './templates.cjs';
10
11
  export * from './conformance.cjs';
11
12
  export * from './fake.cjs';
12
13
  export * from './tools.cjs';
@@ -7,6 +7,7 @@
7
7
  export * from './types.js';
8
8
  export * from './errors.js';
9
9
  export * from './helpers.js';
10
+ export * from './templates.js';
10
11
  export * from './conformance.js';
11
12
  export * from './fake.js';
12
13
  export * from './tools.js';
@@ -3,7 +3,28 @@ import {
3
3
  } from "../chunk-N4ZXW3WB.js";
4
4
  import {
5
5
  createEffectAuthoringSession
6
- } from "../chunk-SBPGIZQN.js";
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-TCZ2J7PR.js";
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
- srgbToLinear
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[];