@pixerate/editor 0.231.0 → 0.232.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 (38) hide show
  1. package/dist/animation-editor/index.cjs +25 -25
  2. package/dist/animation-editor/index.js +1 -1
  3. package/dist/canvas/index.cjs +7 -7
  4. package/dist/canvas/index.js +1 -1
  5. package/dist/{chunk-OPSK22DL.cjs → chunk-2K5TELHV.cjs} +19 -2
  6. package/dist/{chunk-CSM5T6SE.js → chunk-6QLTUGMO.js} +1 -1
  7. package/dist/{chunk-5T3H7CGG.cjs → chunk-A653N65Q.cjs} +7 -7
  8. package/dist/{chunk-SBPGIZQN.js → chunk-MUSZYMBX.js} +1 -1
  9. package/dist/{chunk-TCZ2J7PR.js → chunk-PQYDJ2AV.js} +18 -1
  10. package/dist/{chunk-C73U5UI3.cjs → chunk-RG4O6K2A.cjs} +14 -14
  11. package/dist/effects/conformance.d.cts +4 -1
  12. package/dist/effects/conformance.d.ts +4 -1
  13. package/dist/effects/errors.d.cts +6 -1
  14. package/dist/effects/errors.d.ts +6 -1
  15. package/dist/effects/fake-templates.d.cts +17 -0
  16. package/dist/effects/fake-templates.d.ts +17 -0
  17. package/dist/effects/fake.d.cts +6 -1
  18. package/dist/effects/fake.d.ts +6 -1
  19. package/dist/effects/index.cjs +537 -74
  20. package/dist/effects/index.d.cts +1 -0
  21. package/dist/effects/index.d.ts +1 -0
  22. package/dist/effects/index.js +466 -3
  23. package/dist/effects/templates.d.cts +56 -0
  24. package/dist/effects/templates.d.ts +56 -0
  25. package/dist/effects/types.d.cts +212 -0
  26. package/dist/effects/types.d.ts +212 -0
  27. package/dist/image-editor/controller.d.cts +12 -0
  28. package/dist/image-editor/controller.d.ts +12 -0
  29. package/dist/image-editor/index.cjs +189 -144
  30. package/dist/image-editor/index.js +48 -3
  31. package/dist/paint-editor/index.cjs +7 -7
  32. package/dist/paint-editor/index.js +2 -2
  33. package/dist/vector/index.cjs +6 -6
  34. package/dist/vector/index.js +1 -1
  35. package/dist/video-editor/index.cjs +329 -329
  36. package/dist/video-editor/index.js +3 -3
  37. package/package.json +1 -1
  38. package/skills/pixerate-animation-editor/SKILL.md +37 -0
@@ -3,7 +3,7 @@
3
3
  var _chunk4XSBOGMKcjs = require('../chunk-4XSBOGMK.cjs');
4
4
 
5
5
 
6
- var _chunkC73U5UI3cjs = require('../chunk-C73U5UI3.cjs');
6
+ var _chunkRG4O6K2Acjs = require('../chunk-RG4O6K2A.cjs');
7
7
 
8
8
 
9
9
  var _chunkPY4GWSE2cjs = require('../chunk-PY4GWSE2.cjs');
@@ -45,15 +45,249 @@ var _chunkPY4GWSE2cjs = require('../chunk-PY4GWSE2.cjs');
45
45
 
46
46
 
47
47
 
48
- var _chunkOPSK22DLcjs = require('../chunk-OPSK22DL.cjs');
48
+
49
+
50
+
51
+
52
+
53
+ var _chunk2K5TELHVcjs = require('../chunk-2K5TELHV.cjs');
49
54
  require('../chunk-WOFXZ3XU.cjs');
50
55
  require('../chunk-FJ2MSI43.cjs');
51
56
 
52
57
 
53
58
  var _chunkDWJJI6RTcjs = require('../chunk-DWJJI6RT.cjs');
54
59
 
60
+ // src/effects/templates.ts
61
+ var SLOT_NAME = /^[A-Za-z][\w-]*$/;
62
+ var COLOR = /^#[0-9a-fA-F]{6}$/;
63
+ var EFFECT_SEQUENCE_NAME = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
64
+ var isObject = (v) => !!v && typeof v === "object" && !Array.isArray(v);
65
+ var isSubjectTemplateSlot = (slot) => slot.type === "image" || slot.type === "video" || slot.type === "svg";
66
+ function effectSubjectKind(subject) {
67
+ if (!isObject(subject)) return void 0;
68
+ for (const k of ["slot", "image", "video", "svg", "text"]) if (typeof subject[k] === "string") return k;
69
+ return void 0;
70
+ }
71
+ var typeName = (value) => value === null ? "null" : Array.isArray(value) ? "a list" : typeof value === "object" ? "an object" : typeof value === "string" ? `the words ${JSON.stringify(value.length > 40 ? `${value.slice(0, 40)}\u2026` : value)}` : `${typeof value === "number" ? "the number" : "the value"} ${String(value)}`;
72
+ function range(slot) {
73
+ const whole = slot.integer ? "whole number" : "number";
74
+ if (slot.min !== void 0 && slot.max !== void 0) return `a ${whole} from ${slot.min} to ${slot.max}`;
75
+ if (slot.min !== void 0) return `a ${whole} of at least ${slot.min}`;
76
+ if (slot.max !== void 0) return `a ${whole} of at most ${slot.max}`;
77
+ return `a ${whole}`;
78
+ }
79
+ function templateSlotTakes(slot) {
80
+ switch (slot.type) {
81
+ case "text":
82
+ return `words${slot.maxLength !== void 0 ? ` (up to ${slot.maxLength} characters)` : ""}`;
83
+ case "color":
84
+ return `a colour written #RRGGBB, like "${slot.default}"`;
85
+ case "number":
86
+ return range(slot);
87
+ case "video":
88
+ return "a video URL";
89
+ case "svg":
90
+ return "SVG markup or an SVG URL";
91
+ default:
92
+ return "a picture: a URL, a data: URL or <svg> markup";
93
+ }
94
+ }
95
+ function templateValueProblem(slot, value) {
96
+ const no = (extra = "") => `Slot "${slot.name}" takes ${templateSlotTakes(slot)}${extra}, not ${typeName(value)}.`;
97
+ switch (slot.type) {
98
+ case "text":
99
+ if (typeof value !== "string") return no();
100
+ if (slot.maxLength !== void 0 && value.length > slot.maxLength) return `Slot "${slot.name}" takes up to ${slot.maxLength} characters; the value has ${value.length}. Shorten it.`;
101
+ return void 0;
102
+ case "color":
103
+ return typeof value === "string" && COLOR.test(value) ? void 0 : no();
104
+ case "number":
105
+ if (typeof value !== "number" || !Number.isFinite(value)) return no();
106
+ if (slot.integer && !Number.isInteger(value)) return `Slot "${slot.name}" takes ${range(slot)}; ${value} is not whole.`;
107
+ if (slot.min !== void 0 && value < slot.min || slot.max !== void 0 && value > slot.max) return `Slot "${slot.name}" takes ${range(slot)}; ${value} is out of range.`;
108
+ return void 0;
109
+ default: {
110
+ const host = ` (or { "slot": "${slot.name}" } to leave it for the host)`;
111
+ if (typeof value === "string") return value.trim() ? void 0 : no(host);
112
+ const kind = effectSubjectKind(value);
113
+ if (!kind) return no(host);
114
+ if (kind === "slot") return SLOT_NAME.test(value.slot) ? void 0 : `Slot "${slot.name}" left for the host is { "slot": name }, the name letters, digits, "-" and "_", starting with a letter.`;
115
+ const fits = kind === slot.type || slot.type === "image" && kind === "svg";
116
+ if (!fits) return `Slot "${slot.name}" takes { "${slot.type}": \u2026 }${slot.type === "image" ? ' or { "svg": \u2026 }' : ""}, not { "${kind}": \u2026 }.`;
117
+ return value[kind].trim() ? void 0 : `Slot "${slot.name}"'s "${kind}" is a non-empty string.`;
118
+ }
119
+ }
120
+ }
121
+ var slotList = (slots) => slots.length ? `the slots are ${slots.map((s) => `${s.name} (${s.type})`).join(", ")}` : "the template has no slots";
122
+ function checkTemplateValues(slots, values) {
123
+ if (values === void 0) return [];
124
+ if (!isObject(values)) return [`Values are an object of slot names to values; ${slotList(slots)}.`];
125
+ const byName = new Map(slots.map((s) => [s.name, s]));
126
+ const errors = [];
127
+ for (const [name, value] of Object.entries(values)) {
128
+ const slot = byName.get(name);
129
+ if (!slot) errors.push(`There is no slot "${name}"; ${slotList(slots)}.`);
130
+ else if (value !== void 0) {
131
+ const problem = templateValueProblem(slot, value);
132
+ if (problem) errors.push(problem);
133
+ }
134
+ }
135
+ return errors;
136
+ }
137
+ function templateSlotSchema(slot) {
138
+ const about = `${slot.label}${slot.description ? `: ${slot.description}` : ""}.`;
139
+ switch (slot.type) {
140
+ case "text":
141
+ return { type: "string", ...slot.maxLength !== void 0 ? { maxLength: slot.maxLength } : {}, description: `${about} Words${slot.maxLength !== void 0 ? `, up to ${slot.maxLength} characters` : ""}. Default ${JSON.stringify(slot.default)}.` };
142
+ case "color":
143
+ return { type: "string", pattern: COLOR.source, description: `${about} A colour as #RRGGBB. Default ${slot.default}.` };
144
+ case "number":
145
+ return {
146
+ type: slot.integer ? "integer" : "number",
147
+ ...slot.min !== void 0 ? { minimum: slot.min } : {},
148
+ ...slot.max !== void 0 ? { maximum: slot.max } : {},
149
+ description: `${about} ${range(slot).replace(/^a /, "A ")}. Default ${slot.default}.`
150
+ };
151
+ default: {
152
+ const key = slot.type;
153
+ const object2 = (k, what) => ({ type: "object", properties: { [k]: { type: "string", description: what } }, required: [k], additionalProperties: false, description: `{ "${k}": \u2026 }` });
154
+ return {
155
+ anyOf: [
156
+ { type: "string", minLength: 1, description: key === "video" ? "A video URL." : key === "svg" ? "SVG markup or an SVG URL." : "A picture URL, a data: URL or <svg> markup." },
157
+ object2(key, key === "video" ? "A video URL." : key === "svg" ? "SVG markup or an SVG URL." : "A picture URL or a data: URL."),
158
+ ...key === "image" ? [object2("svg", "SVG markup.")] : [],
159
+ object2("slot", "A slot name, to leave the subject for the host to fill.")
160
+ ],
161
+ description: `${about} ${templateSlotTakes(slot).replace(/^a /, "A ")}. ${slot.hasDefault ? "Default: a placeholder picture." : "No default: left out, the host fills it."}`
162
+ };
163
+ }
164
+ }
165
+ }
166
+ function templateValuesSchema(slots) {
167
+ return {
168
+ type: "object",
169
+ properties: Object.fromEntries(slots.map((s) => [s.name, templateSlotSchema(s)])),
170
+ additionalProperties: false,
171
+ description: `Slot values by name; slots left out take their defaults. ${slots.length ? `Slots: ${slots.map((s) => s.name).join(", ")}.` : "This template has no slots."}`
172
+ };
173
+ }
174
+ function templateDefaultValues(slots) {
175
+ const out = {};
176
+ for (const s of slots) if (!isSubjectTemplateSlot(s)) out[s.name] = s.default;
177
+ return out;
178
+ }
179
+ function templateSlotSummary(slot) {
180
+ const fallback = isSubjectTemplateSlot(slot) ? slot.hasDefault ? "a placeholder by default" : "the host fills it when none is given" : `default ${JSON.stringify(slot.default)}`;
181
+ return `${slot.name} (${slot.type}): ${slot.label}; takes ${templateSlotTakes(slot)}; ${fallback}.`;
182
+ }
183
+ function searchTemplateSummaries(catalog, options = {}) {
184
+ const words = (_nullishCoalesce(options.query, () => ( ""))).toLowerCase().split(/\s+/).filter(Boolean);
185
+ const scored = [];
186
+ for (const t of catalog) {
187
+ if (!_chunk2K5TELHVcjs.hasEffectTags.call(void 0, t, options.tags)) continue;
188
+ let score = 0;
189
+ const name = t.name.toLowerCase();
190
+ const rest = [t.id, ..._nullishCoalesce(t.tags, () => ( [])), t.description].join(" ").toLowerCase();
191
+ if (!words.every((w) => name.includes(w) || rest.includes(w))) continue;
192
+ for (const w of words) score += name.includes(w) ? 2 : 1;
193
+ scored.push({ t, score });
194
+ }
195
+ scored.sort((a, b) => b.score - a.score);
196
+ const out = scored.map((s) => s.t);
197
+ return options.limit !== void 0 ? out.slice(0, Math.max(0, options.limit)) : out;
198
+ }
199
+ var effectLayerRole = (layer) => _nullishCoalesce(layer.role, () => ( (layer.rect ? "subject" : "background")));
200
+ function effectLayerInput(description) {
201
+ const images = description.inputs.filter((i) => i.kind === "image");
202
+ return _optionalChain([(_nullishCoalesce(images.find((i) => i.name === "source"), () => ( images.find((i) => i.name !== "from" && i.name !== "to")))), 'optionalAccess', _ => _.name]);
203
+ }
204
+ var EFFECT_LAYER_USES = ["generator", "filter", "overlay", "title"];
205
+ var effectLayerOffered = (e) => (e.kind === "shader" || e.kind === "vector") && e.uses.some((u) => EFFECT_LAYER_USES.includes(u));
206
+ var isRect = (r) => isObject(r) && ["x", "y", "width", "height"].every((k) => Number.isFinite(r[k])) && r.width > 0 && r.height > 0;
207
+ var isLayerTime = (t) => typeof t === "number" && Number.isFinite(t) && t >= 0 || isObject(t) && Number.isInteger(t.shots) && t.shots >= 1;
208
+ function effectSubjectProblem(subject) {
209
+ const kind = effectSubjectKind(subject);
210
+ if (!kind) return `a subject is one of { image }, { video }, { svg }, { text } or { slot }, not ${typeName(subject)}`;
211
+ if (!subject[kind].trim()) return `a subject's "${kind}" is a non-empty string`;
212
+ return void 0;
213
+ }
214
+ function checkEffectSequence(sequence, catalog) {
215
+ const problems = [];
216
+ if (!isObject(sequence)) return ["A sequence is an object with name, stage and shots."];
217
+ if (typeof sequence.name !== "string" || !sequence.name) problems.push("The sequence needs a name.");
218
+ const stage = sequence.stage;
219
+ if (!isObject(stage) || !(Number(stage.width) > 0) || !(Number(stage.height) > 0)) problems.push("The sequence needs a stage { width, height } in pixels, both > 0.");
220
+ if (!Array.isArray(sequence.shots) || !sequence.shots.length) return [...problems, "The sequence needs at least one shot."];
221
+ const byId = catalog ? new Map(catalog.map((e) => [e.id, e])) : void 0;
222
+ const ids = /* @__PURE__ */ new Set();
223
+ sequence.shots.forEach((shot, i) => {
224
+ const at = `shot ${i + 1}`;
225
+ if (!isObject(shot)) return void problems.push(`${at} is not an object.`);
226
+ if (!(Number.isFinite(shot.hold) && shot.hold >= 0)) problems.push(`${at}: hold must be ms \u2265 0.`);
227
+ for (const k of ["title", "caption"]) if (shot[k] !== void 0 && typeof shot[k] !== "string") problems.push(`${at}: ${k} must be words.`);
228
+ if (shot.camera !== void 0) {
229
+ const camera = shot.camera;
230
+ if (!isObject(camera)) problems.push(`${at}: camera must be an object.`);
231
+ else if (camera.framing !== void 0 && !isRect(camera.framing)) problems.push(`${at}: camera.framing must be { x, y, width, height } with width and height > 0.`);
232
+ }
233
+ if (!Array.isArray(shot.layers)) problems.push(`${at}: layers must be a list (it may be empty).`);
234
+ else
235
+ shot.layers.forEach((layer, j) => {
236
+ const where = `${at}, layer ${j + 1}`;
237
+ if (!isObject(layer)) return void problems.push(`${where} is not an object.`);
238
+ if (layer.id !== void 0) {
239
+ if (typeof layer.id !== "string" || !layer.id) problems.push(`${where}: id must be a non-empty string.`);
240
+ else if (ids.has(layer.id)) problems.push(`${where}: id "${layer.id}" is used twice.`);
241
+ else ids.add(layer.id);
242
+ }
243
+ if (layer.effect === void 0 && layer.subject === void 0) problems.push(`${where} has neither an effect nor a subject.`);
244
+ if (layer.effect !== void 0 && (typeof layer.effect !== "string" || !layer.effect)) problems.push(`${where}: effect must be an effect id.`);
245
+ else if (typeof layer.effect === "string" && byId) {
246
+ const e = byId.get(layer.effect);
247
+ if (!e) problems.push(`${where}: the provider has no effect "${layer.effect}".`);
248
+ else if (!effectLayerOffered(e)) problems.push(`${where}: "${layer.effect}" (${e.kind}, ${e.uses.join("/")}) cannot be a layer; a layer's effect is a generator, filter, overlay or title.`);
249
+ }
250
+ if (layer.subject !== void 0) {
251
+ const p = effectSubjectProblem(layer.subject);
252
+ if (p) problems.push(`${where}: ${p}.`);
253
+ }
254
+ if (layer.role !== void 0 && !_chunk2K5TELHVcjs.EFFECT_LAYER_ROLES.includes(layer.role)) problems.push(`${where}: role is one of ${_chunk2K5TELHVcjs.EFFECT_LAYER_ROLES.join(", ")}.`);
255
+ if (layer.rect !== void 0 && !isRect(layer.rect)) problems.push(`${where}: rect must be { x, y, width, height } with width and height > 0.`);
256
+ for (const k of ["from", "until"]) if (layer[k] !== void 0 && !isLayerTime(layer[k])) problems.push(`${where}: ${k} is ms \u2265 0 or { shots: n } with n \u2265 1.`);
257
+ if (layer.opacity !== void 0 && !(typeof layer.opacity === "number" && layer.opacity >= 0 && layer.opacity <= 1)) problems.push(`${where}: opacity is 0\u20131.`);
258
+ if (layer.fade !== void 0 && !(typeof layer.fade === "number" && layer.fade >= 0)) problems.push(`${where}: fade is ms \u2265 0.`);
259
+ if (layer.values !== void 0 && !isObject(layer.values)) problems.push(`${where}: values must be an object of control values.`);
260
+ });
261
+ if (shot.transition !== void 0) {
262
+ const t = shot.transition;
263
+ if (i === 0) problems.push(`${at} has a transition, but there is no shot before it.`);
264
+ if (!isObject(t) || typeof t.effect !== "string" || !t.effect) problems.push(`${at}: transition needs an effect id.`);
265
+ else {
266
+ if (t.ms !== void 0 && !(typeof t.ms === "number" && t.ms > 0)) problems.push(`${at}: transition ms must be > 0.`);
267
+ const e = _optionalChain([byId, 'optionalAccess', _2 => _2.get, 'call', _3 => _3(t.effect)]);
268
+ if (byId && !e) problems.push(`${at}: the provider has no transition "${t.effect}".`);
269
+ else if (e && !e.uses.includes("transition")) problems.push(`${at}: "${t.effect}" is not a transition (its uses are ${e.uses.join(", ")}).`);
270
+ }
271
+ }
272
+ });
273
+ return problems;
274
+ }
275
+ function effectSequenceEffects(sequence) {
276
+ const out = /* @__PURE__ */ new Set();
277
+ for (const shot of sequence.shots) {
278
+ for (const l of shot.layers) if (l.effect) out.add(l.effect);
279
+ if (shot.transition) out.add(shot.transition.effect);
280
+ }
281
+ return [...out];
282
+ }
283
+ function effectSequenceSlots(sequence) {
284
+ const out = /* @__PURE__ */ new Set();
285
+ for (const shot of sequence.shots) for (const l of shot.layers) if (l.subject && "slot" in l.subject) out.add(l.subject.slot);
286
+ return [...out];
287
+ }
288
+
55
289
  // src/effects/conformance.ts
56
- var codeOf = (e) => _chunkOPSK22DLcjs.isEffectError.call(void 0, e) ? e.code : e instanceof Error ? `untyped ${e.name}: ${e.message}` : String(e);
290
+ var codeOf = (e) => _chunk2K5TELHVcjs.isEffectError.call(void 0, e) ? e.code : e instanceof Error ? `untyped ${e.name}: ${e.message}` : String(e);
57
291
  async function rejectsWith(code, run) {
58
292
  try {
59
293
  await run();
@@ -67,26 +301,26 @@ function checkSummary(e, issues) {
67
301
  const at = (message) => issues.push({ effectId: e.id, message });
68
302
  if (!e.id || typeof e.id !== "string") at("summary has no id");
69
303
  if (!e.name) at("summary has no name");
70
- if (!_chunkOPSK22DLcjs.EFFECT_KINDS.includes(e.kind)) at(`kind "${e.kind}" is not one of ${_chunkOPSK22DLcjs.EFFECT_KINDS.join(", ")}`);
304
+ if (!_chunk2K5TELHVcjs.EFFECT_KINDS.includes(e.kind)) at(`kind "${e.kind}" is not one of ${_chunk2K5TELHVcjs.EFFECT_KINDS.join(", ")}`);
71
305
  if (!e.category) at("summary has no category");
72
306
  if (!Array.isArray(e.uses) || !e.uses.length) at("summary has no uses");
73
- for (const u of _nullishCoalesce(e.uses, () => ( []))) if (!_chunkOPSK22DLcjs.EFFECT_USES.includes(u)) at(`use "${u}" is not one of ${_chunkOPSK22DLcjs.EFFECT_USES.join(", ")}`);
307
+ for (const u of _nullishCoalesce(e.uses, () => ( []))) if (!_chunk2K5TELHVcjs.EFFECT_USES.includes(u)) at(`use "${u}" is not one of ${_chunk2K5TELHVcjs.EFFECT_USES.join(", ")}`);
74
308
  if (typeof e.transparent !== "boolean") at("transparent is not a boolean");
75
309
  if (typeof e.loop !== "boolean") at("loop is not a boolean");
76
310
  if (e.duration !== void 0 && !(e.duration > 0)) at("duration must be a positive number of ms when present");
77
311
  if (e.backgroundOpacity !== void 0 && (typeof e.backgroundOpacity !== "string" || !e.backgroundOpacity)) at("backgroundOpacity must name a control when present");
78
312
  if (e.kind === "camera") {
79
- if (_optionalChain([e, 'access', _ => _.uses, 'optionalAccess', _2 => _2.length]) !== 1 || e.uses[0] !== "camera") at('a camera effect must have exactly the use "camera"');
313
+ if (_optionalChain([e, 'access', _4 => _4.uses, 'optionalAccess', _5 => _5.length]) !== 1 || e.uses[0] !== "camera") at('a camera effect must have exactly the use "camera"');
80
314
  const m = e.camera;
81
315
  if (!m) at("a camera effect needs camera: { role, durationMs }");
82
316
  else {
83
- if (!_chunkOPSK22DLcjs.CAMERA_MOVE_ROLES.includes(m.role)) at(`camera.role "${m.role}" is not one of ${_chunkOPSK22DLcjs.CAMERA_MOVE_ROLES.join(", ")}`);
317
+ if (!_chunk2K5TELHVcjs.CAMERA_MOVE_ROLES.includes(m.role)) at(`camera.role "${m.role}" is not one of ${_chunk2K5TELHVcjs.CAMERA_MOVE_ROLES.join(", ")}`);
84
318
  if (!(Number.isFinite(m.durationMs) && m.durationMs >= 0)) at("camera.durationMs must be a number of ms \u2265 0");
85
319
  if (m.cut !== void 0 && !(m.cut >= 0 && m.cut <= 1)) at("camera.cut must be 0\u20131 when present");
86
320
  if (e.duration !== void 0 && e.duration !== m.durationMs) at(`duration ${e.duration} differs from camera.durationMs ${m.durationMs}`);
87
321
  }
88
322
  } else {
89
- if (_optionalChain([e, 'access', _3 => _3.uses, 'optionalAccess', _4 => _4.includes, 'call', _5 => _5("camera")])) at('only camera effects may have the use "camera"');
323
+ if (_optionalChain([e, 'access', _6 => _6.uses, 'optionalAccess', _7 => _7.includes, 'call', _8 => _8("camera")])) at('only camera effects may have the use "camera"');
90
324
  if (e.camera !== void 0) at("only camera effects may have camera");
91
325
  }
92
326
  }
@@ -95,19 +329,19 @@ function checkDescription(id, d, issues) {
95
329
  if (d.id !== id) at(`describe("${id}") returned id "${d.id}"`);
96
330
  const c = d.controls;
97
331
  if (!c || c.type !== "object") at("controls is not an object schema");
98
- if (_optionalChain([c, 'optionalAccess', _6 => _6.additionalProperties]) !== false) at("controls must set additionalProperties: false");
99
- for (const [name, schema] of Object.entries(_nullishCoalesce(_optionalChain([c, 'optionalAccess', _7 => _7.properties]), () => ( {})))) {
332
+ if (_optionalChain([c, 'optionalAccess', _9 => _9.additionalProperties]) !== false) at("controls must set additionalProperties: false");
333
+ for (const [name, schema] of Object.entries(_nullishCoalesce(_optionalChain([c, 'optionalAccess', _10 => _10.properties]), () => ( {})))) {
100
334
  if (!schema.description || !String(schema.description).trim()) at(`control "${name}" has no description`);
101
335
  if (!(name in (_nullishCoalesce(d.defaults, () => ( {}))))) at(`control "${name}" has no default`);
102
336
  }
103
- for (const name of Object.keys(_nullishCoalesce(d.defaults, () => ( {})))) if (!(name in (_nullishCoalesce(_optionalChain([c, 'optionalAccess', _8 => _8.properties]), () => ( {}))))) at(`default "${name}" is not a control`);
337
+ for (const name of Object.keys(_nullishCoalesce(d.defaults, () => ( {})))) if (!(name in (_nullishCoalesce(_optionalChain([c, 'optionalAccess', _11 => _11.properties]), () => ( {}))))) at(`default "${name}" is not a control`);
104
338
  if (d.backgroundOpacity !== void 0) {
105
- const control = _optionalChain([c, 'optionalAccess', _9 => _9.properties, 'optionalAccess', _10 => _10[d.backgroundOpacity]]);
339
+ const control = _optionalChain([c, 'optionalAccess', _12 => _12.properties, 'optionalAccess', _13 => _13[d.backgroundOpacity]]);
106
340
  if (!control) at(`backgroundOpacity "${d.backgroundOpacity}" is not a control`);
107
341
  else if (control.type !== "number" || control.minimum !== 0 || control.maximum !== 1) at(`backgroundOpacity "${d.backgroundOpacity}" must be a number control from 0 to 1`);
108
342
  }
109
- for (const e of _chunkOPSK22DLcjs.effectValueErrors.call(void 0, d, d.defaults)) at(`default ${e.path}: ${e.message}`);
110
- for (const p of _nullishCoalesce(d.presets, () => ( []))) for (const e of _chunkOPSK22DLcjs.effectValueErrors.call(void 0, d, p.values)) at(`preset "${p.name}" ${e.path}: ${e.message}`);
343
+ for (const e of _chunk2K5TELHVcjs.effectValueErrors.call(void 0, d, d.defaults)) at(`default ${e.path}: ${e.message}`);
344
+ for (const p of _nullishCoalesce(d.presets, () => ( []))) for (const e of _chunk2K5TELHVcjs.effectValueErrors.call(void 0, d, p.values)) at(`preset "${p.name}" ${e.path}: ${e.message}`);
111
345
  for (const input2 of _nullishCoalesce(d.inputs, () => ( []))) {
112
346
  if (!input2.name || !input2.description) at("every input needs a name and a description");
113
347
  if (input2.kind !== "image" && input2.kind !== "audio") at(`input "${input2.name}" has kind "${input2.kind}"`);
@@ -118,7 +352,7 @@ function checkDescription(id, d, issues) {
118
352
  }
119
353
  }
120
354
  function grey(size) {
121
- const p = _chunkOPSK22DLcjs.createEffectPixels.call(void 0, size, size);
355
+ const p = _chunk2K5TELHVcjs.createEffectPixels.call(void 0, size, size);
122
356
  p.data.fill(128);
123
357
  return p;
124
358
  }
@@ -135,7 +369,7 @@ async function checkRender(provider, d, size, issues) {
135
369
  }
136
370
  try {
137
371
  const out = await renderer.render({ time: 0, inputs });
138
- if (!_chunkOPSK22DLcjs.isEffectPixels.call(void 0, out)) at("render did not return EffectPixels");
372
+ if (!_chunk2K5TELHVcjs.isEffectPixels.call(void 0, out)) at("render did not return EffectPixels");
139
373
  else if (out.width !== size || out.height !== size || out.data.length !== size * size * 4) at(`render returned ${out.width}\xD7${out.height}, not ${size}\xD7${size}`);
140
374
  } catch (e) {
141
375
  at(`render failed: ${codeOf(e)}`);
@@ -165,10 +399,10 @@ async function checkCamera(provider, d, issues) {
165
399
  at("cameraView must be synchronous; it returned a Promise");
166
400
  return;
167
401
  }
168
- if (!_chunkOPSK22DLcjs.isCameraView.call(void 0, view)) at(`cameraView at u ${u} is not a CameraView (zoom > 0, finite scrollX and scrollY): ${JSON.stringify(view)}`);
402
+ if (!_chunk2K5TELHVcjs.isCameraView.call(void 0, view)) at(`cameraView at u ${u} is not a CameraView (zoom > 0, finite scrollX and scrollY): ${JSON.stringify(view)}`);
169
403
  else views.push(view);
170
404
  const again = provider.cameraView(d.id, ctx(u));
171
- if (_chunkOPSK22DLcjs.isCameraView.call(void 0, view) && !sameView(view, again)) at(`cameraView is not pure: two calls at u ${u} gave different views`);
405
+ if (_chunk2K5TELHVcjs.isCameraView.call(void 0, view) && !sameView(view, again)) at(`cameraView is not pure: two calls at u ${u} gave different views`);
172
406
  } catch (e) {
173
407
  at(`cameraView at u ${u} failed: ${codeOf(e)}`);
174
408
  }
@@ -178,10 +412,10 @@ async function checkCamera(provider, d, issues) {
178
412
  if (provider.sampleCameraMove && views.length === 5) {
179
413
  try {
180
414
  const sample = await provider.sampleCameraMove(d.id, { from: WIDE, to, ms, stage: STAGE, fps: 10 });
181
- const keys = _optionalChain([sample, 'optionalAccess', _11 => _11.keys]);
415
+ const keys = _optionalChain([sample, 'optionalAccess', _14 => _14.keys]);
182
416
  if (!Array.isArray(keys) || keys.length < 2) at("sampleCameraMove returned fewer than two keys");
183
417
  else {
184
- if (keys.some((k, i) => !_chunkOPSK22DLcjs.isCameraView.call(void 0, k.view) || !Number.isFinite(k.t) || i > 0 && k.t < keys[i - 1].t)) at("sampleCameraMove keys must be CameraViews in time order");
418
+ if (keys.some((k, i) => !_chunk2K5TELHVcjs.isCameraView.call(void 0, k.view) || !Number.isFinite(k.t) || i > 0 && k.t < keys[i - 1].t)) at("sampleCameraMove keys must be CameraViews in time order");
185
419
  if (keys[0].t !== 0 || keys[keys.length - 1].t !== ms) at(`sampleCameraMove keys must run from 0 to ${ms} ms, got ${keys[0].t} to ${keys[keys.length - 1].t}`);
186
420
  else if (!near(keys[0].view, views[0]) || !near(keys[keys.length - 1].view, views[4])) at("sampleCameraMove disagrees with cameraView at the start or end of the move");
187
421
  if (camera.cut !== void 0 && sample.cut === void 0) at("sampleCameraMove gave no cut for a move that cuts");
@@ -191,20 +425,107 @@ async function checkCamera(provider, d, issues) {
191
425
  }
192
426
  }
193
427
  }
428
+ var wrongValue = (slot) => slot.type === "number" ? "not a number" : slot.type === "text" ? 42 : slot.type === "color" ? "blue" : 42;
429
+ function checkSlot(templateId, slot, issues) {
430
+ const at = (message) => issues.push({ templateId, message: `slot ${JSON.stringify(_optionalChain([slot, 'optionalAccess', _15 => _15.name]))}: ${message}` });
431
+ 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');
432
+ if (!_chunk2K5TELHVcjs.EFFECT_TEMPLATE_SLOT_TYPES.includes(slot.type)) return at(`type "${slot.type}" is not one of ${_chunk2K5TELHVcjs.EFFECT_TEMPLATE_SLOT_TYPES.join(", ")}`);
433
+ if (typeof slot.label !== "string" || !slot.label) at("needs a label");
434
+ if (isSubjectTemplateSlot(slot)) {
435
+ if (typeof slot.hasDefault !== "boolean") at("a subject slot needs hasDefault (a boolean)");
436
+ if ("default" in slot) at("a subject slot describes hasDefault, not its default");
437
+ return;
438
+ }
439
+ const fallback = slot.default;
440
+ if (fallback === void 0) return at("needs a default");
441
+ const problem = templateValueProblem(slot, fallback);
442
+ if (problem) at(`its default does not fit: ${problem}`);
443
+ if (slot.type === "number" && slot.min !== void 0 && slot.max !== void 0 && slot.min > slot.max) at("min is above max");
444
+ }
445
+ async function checkTemplates(provider, list, issues) {
446
+ const top = (message) => issues.push({ message });
447
+ const templates = await provider.listTemplates();
448
+ if (!Array.isArray(templates)) return top("listTemplates did not return a list");
449
+ const seen = /* @__PURE__ */ new Set();
450
+ for (const t of templates) if (seen.has(t.id)) top(`duplicate template id "${t.id}"`);
451
+ else seen.add(t.id);
452
+ const unknownDescribe = await rejectsWith("unknown_template", () => provider.describeTemplate("__no_such_template__"));
453
+ if (unknownDescribe) top(`describeTemplate of an unknown id ${unknownDescribe}`);
454
+ const unknownFill = await rejectsWith("unknown_template", () => provider.instantiateTemplate("__no_such_template__"));
455
+ if (unknownFill) top(`instantiateTemplate of an unknown id ${unknownFill}`);
456
+ for (const summary of templates) {
457
+ const id = summary.id;
458
+ const at = (message) => issues.push({ templateId: id, message });
459
+ if (!id || typeof id !== "string") top("a template has no id");
460
+ if (!summary.name) at("template has no name");
461
+ if (!summary.description) at("template has no description");
462
+ if (!(Number.isInteger(summary.shots) && summary.shots >= 1)) at("shots must be a whole number \u2265 1");
463
+ if (summary.durationMs !== void 0 && !(summary.durationMs > 0)) at("durationMs must be > 0 when present");
464
+ let slots;
465
+ try {
466
+ const d = await provider.describeTemplate(id);
467
+ if (d.id !== id) at(`describeTemplate returned id "${d.id}"`);
468
+ if (!Array.isArray(d.slots)) {
469
+ at("describeTemplate gave no slots list");
470
+ continue;
471
+ }
472
+ slots = d.slots;
473
+ const names = /* @__PURE__ */ new Set();
474
+ for (const slot of slots) {
475
+ if (names.has(_optionalChain([slot, 'optionalAccess', _16 => _16.name]))) at(`slot "${slot.name}" is declared twice`);
476
+ names.add(_optionalChain([slot, 'optionalAccess', _17 => _17.name]));
477
+ checkSlot(id, slot, issues);
478
+ }
479
+ } catch (e) {
480
+ at(`describeTemplate failed: ${codeOf(e)}`);
481
+ continue;
482
+ }
483
+ try {
484
+ const result = await provider.instantiateTemplate(id);
485
+ if (!result.ok) at(`instantiateTemplate with the defaults failed: ${result.errors.join(" ")}`);
486
+ else {
487
+ for (const p of checkEffectSequence(result.sequence, list)) at(`with the defaults, ${p}`);
488
+ if (_optionalChain([result, 'access', _18 => _18.sequence, 'optionalAccess', _19 => _19.shots, 'optionalAccess', _20 => _20.length]) !== summary.shots) at(`listTemplates says ${summary.shots} shots; the sequence has ${_optionalChain([result, 'access', _21 => _21.sequence, 'optionalAccess', _22 => _22.shots, 'optionalAccess', _23 => _23.length])}`);
489
+ if (!Array.isArray(result.openSlots) || !Array.isArray(result.notes)) at("instantiateTemplate needs openSlots and notes lists");
490
+ else {
491
+ const open = Array.isArray(_optionalChain([result, 'access', _24 => _24.sequence, 'optionalAccess', _25 => _25.shots])) ? effectSequenceSlots(result.sequence) : [];
492
+ if (open.some((s) => !result.openSlots.includes(s))) at(`openSlots ${JSON.stringify(result.openSlots)} misses slots the sequence leaves open (${open.join(", ")})`);
493
+ }
494
+ }
495
+ } catch (e) {
496
+ at(`instantiateTemplate with the defaults failed: ${codeOf(e)}`);
497
+ }
498
+ const bad = { __no_such_slot__: "x", ...slots[0] ? { [slots[0].name]: wrongValue(slots[0]) } : {} };
499
+ try {
500
+ const result = await provider.instantiateTemplate(id, bad);
501
+ if (result.ok) at("instantiateTemplate accepted an unknown slot and a value of the wrong type");
502
+ else if (!result.errors.length || result.errors.some((e) => typeof e !== "string" || !e)) at("instantiateTemplate refused bad values without a sentence for each");
503
+ 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)");
504
+ } catch (e) {
505
+ at(`instantiateTemplate with bad values threw (${codeOf(e)}) instead of returning { ok: false, errors }`);
506
+ }
507
+ }
508
+ }
194
509
  async function checkEffectProvider(provider, options = {}) {
195
510
  const issues = [];
196
511
  const top = (message) => issues.push({ message });
197
512
  if (!provider.id) top("provider has no id");
198
513
  const caps = provider.capabilities;
199
514
  for (const k of ["supportsWorker", "supportsFloat", "supportsMask", "supportsHostImages", "supportsVector"]) {
200
- if (typeof _optionalChain([caps, 'optionalAccess', _12 => _12[k]]) !== "boolean") top(`capabilities.${k} is not a boolean`);
515
+ if (typeof _optionalChain([caps, 'optionalAccess', _26 => _26[k]]) !== "boolean") top(`capabilities.${k} is not a boolean`);
201
516
  }
202
- if (_optionalChain([caps, 'optionalAccess', _13 => _13.supportsAuthoring]) !== void 0 && typeof caps.supportsAuthoring !== "boolean") top("capabilities.supportsAuthoring is not a boolean");
203
- if (_optionalChain([caps, 'optionalAccess', _14 => _14.supportsVector]) && typeof provider.applyVectorEffect !== "function") top("supportsVector is set but applyVectorEffect is missing");
204
- if (_optionalChain([caps, 'optionalAccess', _15 => _15.supportsAuthoring]) && typeof provider.openAuthoring !== "function") top("supportsAuthoring is set but openAuthoring is missing");
205
- if (_optionalChain([caps, 'optionalAccess', _16 => _16.supportsCamera]) !== void 0 && typeof caps.supportsCamera !== "boolean") top("capabilities.supportsCamera is not a boolean");
206
- if (_optionalChain([caps, 'optionalAccess', _17 => _17.supportsCamera]) && typeof provider.cameraView !== "function") top("supportsCamera is set but cameraView is missing");
517
+ if (_optionalChain([caps, 'optionalAccess', _27 => _27.supportsAuthoring]) !== void 0 && typeof caps.supportsAuthoring !== "boolean") top("capabilities.supportsAuthoring is not a boolean");
518
+ if (_optionalChain([caps, 'optionalAccess', _28 => _28.supportsVector]) && typeof provider.applyVectorEffect !== "function") top("supportsVector is set but applyVectorEffect is missing");
519
+ if (_optionalChain([caps, 'optionalAccess', _29 => _29.supportsAuthoring]) && typeof provider.openAuthoring !== "function") top("supportsAuthoring is set but openAuthoring is missing");
520
+ if (_optionalChain([caps, 'optionalAccess', _30 => _30.supportsCamera]) !== void 0 && typeof caps.supportsCamera !== "boolean") top("capabilities.supportsCamera is not a boolean");
521
+ if (_optionalChain([caps, 'optionalAccess', _31 => _31.supportsCamera]) && typeof provider.cameraView !== "function") top("supportsCamera is set but cameraView is missing");
207
522
  if (provider.sampleCameraMove && typeof provider.cameraView !== "function") top("sampleCameraMove is present but cameraView is missing");
523
+ if (_optionalChain([caps, 'optionalAccess', _32 => _32.supportsTemplates]) !== void 0 && typeof caps.supportsTemplates !== "boolean") top("capabilities.supportsTemplates is not a boolean");
524
+ const templateMethods = ["listTemplates", "describeTemplate", "instantiateTemplate"];
525
+ if (_optionalChain([caps, 'optionalAccess', _33 => _33.supportsTemplates])) {
526
+ for (const m of templateMethods) if (typeof provider[m] !== "function") top(`supportsTemplates is set but ${m} is missing`);
527
+ }
528
+ if (!_optionalChain([caps, 'optionalAccess', _34 => _34.supportsTemplates]) && templateMethods.some((m) => typeof provider[m] === "function")) top("template methods are present but capabilities.supportsTemplates is not set");
208
529
  const list = await provider.list();
209
530
  const ids = /* @__PURE__ */ new Set();
210
531
  for (const e of list) {
@@ -212,10 +533,10 @@ async function checkEffectProvider(provider, options = {}) {
212
533
  ids.add(e.id);
213
534
  checkSummary(e, issues);
214
535
  }
215
- if (!_optionalChain([caps, 'optionalAccess', _18 => _18.supportsCamera]) && list.some((e) => e.kind === "camera")) top("the catalog lists camera effects but capabilities.supportsCamera is not set");
536
+ if (!_optionalChain([caps, 'optionalAccess', _35 => _35.supportsCamera]) && list.some((e) => e.kind === "camera")) top("the catalog lists camera effects but capabilities.supportsCamera is not set");
216
537
  const all = await provider.search("");
217
538
  if (all.length !== list.length) top(`search("") returned ${all.length} effects, list() ${list.length}`);
218
- const firstUse = _optionalChain([list, 'access', _19 => _19[0], 'optionalAccess', _20 => _20.uses, 'access', _21 => _21[0]]);
539
+ const firstUse = _optionalChain([list, 'access', _36 => _36[0], 'optionalAccess', _37 => _37.uses, 'access', _38 => _38[0]]);
219
540
  if (firstUse) {
220
541
  const filtered = await provider.search("", { use: firstUse });
221
542
  if (filtered.some((e) => !e.uses.includes(firstUse))) top(`search("", { use: "${firstUse}" }) returned effects without that use`);
@@ -224,7 +545,7 @@ async function checkEffectProvider(provider, options = {}) {
224
545
  if (unknown) top(`describe of an unknown id ${unknown}`);
225
546
  const unknownRenderer = await rejectsWith("unknown_effect", () => provider.createRenderer("__no_such_effect__", { width: 4, height: 4 }));
226
547
  if (unknownRenderer) top(`createRenderer of an unknown id ${unknownRenderer}`);
227
- if (_optionalChain([caps, 'optionalAccess', _22 => _22.supportsCamera]) && provider.cameraView) {
548
+ if (_optionalChain([caps, 'optionalAccess', _39 => _39.supportsCamera]) && provider.cameraView) {
228
549
  const probe = { from: WIDE, to: CLOSE, u: 0.5, ms: 1e3, stage: STAGE };
229
550
  const unknownCamera = await rejectsWith("unknown_effect", () => provider.cameraView("__no_such_effect__", probe));
230
551
  if (unknownCamera) top(`cameraView of an unknown id ${unknownCamera}`);
@@ -256,7 +577,7 @@ async function checkEffectProvider(provider, options = {}) {
256
577
  if (bad) issues.push({ effectId: id, message: `applyVectorEffect with an unknown control ${bad}` });
257
578
  }
258
579
  }
259
- if (_optionalChain([caps, 'optionalAccess', _23 => _23.supportsAuthoring]) && options.authoring !== false && typeof provider.openAuthoring === "function") {
580
+ if (_optionalChain([caps, 'optionalAccess', _40 => _40.supportsAuthoring]) && options.authoring !== false && typeof provider.openAuthoring === "function") {
260
581
  const targetEffect = (await Promise.all((_nullishCoalesce(options.ids, () => ( [...ids]))).map((id) => provider.describe(id)))).find(
261
582
  (d) => d.kind !== "motion" && d.kind !== "vector" && d.kind !== "camera"
262
583
  );
@@ -307,9 +628,125 @@ async function checkEffectProvider(provider, options = {}) {
307
628
  }
308
629
  }
309
630
  }
631
+ if (_optionalChain([caps, 'optionalAccess', _41 => _41.supportsTemplates]) && options.templates !== false && templateMethods.every((m) => typeof provider[m] === "function")) await checkTemplates(provider, list, issues);
310
632
  return issues;
311
633
  }
312
634
 
635
+ // src/effects/fake-templates.ts
636
+ var PLACEHOLDER = /\{\{([A-Za-z][\w-]*)\}\}/g;
637
+ var WHOLE = /^\{\{([A-Za-z][\w-]*)\}\}$/;
638
+ 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>`;
639
+ var TEMPLATES = [
640
+ {
641
+ 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 },
642
+ slots: [
643
+ { name: "title", type: "text", label: "Title", default: "Hello", maxLength: 40 },
644
+ { name: "subtitle", type: "text", label: "Closing caption", default: "See you soon", maxLength: 60 },
645
+ { name: "accent", type: "color", label: "Accent colour", default: "#0ea5e9" },
646
+ { name: "holdMs", type: "number", label: "Time on each shot (ms)", default: 2e3, min: 500, max: 1e4, integer: true }
647
+ ],
648
+ sequence: {
649
+ name: "title-sequence",
650
+ title: "{{title}}",
651
+ stage: { width: 1280, height: 720 },
652
+ shots: [
653
+ {
654
+ hold: "{{holdMs}}",
655
+ title: "{{title}}",
656
+ layers: [
657
+ { id: "backdrop", effect: "fake.gradient", role: "background", values: { from: "{{accent}}" }, until: { shots: 1 } },
658
+ { id: "bar", effect: "fake.bar", role: "overlay", values: { color: "{{accent}}" }, from: 200 }
659
+ ]
660
+ },
661
+ {
662
+ hold: "{{holdMs}}",
663
+ caption: "{{subtitle}}",
664
+ transition: { effect: "fake.crossfade", ms: 600 },
665
+ layers: [{ id: "closing", effect: "fake.gradient", role: "background", values: { from: "#111827", to: "{{accent}}" } }]
666
+ }
667
+ ]
668
+ }
669
+ },
670
+ {
671
+ 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 },
672
+ slots: [
673
+ { name: "picture", type: "image", label: "Picture", description: "The picture to reveal.", hasDefault: true, subjectDefault: picture("Picture", "#64748b") },
674
+ { name: "logo", type: "image", label: "Logo", description: "A logo shown over the second shot; the host fills it when none is given.", hasDefault: false },
675
+ { name: "caption", type: "text", label: "Caption", default: "Now in colour", maxLength: 50 },
676
+ { name: "holdMs", type: "number", label: "Time on each shot (ms)", default: 2e3, min: 500, max: 1e4, integer: true }
677
+ ],
678
+ sequence: {
679
+ name: "picture-reveal",
680
+ stage: { width: 1280, height: 720 },
681
+ shots: [
682
+ { hold: "{{holdMs}}", layers: [{ id: "tinted", effect: "fake.tint", subject: { slot: "picture" }, values: { color: "#704214", amount: 0.6 } }] },
683
+ {
684
+ hold: "{{holdMs}}",
685
+ caption: "{{caption}}",
686
+ transition: { effect: "fake.crossfade", ms: 800 },
687
+ layers: [
688
+ { id: "picture", subject: { slot: "picture" }, role: "background" },
689
+ { id: "logo", subject: { slot: "logo" }, role: "overlay", rect: { x: 1040, y: 40, width: 200, height: 112 }, fade: 300 }
690
+ ]
691
+ }
692
+ ]
693
+ }
694
+ }
695
+ ];
696
+ var describeOf = (t) => ({
697
+ ...t.summary,
698
+ slots: t.slots.map(({ subjectDefault: _d, ...slot }) => slot)
699
+ });
700
+ function subjectOf(type, value) {
701
+ if (typeof value !== "string") return value;
702
+ if (value.trimStart().startsWith("<svg") || type === "svg") return { svg: value };
703
+ return type === "video" ? { video: value } : { image: value };
704
+ }
705
+ function fill(t, values) {
706
+ const slots = new Map(t.slots.map((s) => [s.name, s]));
707
+ const valueOf = (name) => {
708
+ const s = slots.get(name);
709
+ return _nullishCoalesce(values[name], () => ( (isSubjectTemplateSlot(s) ? s.subjectDefault : s.default)));
710
+ };
711
+ const walk = (v, key) => {
712
+ if (typeof v === "string") {
713
+ const whole = WHOLE.exec(v);
714
+ if (whole && slots.has(whole[1])) return valueOf(whole[1]);
715
+ return v.replace(PLACEHOLDER, (m, name) => slots.has(name) ? String(valueOf(name)) : m);
716
+ }
717
+ if (Array.isArray(v)) return v.map((x) => walk(x));
718
+ if (!v || typeof v !== "object") return v;
719
+ if (key === "subject" && typeof v.slot === "string") {
720
+ const s = slots.get(v.slot);
721
+ const value = s ? valueOf(s.name) : void 0;
722
+ return s && value !== void 0 ? subjectOf(s.type, value) : v;
723
+ }
724
+ return Object.fromEntries(Object.entries(v).map(([k, x]) => [k, walk(x, k)]));
725
+ };
726
+ return walk(t.sequence);
727
+ }
728
+ function fakeTemplateMethods() {
729
+ const byId = new Map(TEMPLATES.map((t) => [t.summary.id, t]));
730
+ const get = (id) => {
731
+ const t = byId.get(id);
732
+ if (!t) throw new (0, _chunk2K5TELHVcjs.UnknownTemplateError)(id, "the fake provider");
733
+ return t;
734
+ };
735
+ return {
736
+ listTemplates: (options) => searchTemplateSummaries(TEMPLATES.map((t) => t.summary), options).map((s) => structuredClone(s)),
737
+ describeTemplate: (id) => structuredClone(describeOf(get(id))),
738
+ instantiateTemplate(id, values = {}, options = {}) {
739
+ const t = get(id);
740
+ const errors = checkTemplateValues(describeOf(t).slots, values);
741
+ 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\./, "")}").`);
742
+ if (errors.length) return { ok: false, errors };
743
+ const sequence = fill(t, values);
744
+ if (options.name) sequence.name = options.name;
745
+ return { ok: true, sequence, openSlots: effectSequenceSlots(sequence), notes: [] };
746
+ }
747
+ };
748
+ }
749
+
313
750
  // src/effects/fake.ts
314
751
  var HEX = "^#[0-9a-fA-F]{6}$";
315
752
  var colour = (description) => ({ type: "string", pattern: HEX, description });
@@ -550,16 +987,16 @@ var hexToRgb = (hex) => [1, 3, 5].map((i) => parseInt(hex.slice(i, i + 2), 16));
550
987
  var smooth = (t) => t * t * (3 - 2 * t);
551
988
  var clamp01 = (v) => v < 0 ? 0 : v > 1 ? 1 : v;
552
989
  function input(request, name, id, width, height) {
553
- const src = _optionalChain([request, 'access', _24 => _24.inputs, 'optionalAccess', _25 => _25[name]]);
554
- if (!src) throw new (0, _chunkOPSK22DLcjs.EffectUnsupportedError)(`Effect "${id}" needs an input named "${name}".`, id);
555
- if (!_chunkOPSK22DLcjs.isEffectPixels.call(void 0, src)) throw new (0, _chunkOPSK22DLcjs.EffectUnsupportedError)(`The fake provider only takes EffectPixels inputs ("${name}").`, id);
990
+ const src = _optionalChain([request, 'access', _42 => _42.inputs, 'optionalAccess', _43 => _43[name]]);
991
+ if (!src) throw new (0, _chunk2K5TELHVcjs.EffectUnsupportedError)(`Effect "${id}" needs an input named "${name}".`, id);
992
+ if (!_chunk2K5TELHVcjs.isEffectPixels.call(void 0, src)) throw new (0, _chunk2K5TELHVcjs.EffectUnsupportedError)(`The fake provider only takes EffectPixels inputs ("${name}").`, id);
556
993
  if (src.width !== width || src.height !== height) {
557
- throw new (0, _chunkOPSK22DLcjs.EffectUnsupportedError)(`Input "${name}" is ${src.width}\xD7${src.height}; the renderer is ${width}\xD7${height}.`, id);
994
+ throw new (0, _chunk2K5TELHVcjs.EffectUnsupportedError)(`Input "${name}" is ${src.width}\xD7${src.height}; the renderer is ${width}\xD7${height}.`, id);
558
995
  }
559
996
  return src;
560
997
  }
561
998
  function renderPixels(d, v, request, width, height) {
562
- const out = _chunkOPSK22DLcjs.createEffectPixels.call(void 0, width, height);
999
+ const out = _chunk2K5TELHVcjs.createEffectPixels.call(void 0, width, height);
563
1000
  const o = out.data;
564
1001
  switch (d.id) {
565
1002
  case "fake.invert": {
@@ -625,7 +1062,7 @@ function renderPixels(d, v, request, width, height) {
625
1062
  break;
626
1063
  }
627
1064
  default:
628
- throw new (0, _chunkOPSK22DLcjs.EffectUnsupportedError)(`"${d.id}" is a ${d.kind} effect; use applyVectorEffect.`, d.id);
1065
+ throw new (0, _chunk2K5TELHVcjs.EffectUnsupportedError)(`"${d.id}" is a ${d.kind} effect; use applyVectorEffect.`, d.id);
629
1066
  }
630
1067
  return out;
631
1068
  }
@@ -655,22 +1092,22 @@ function cameraViewOf(d, ctx, v) {
655
1092
  case "fake.drift":
656
1093
  return viewAt(x0, y0, from.zoom * lerp(1, v.scale, smooth(u)), ctx);
657
1094
  default:
658
- throw new (0, _chunkOPSK22DLcjs.EffectUnsupportedError)(`"${d.id}" is a ${d.kind} effect, not a camera move.`, d.id);
1095
+ throw new (0, _chunk2K5TELHVcjs.EffectUnsupportedError)(`"${d.id}" is a ${d.kind} effect, not a camera move.`, d.id);
659
1096
  }
660
1097
  }
661
1098
  function toFloat(p) {
662
1099
  const f = new Float32Array(p.data.length);
663
1100
  for (let i = 0; i < f.length; i += 4) {
664
- f[i] = _chunkOPSK22DLcjs.srgbToLinear.call(void 0, p.data[i] / 255);
665
- f[i + 1] = _chunkOPSK22DLcjs.srgbToLinear.call(void 0, p.data[i + 1] / 255);
666
- f[i + 2] = _chunkOPSK22DLcjs.srgbToLinear.call(void 0, p.data[i + 2] / 255);
1101
+ f[i] = _chunk2K5TELHVcjs.srgbToLinear.call(void 0, p.data[i] / 255);
1102
+ f[i + 1] = _chunk2K5TELHVcjs.srgbToLinear.call(void 0, p.data[i + 1] / 255);
1103
+ f[i + 2] = _chunk2K5TELHVcjs.srgbToLinear.call(void 0, p.data[i + 2] / 255);
667
1104
  f[i + 3] = p.data[i + 3] / 255;
668
1105
  }
669
- return _chunkOPSK22DLcjs.encodeEffectFloat.call(void 0, { ...p, float: f });
1106
+ return _chunk2K5TELHVcjs.encodeEffectFloat.call(void 0, { ...p, float: f });
670
1107
  }
671
1108
  function maskResult(out, mask, source, id) {
672
- if (!_chunkOPSK22DLcjs.isEffectPixels.call(void 0, mask) || mask.width !== out.width || mask.height !== out.height) {
673
- throw new (0, _chunkOPSK22DLcjs.EffectUnsupportedError)("The mask must be EffectPixels the size of the renderer.", id);
1109
+ if (!_chunk2K5TELHVcjs.isEffectPixels.call(void 0, mask) || mask.width !== out.width || mask.height !== out.height) {
1110
+ throw new (0, _chunk2K5TELHVcjs.EffectUnsupportedError)("The mask must be EffectPixels the size of the renderer.", id);
674
1111
  }
675
1112
  const o = out.data;
676
1113
  for (let i = 0; i < o.length; i += 4) {
@@ -689,6 +1126,7 @@ function createFakeEffectProvider(options = {}) {
689
1126
  supportsVector: true,
690
1127
  supportsAuthoring,
691
1128
  ...options.camera ? { supportsCamera: true } : {},
1129
+ ...options.templates ? { supportsTemplates: true } : {},
692
1130
  maxSize: 8192,
693
1131
  ...options.capabilities
694
1132
  };
@@ -696,32 +1134,32 @@ function createFakeEffectProvider(options = {}) {
696
1134
  const byId = new Map(all.map((d) => [d.id, d]));
697
1135
  const get = (id) => {
698
1136
  const d = byId.get(id);
699
- if (!d) throw new (0, _chunkOPSK22DLcjs.UnknownEffectError)(id, "the fake provider");
1137
+ if (!d) throw new (0, _chunk2K5TELHVcjs.UnknownEffectError)(id, "the fake provider");
700
1138
  return d;
701
1139
  };
702
1140
  const summaries = all.map(summaryOf);
703
1141
  const camera = (id, ctx, values) => {
704
1142
  const d = get(id);
705
- if (d.kind !== "camera") throw new (0, _chunkOPSK22DLcjs.EffectUnsupportedError)(`"${id}" is a ${d.kind} effect, not a camera move.`, id);
706
- if (!(ctx.u >= 0 && ctx.u <= 1)) throw new (0, _chunkOPSK22DLcjs.EffectUnsupportedError)(`u must be 0\u20131 through the move, got ${ctx.u}.`, id);
707
- return cameraViewOf(d, ctx, _chunkOPSK22DLcjs.resolveEffectValues.call(void 0, d, values));
1143
+ if (d.kind !== "camera") throw new (0, _chunk2K5TELHVcjs.EffectUnsupportedError)(`"${id}" is a ${d.kind} effect, not a camera move.`, id);
1144
+ if (!(ctx.u >= 0 && ctx.u <= 1)) throw new (0, _chunk2K5TELHVcjs.EffectUnsupportedError)(`u must be 0\u20131 through the move, got ${ctx.u}.`, id);
1145
+ return cameraViewOf(d, ctx, _chunk2K5TELHVcjs.resolveEffectValues.call(void 0, d, values));
708
1146
  };
709
1147
  const provider = {
710
1148
  id: "fake",
711
1149
  name: "Fake effects",
712
1150
  version: "1",
713
1151
  capabilities,
714
- list: (o) => _chunkOPSK22DLcjs.searchEffectSummaries.call(void 0, summaries, "", o),
715
- search: (q, o) => _chunkOPSK22DLcjs.searchEffectSummaries.call(void 0, summaries, q, o),
1152
+ list: (o) => _chunk2K5TELHVcjs.searchEffectSummaries.call(void 0, summaries, "", o),
1153
+ search: (q, o) => _chunk2K5TELHVcjs.searchEffectSummaries.call(void 0, summaries, q, o),
716
1154
  describe: (id) => structuredClone(get(id)),
717
1155
  createRenderer(id, ro) {
718
1156
  const d = get(id);
719
- if (d.kind === "camera") throw new (0, _chunkOPSK22DLcjs.EffectUnsupportedError)(`"${id}" is a camera move: it moves a scene's camera and draws no pixels. Use cameraView.`, id);
720
- if (d.kind !== "shader") throw new (0, _chunkOPSK22DLcjs.EffectUnsupportedError)(`"${id}" is a ${d.kind} effect; use applyVectorEffect.`, id);
1157
+ if (d.kind === "camera") throw new (0, _chunk2K5TELHVcjs.EffectUnsupportedError)(`"${id}" is a camera move: it moves a scene's camera and draws no pixels. Use cameraView.`, id);
1158
+ if (d.kind !== "shader") throw new (0, _chunk2K5TELHVcjs.EffectUnsupportedError)(`"${id}" is a ${d.kind} effect; use applyVectorEffect.`, id);
721
1159
  const { width, height } = ro;
722
1160
  const depth = _nullishCoalesce(ro.depth, () => ( 8));
723
1161
  if (!(width > 0 && height > 0) || width > capabilities.maxSize || height > capabilities.maxSize) {
724
- throw new (0, _chunkOPSK22DLcjs.EffectUnsupportedError)(`Renderer size ${width}\xD7${height} is outside 1\u2013${capabilities.maxSize}.`, id);
1162
+ throw new (0, _chunk2K5TELHVcjs.EffectUnsupportedError)(`Renderer size ${width}\xD7${height} is outside 1\u2013${capabilities.maxSize}.`, id);
725
1163
  }
726
1164
  let disposed = false;
727
1165
  return {
@@ -730,16 +1168,16 @@ function createFakeEffectProvider(options = {}) {
730
1168
  height,
731
1169
  depth,
732
1170
  async render(request) {
733
- if (disposed) throw new (0, _chunkOPSK22DLcjs.EffectDisposedError)(id);
1171
+ if (disposed) throw new (0, _chunk2K5TELHVcjs.EffectDisposedError)(id);
734
1172
  if (!Number.isFinite(request.time) || request.time < 0) {
735
- throw new (0, _chunkOPSK22DLcjs.EffectUnsupportedError)(`time must be a finite number of ms \u2265 0, got ${request.time}.`, id);
1173
+ throw new (0, _chunk2K5TELHVcjs.EffectUnsupportedError)(`time must be a finite number of ms \u2265 0, got ${request.time}.`, id);
736
1174
  }
737
- const values = _chunkOPSK22DLcjs.resolveEffectValues.call(void 0, d, request.values);
738
- _optionalChain([options, 'access', _26 => _26.onRender, 'optionalCall', _27 => _27(id, request)]);
1175
+ const values = _chunk2K5TELHVcjs.resolveEffectValues.call(void 0, d, request.values);
1176
+ _optionalChain([options, 'access', _44 => _44.onRender, 'optionalCall', _45 => _45(id, request)]);
739
1177
  const out = renderPixels(d, values, request, width, height);
740
1178
  if (request.mask) {
741
- if (!capabilities.supportsMask) throw new (0, _chunkOPSK22DLcjs.EffectUnsupportedError)("This provider does not take masks.", id);
742
- const source = d.uses.includes("filter") ? _optionalChain([request, 'access', _28 => _28.inputs, 'optionalAccess', _29 => _29.source]) : void 0;
1179
+ if (!capabilities.supportsMask) throw new (0, _chunk2K5TELHVcjs.EffectUnsupportedError)("This provider does not take masks.", id);
1180
+ const source = d.uses.includes("filter") ? _optionalChain([request, 'access', _46 => _46.inputs, 'optionalAccess', _47 => _47.source]) : void 0;
743
1181
  maskResult(out, request.mask, source, id);
744
1182
  }
745
1183
  return depth > 8 && capabilities.supportsFloat ? toFloat(out) : out;
@@ -751,8 +1189,8 @@ function createFakeEffectProvider(options = {}) {
751
1189
  },
752
1190
  applyVectorEffect(id, target, values) {
753
1191
  const d = get(id);
754
- if (d.kind !== "motion" && d.kind !== "vector") throw new (0, _chunkOPSK22DLcjs.EffectUnsupportedError)(`"${id}" is a ${d.kind} effect, not a vector one.`, id);
755
- const v = _chunkOPSK22DLcjs.resolveEffectValues.call(void 0, d, values);
1192
+ if (d.kind !== "motion" && d.kind !== "vector") throw new (0, _chunk2K5TELHVcjs.EffectUnsupportedError)(`"${id}" is a ${d.kind} effect, not a vector one.`, id);
1193
+ const v = _chunk2K5TELHVcjs.resolveEffectValues.call(void 0, d, values);
756
1194
  if (d.kind === "vector") {
757
1195
  return { svg: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100"><circle id="badge" cx="50" cy="50" r="40" fill="${v.color}"/></svg>`, animate: [{ id: "badge", ms: v.ms, attrs: { opacity: [0, 1] } }], duration: v.ms, loop: false };
758
1196
  }
@@ -772,11 +1210,12 @@ function createFakeEffectProvider(options = {}) {
772
1210
  sampleCameraMove: (id, request) => {
773
1211
  const d = get(id);
774
1212
  const { from, to, ms, stage, fps, values } = request;
775
- return _chunkOPSK22DLcjs.sampleCameraViews.call(void 0, (u) => camera(id, { from, to, u, ms, stage }, values), { ms, fps, cut: _optionalChain([d, 'access', _30 => _30.camera, 'optionalAccess', _31 => _31.cut]) });
1213
+ return _chunk2K5TELHVcjs.sampleCameraViews.call(void 0, (u) => camera(id, { from, to, u, ms, stage }, values), { ms, fps, cut: _optionalChain([d, 'access', _48 => _48.camera, 'optionalAccess', _49 => _49.cut]) });
776
1214
  }
777
1215
  } : {},
1216
+ ...options.templates ? fakeTemplateMethods() : {},
778
1217
  ...supportsAuthoring ? {
779
- openAuthoring: (from) => _chunkC73U5UI3cjs.createEffectAuthoringSession.call(void 0, from, { provider })
1218
+ openAuthoring: (from) => _chunkRG4O6K2Acjs.createEffectAuthoringSession.call(void 0, from, { provider })
780
1219
  } : {}
781
1220
  };
782
1221
  return provider;
@@ -812,7 +1251,7 @@ function jsonTypeOf(value) {
812
1251
  function effectControlField(name, schema, fallback, options = {}) {
813
1252
  const base = { id: name, ...schema.title ? { label: schema.title } : {}, ...schema.description ? { description: schema.description } : {} };
814
1253
  const def = _nullishCoalesce(schema.default, () => ( fallback));
815
- const type = _nullishCoalesce(typeOf(schema), () => ( typeOf(_nullishCoalesce(_optionalChain([schema, 'access', _32 => _32.anyOf, 'optionalAccess', _33 => _33.find, 'call', _34 => _34((s) => typeOf(s) === jsonTypeOf(def))]), () => ( {})))));
1254
+ const type = _nullishCoalesce(typeOf(schema), () => ( typeOf(_nullishCoalesce(_optionalChain([schema, 'access', _50 => _50.anyOf, 'optionalAccess', _51 => _51.find, 'call', _52 => _52((s) => typeOf(s) === jsonTypeOf(def))]), () => ( {})))));
816
1255
  if (Array.isArray(schema.enum) && schema.enum.length) {
817
1256
  const options2 = schema.enum.filter((v) => typeof v === "string" || typeof v === "number");
818
1257
  return { ...base, type: "choice", options: options2, default: typeof def === "string" || typeof def === "number" ? def : options2[0], control: options2.length <= 4 ? "segmented" : "select" };
@@ -826,7 +1265,7 @@ function effectControlField(name, schema, fallback, options = {}) {
826
1265
  if (isEffectFontControl(schema)) {
827
1266
  const fonts = _nullishCoalesce(options.fonts, () => ( _chunk4XSBOGMKcjs.SYSTEM_FONT_CATALOG));
828
1267
  const opts = fonts.map((f) => ({ value: f.family, label: f.family, description: f.category }));
829
- const current = typeof def === "string" && def ? def : _nullishCoalesce(_optionalChain([opts, 'access', _35 => _35[0], 'optionalAccess', _36 => _36.value]), () => ( "sans-serif"));
1268
+ const current = typeof def === "string" && def ? def : _nullishCoalesce(_optionalChain([opts, 'access', _53 => _53[0], 'optionalAccess', _54 => _54.value]), () => ( "sans-serif"));
830
1269
  if (!opts.some((o) => o.value.toLowerCase() === current.toLowerCase())) opts.unshift({ value: current, label: current, description: "current" });
831
1270
  return { ...base, type: "choice", options: opts, default: opts.find((o) => o.value.toLowerCase() === current.toLowerCase()).value, control: "select" };
832
1271
  }
@@ -835,7 +1274,7 @@ function effectControlField(name, schema, fallback, options = {}) {
835
1274
  return { ...base, type: "text", default: typeof def === "string" ? def : "", ...schema.maxLength ? { maxLength: schema.maxLength } : {} };
836
1275
  }
837
1276
  if (type === "array" && Array.isArray(def) && def.length >= 2 && def.length <= 4 && def.every((n) => typeof n === "number")) {
838
- const items = _nullishCoalesce(_nullishCoalesce(schema.items, () => ( _optionalChain([schema, 'access', _37 => _37.anyOf, 'optionalAccess', _38 => _38.find, 'call', _39 => _39((s) => typeOf(s) === "array"), 'optionalAccess', _40 => _40.items]))), () => ( {}));
1277
+ const items = _nullishCoalesce(_nullishCoalesce(schema.items, () => ( _optionalChain([schema, 'access', _55 => _55.anyOf, 'optionalAccess', _56 => _56.find, 'call', _57 => _57((s) => typeOf(s) === "array"), 'optionalAccess', _58 => _58.items]))), () => ( {}));
839
1278
  return { ...base, type: "vector", size: def.length, default: [...def], ...items.minimum !== void 0 ? { min: items.minimum } : {}, ...items.maximum !== void 0 ? { max: items.maximum } : {} };
840
1279
  }
841
1280
  return null;
@@ -857,7 +1296,7 @@ var effectFieldValue = (field, value) => {
857
1296
  return value === void 0 || value === null || typeof value === "object" && !Array.isArray(value) ? field.default : value;
858
1297
  };
859
1298
  function effectSamplePicture(width, height, variant = 0) {
860
- const p = _chunkOPSK22DLcjs.createEffectPixels.call(void 0, width, height);
1299
+ const p = _chunk2K5TELHVcjs.createEffectPixels.call(void 0, width, height);
861
1300
  for (let y = 0, i = 0; y < height; y++) {
862
1301
  for (let x = 0; x < width; x++, i += 4) {
863
1302
  const u = x / Math.max(1, width - 1);
@@ -948,11 +1387,11 @@ var EASING_SCHEMA = {
948
1387
  };
949
1388
  var NO_SESSION = "No effect authoring session is currently open. Open an effect using EffectProvider.openAuthoring() or in an authoring editor before calling effect authoring tools.";
950
1389
  function createEffectAuthoringToolProvider(host, options) {
951
- const id = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _41 => _41.id]), () => ( "effect-authoring"));
952
- const namespace = _optionalChain([options, 'optionalAccess', _42 => _42.namespace]);
953
- const title = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _43 => _43.title]), () => ( "Effect authoring"));
954
- const description = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _44 => _44.description]), () => ( "Author shaders and procedural effects, inspect parameters, adjust values, and manage keyframe animations."));
955
- const skill = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _45 => _45.skill]), () => ( "pixerate-effect-authoring"));
1390
+ const id = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _59 => _59.id]), () => ( "effect-authoring"));
1391
+ const namespace = _optionalChain([options, 'optionalAccess', _60 => _60.namespace]);
1392
+ const title = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _61 => _61.title]), () => ( "Effect authoring"));
1393
+ const description = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _62 => _62.description]), () => ( "Author shaders and procedural effects, inspect parameters, adjust values, and manage keyframe animations."));
1394
+ const skill = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _63 => _63.skill]), () => ( "pixerate-effect-authoring"));
956
1395
  const requireSession = () => {
957
1396
  const s = host.session();
958
1397
  if (!s) throw new Error(NO_SESSION);
@@ -973,7 +1412,7 @@ function createEffectAuthoringToolProvider(host, options) {
973
1412
  sourceLanguage: state.sourceLanguage,
974
1413
  controls: effectParameterFields(state.description),
975
1414
  values: state.values,
976
- presets: _nullishCoalesce(_optionalChain([state, 'access', _46 => _46.description, 'access', _47 => _47.presets, 'optionalAccess', _48 => _48.map, 'call', _49 => _49((p) => p.name)]), () => ( [])),
1415
+ presets: _nullishCoalesce(_optionalChain([state, 'access', _64 => _64.description, 'access', _65 => _65.presets, 'optionalAccess', _66 => _66.map, 'call', _67 => _67((p) => p.name)]), () => ( [])),
977
1416
  tracks: Object.entries(state.tracks).map(([control, track]) => ({
978
1417
  control,
979
1418
  keyframes: track.length
@@ -1280,7 +1719,7 @@ function createEffectAuthoringToolProvider(host, options) {
1280
1719
  const tools = [
1281
1720
  describeTool,
1282
1721
  getSourceTool,
1283
- ..._optionalChain([session, 'optionalAccess', _50 => _50.setSource]) ? [setSourceTool] : [],
1722
+ ..._optionalChain([session, 'optionalAccess', _68 => _68.setSource]) ? [setSourceTool] : [],
1284
1723
  setValuesTool,
1285
1724
  resetValuesTool,
1286
1725
  applyPresetTool,
@@ -1352,4 +1791,28 @@ function createEffectAuthoringToolProvider(host, options) {
1352
1791
 
1353
1792
 
1354
1793
 
1355
- exports.CAMERA_MOVE_MAX_MS = _chunkOPSK22DLcjs.CAMERA_MOVE_MAX_MS; exports.CAMERA_MOVE_ROLES = _chunkOPSK22DLcjs.CAMERA_MOVE_ROLES; exports.EFFECT_ERROR_CODES = _chunkOPSK22DLcjs.EFFECT_ERROR_CODES; exports.EFFECT_KINDS = _chunkOPSK22DLcjs.EFFECT_KINDS; exports.EFFECT_USES = _chunkOPSK22DLcjs.EFFECT_USES; exports.EFFECT_USE_LABELS = EFFECT_USE_LABELS; exports.EffectControlError = _chunkOPSK22DLcjs.EffectControlError; exports.EffectDisposedError = _chunkOPSK22DLcjs.EffectDisposedError; exports.EffectError = _chunkOPSK22DLcjs.EffectError; exports.EffectRendererPool = _chunkPY4GWSE2cjs.EffectRendererPool; exports.EffectUnsupportedError = _chunkOPSK22DLcjs.EffectUnsupportedError; exports.EffectsSlot = _chunkOPSK22DLcjs.EffectsSlot; exports.NoEffectsProviderError = _chunkOPSK22DLcjs.NoEffectsProviderError; exports.UnknownEffectError = _chunkOPSK22DLcjs.UnknownEffectError; exports.applyEffectMask = _chunkOPSK22DLcjs.applyEffectMask; exports.cameraBoxOfView = _chunkOPSK22DLcjs.cameraBoxOfView; exports.cameraMoveField = _chunkOPSK22DLcjs.cameraMoveField; exports.cameraMoveIdList = _chunkOPSK22DLcjs.cameraMoveIdList; exports.cameraMoveParts = _chunkOPSK22DLcjs.cameraMoveParts; exports.cameraMovesFor = _chunkOPSK22DLcjs.cameraMovesFor; exports.cameraViewOfBox = _chunkOPSK22DLcjs.cameraViewOfBox; exports.checkEffectProvider = checkEffectProvider; exports.countEffectTags = _chunkOPSK22DLcjs.countEffectTags; exports.createEffectAuthoringSession = _chunkC73U5UI3cjs.createEffectAuthoringSession; exports.createEffectAuthoringToolProvider = createEffectAuthoringToolProvider; exports.createEffectPixels = _chunkOPSK22DLcjs.createEffectPixels; exports.createEffectToolProvider = _chunkOPSK22DLcjs.createEffectToolProvider; exports.createFakeEffectProvider = createFakeEffectProvider; exports.effectControlField = effectControlField; exports.effectFieldValue = effectFieldValue; exports.effectFontFamilies = effectFontFamilies; exports.effectOffered = _chunkOPSK22DLcjs.effectOffered; exports.effectParameterFields = effectParameterFields; exports.effectSampleInputs = effectSampleInputs; exports.effectSamplePicture = effectSamplePicture; exports.effectValueErrors = _chunkOPSK22DLcjs.effectValueErrors; exports.encodeEffectFloat = _chunkOPSK22DLcjs.encodeEffectFloat; exports.groupEffectsByCategory = groupEffectsByCategory; exports.hasEffectTags = _chunkOPSK22DLcjs.hasEffectTags; exports.isCameraView = _chunkOPSK22DLcjs.isCameraView; exports.isEffectError = _chunkOPSK22DLcjs.isEffectError; exports.isEffectFontControl = isEffectFontControl; exports.isEffectPixels = _chunkOPSK22DLcjs.isEffectPixels; exports.linearToSrgb = _chunkOPSK22DLcjs.linearToSrgb; exports.normaliseEffectTag = _chunkOPSK22DLcjs.normaliseEffectTag; exports.renderEffectThumbnail = renderEffectThumbnail; exports.resolveCameraMoveSpec = _chunkOPSK22DLcjs.resolveCameraMoveSpec; exports.resolveEffectValues = _chunkOPSK22DLcjs.resolveEffectValues; exports.sampleCameraViews = _chunkOPSK22DLcjs.sampleCameraViews; exports.sampleEffectCameraMove = _chunkOPSK22DLcjs.sampleEffectCameraMove; exports.searchEffectSummaries = _chunkOPSK22DLcjs.searchEffectSummaries; exports.srgbToLinear = _chunkOPSK22DLcjs.srgbToLinear;
1794
+
1795
+
1796
+
1797
+
1798
+
1799
+
1800
+
1801
+
1802
+
1803
+
1804
+
1805
+
1806
+
1807
+
1808
+
1809
+
1810
+
1811
+
1812
+
1813
+
1814
+
1815
+
1816
+
1817
+
1818
+ exports.CAMERA_MOVE_MAX_MS = _chunk2K5TELHVcjs.CAMERA_MOVE_MAX_MS; exports.CAMERA_MOVE_ROLES = _chunk2K5TELHVcjs.CAMERA_MOVE_ROLES; exports.EFFECT_ERROR_CODES = _chunk2K5TELHVcjs.EFFECT_ERROR_CODES; exports.EFFECT_KINDS = _chunk2K5TELHVcjs.EFFECT_KINDS; exports.EFFECT_LAYER_ROLES = _chunk2K5TELHVcjs.EFFECT_LAYER_ROLES; exports.EFFECT_LAYER_USES = EFFECT_LAYER_USES; exports.EFFECT_SEQUENCE_NAME = EFFECT_SEQUENCE_NAME; exports.EFFECT_SUBJECT_KINDS = _chunk2K5TELHVcjs.EFFECT_SUBJECT_KINDS; exports.EFFECT_TEMPLATE_SLOT_TYPES = _chunk2K5TELHVcjs.EFFECT_TEMPLATE_SLOT_TYPES; exports.EFFECT_TRANSITION_MS = _chunk2K5TELHVcjs.EFFECT_TRANSITION_MS; exports.EFFECT_USES = _chunk2K5TELHVcjs.EFFECT_USES; exports.EFFECT_USE_LABELS = EFFECT_USE_LABELS; exports.EffectControlError = _chunk2K5TELHVcjs.EffectControlError; exports.EffectDisposedError = _chunk2K5TELHVcjs.EffectDisposedError; exports.EffectError = _chunk2K5TELHVcjs.EffectError; exports.EffectRendererPool = _chunkPY4GWSE2cjs.EffectRendererPool; exports.EffectUnsupportedError = _chunk2K5TELHVcjs.EffectUnsupportedError; exports.EffectsSlot = _chunk2K5TELHVcjs.EffectsSlot; exports.NoEffectsProviderError = _chunk2K5TELHVcjs.NoEffectsProviderError; exports.UnknownEffectError = _chunk2K5TELHVcjs.UnknownEffectError; exports.UnknownTemplateError = _chunk2K5TELHVcjs.UnknownTemplateError; exports.applyEffectMask = _chunk2K5TELHVcjs.applyEffectMask; exports.cameraBoxOfView = _chunk2K5TELHVcjs.cameraBoxOfView; exports.cameraMoveField = _chunk2K5TELHVcjs.cameraMoveField; exports.cameraMoveIdList = _chunk2K5TELHVcjs.cameraMoveIdList; exports.cameraMoveParts = _chunk2K5TELHVcjs.cameraMoveParts; exports.cameraMovesFor = _chunk2K5TELHVcjs.cameraMovesFor; exports.cameraViewOfBox = _chunk2K5TELHVcjs.cameraViewOfBox; exports.checkEffectProvider = checkEffectProvider; exports.checkEffectSequence = checkEffectSequence; exports.checkTemplateValues = checkTemplateValues; exports.countEffectTags = _chunk2K5TELHVcjs.countEffectTags; exports.createEffectAuthoringSession = _chunkRG4O6K2Acjs.createEffectAuthoringSession; exports.createEffectAuthoringToolProvider = createEffectAuthoringToolProvider; exports.createEffectPixels = _chunk2K5TELHVcjs.createEffectPixels; exports.createEffectToolProvider = _chunk2K5TELHVcjs.createEffectToolProvider; exports.createFakeEffectProvider = createFakeEffectProvider; exports.effectControlField = effectControlField; exports.effectFieldValue = effectFieldValue; exports.effectFontFamilies = effectFontFamilies; exports.effectLayerInput = effectLayerInput; exports.effectLayerOffered = effectLayerOffered; exports.effectLayerRole = effectLayerRole; exports.effectOffered = _chunk2K5TELHVcjs.effectOffered; exports.effectParameterFields = effectParameterFields; exports.effectSampleInputs = effectSampleInputs; exports.effectSamplePicture = effectSamplePicture; exports.effectSequenceEffects = effectSequenceEffects; exports.effectSequenceSlots = effectSequenceSlots; exports.effectSubjectKind = effectSubjectKind; exports.effectSubjectProblem = effectSubjectProblem; exports.effectValueErrors = _chunk2K5TELHVcjs.effectValueErrors; exports.encodeEffectFloat = _chunk2K5TELHVcjs.encodeEffectFloat; exports.groupEffectsByCategory = groupEffectsByCategory; exports.hasEffectTags = _chunk2K5TELHVcjs.hasEffectTags; exports.isCameraView = _chunk2K5TELHVcjs.isCameraView; exports.isEffectError = _chunk2K5TELHVcjs.isEffectError; exports.isEffectFontControl = isEffectFontControl; exports.isEffectPixels = _chunk2K5TELHVcjs.isEffectPixels; exports.isSubjectTemplateSlot = isSubjectTemplateSlot; exports.linearToSrgb = _chunk2K5TELHVcjs.linearToSrgb; exports.normaliseEffectTag = _chunk2K5TELHVcjs.normaliseEffectTag; exports.renderEffectThumbnail = renderEffectThumbnail; exports.resolveCameraMoveSpec = _chunk2K5TELHVcjs.resolveCameraMoveSpec; exports.resolveEffectValues = _chunk2K5TELHVcjs.resolveEffectValues; exports.sampleCameraViews = _chunk2K5TELHVcjs.sampleCameraViews; exports.sampleEffectCameraMove = _chunk2K5TELHVcjs.sampleEffectCameraMove; exports.searchEffectSummaries = _chunk2K5TELHVcjs.searchEffectSummaries; exports.searchTemplateSummaries = searchTemplateSummaries; exports.srgbToLinear = _chunk2K5TELHVcjs.srgbToLinear; exports.templateDefaultValues = templateDefaultValues; exports.templateSlotSchema = templateSlotSchema; exports.templateSlotSummary = templateSlotSummary; exports.templateSlotTakes = templateSlotTakes; exports.templateValueProblem = templateValueProblem; exports.templateValuesSchema = templateValuesSchema;