@pixerate/editor 0.232.0 → 0.234.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 (54) 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/editorDocument.d.cts +49 -4
  26. package/dist/canvas/editorDocument.d.ts +49 -4
  27. package/dist/canvas/index.cjs +57 -30
  28. package/dist/canvas/index.js +44 -17
  29. package/dist/chunk-6RZVFYGJ.cjs +255 -0
  30. package/dist/{chunk-RG4O6K2A.cjs → chunk-A7PQNIBX.cjs} +14 -14
  31. package/dist/{chunk-ERJA5CGT.cjs → chunk-DGWOGQJ5.cjs} +8 -1
  32. package/dist/{chunk-TYCJGFCF.js → chunk-EUKY4KFX.js} +8 -1
  33. package/dist/chunk-I277KJLQ.js +255 -0
  34. package/dist/{chunk-2K5TELHV.cjs → chunk-JAOSL334.cjs} +10 -10
  35. package/dist/{chunk-MUSZYMBX.js → chunk-TEFQISBY.js} +1 -1
  36. package/dist/{chunk-6QLTUGMO.js → chunk-WDDUPWVG.js} +1 -1
  37. package/dist/{chunk-A653N65Q.cjs → chunk-ZQIWBJGH.cjs} +7 -7
  38. package/dist/effects/index.cjs +114 -322
  39. package/dist/effects/index.js +23 -231
  40. package/dist/image-editor/index.cjs +16 -16
  41. package/dist/image-editor/index.js +4 -4
  42. package/dist/paint-editor/index.cjs +10 -10
  43. package/dist/paint-editor/index.js +5 -5
  44. package/dist/vector/index.cjs +6 -6
  45. package/dist/vector/index.js +1 -1
  46. package/dist/video-editor/index.cjs +339 -339
  47. package/dist/video-editor/index.js +5 -5
  48. package/package.json +1 -1
  49. package/skills/pixerate-animation-editor/SKILL.md +10 -0
  50. package/skills/pixerate-animation-motion-graphics/SKILL.md +4 -0
  51. package/skills/pixerate-canvas/SKILL.md +2 -2
  52. package/skills/pixerate-video-editor/SKILL.md +11 -0
  53. package/skills/pixerate-video-montage/SKILL.md +2 -0
  54. package/dist/{chunk-PQYDJ2AV.js → chunk-SIK3LT6M.js} +16 -16
@@ -115,9 +115,6 @@ import {
115
115
  CAPTURE_OVERLAY_SELECTORS,
116
116
  rasterizeElement
117
117
  } from "../chunk-XCK7QK5D.js";
118
- import {
119
- EffectRendererPool
120
- } from "../chunk-EHLOCVWB.js";
121
118
  import {
122
119
  createCaptureToolProvider,
123
120
  unionCaptureRects
@@ -215,12 +212,15 @@ import {
215
212
  shapeToPolygon,
216
213
  simplifyRing
217
214
  } from "../chunk-PWBZH3FK.js";
215
+ import {
216
+ EffectRendererPool
217
+ } from "../chunk-EHLOCVWB.js";
218
218
  import {
219
219
  EffectUnsupportedError,
220
220
  EffectsSlot,
221
221
  createEffectToolProvider,
222
222
  resolveEffectValues
223
- } from "../chunk-PQYDJ2AV.js";
223
+ } from "../chunk-SIK3LT6M.js";
224
224
  import "../chunk-V2ZCJRDM.js";
225
225
  import {
226
226
  brushstrokeScaleBucket
@@ -11786,17 +11786,26 @@ function createCanvasEffectsToolProvider(controller, options = {}) {
11786
11786
 
11787
11787
  // src/canvas/editorDocument.ts
11788
11788
  var RUNTIME_NODE_KEYS = ["selected", "dragging", "measured", "resizing"];
11789
- var stripNode = (node) => {
11790
- const copy = { ...node };
11791
- for (const key of RUNTIME_NODE_KEYS) delete copy[key];
11789
+ var RUNTIME_EDGE_KEYS = ["selected"];
11790
+ var omit = (value, keys) => {
11791
+ const copy = { ...value };
11792
+ for (const key of keys) delete copy[key];
11792
11793
  return copy;
11793
11794
  };
11794
- var stripEdge = (edge) => {
11795
- const { selected: _selected, ...rest } = edge;
11796
- return rest;
11795
+ var omitKeys = (options = {}) => ({
11796
+ node: [...RUNTIME_NODE_KEYS, ...options.omitNodeKeys ?? []],
11797
+ edge: [...RUNTIME_EDGE_KEYS, ...options.omitEdgeKeys ?? []]
11798
+ });
11799
+ function canvasDocumentContentKey(nodes, edges, options) {
11800
+ const keys = omitKeys(options);
11801
+ return JSON.stringify([nodes.map((n3) => omit(n3, keys.node)), edges.map((e) => omit(e, keys.edge))]);
11802
+ }
11803
+ var isViewport = (value) => {
11804
+ const v = value;
11805
+ return !!v && typeof v === "object" && [v.x, v.y, v.zoom].every((n3) => typeof n3 === "number" && Number.isFinite(n3)) && v.zoom > 0;
11797
11806
  };
11798
11807
  function checkCanvasDocument(document2) {
11799
- const hint = "A canvas document is { nodes: [{ id, position: { x, y }, data }], edges: [{ id, source, target }], scenes? } as get_canvas_document returns it.";
11808
+ const hint = "A canvas document is { nodes: [{ id, position: { x, y }, data }], edges: [{ id, source, target }], scenes?, viewport? } as get_canvas_document returns it.";
11800
11809
  const value = document2;
11801
11810
  if (!value || typeof value !== "object" || !Array.isArray(value.nodes)) throw new Error(`nodes must be an array. ${hint}`);
11802
11811
  if (!Array.isArray(value.edges)) throw new Error(`edges must be an array. ${hint}`);
@@ -11819,25 +11828,42 @@ function checkCanvasDocument(document2) {
11819
11828
  }
11820
11829
  });
11821
11830
  if (value.scenes !== void 0 && !Array.isArray(value.scenes)) throw new Error(`scenes must be an array. ${hint}`);
11831
+ if (value.viewport !== void 0 && !isViewport(value.viewport)) throw new Error(`viewport must be { x, y, zoom } with finite numbers and a zoom above 0. ${hint}`);
11822
11832
  }
11823
11833
  function createCanvasEditorDocument(options) {
11824
11834
  const { history, scenes: scenes2 } = options;
11835
+ const keys = omitKeys(options);
11825
11836
  const snapshot = () => ({
11826
- nodes: options.getNodes().map(stripNode),
11827
- edges: options.getEdges().map(stripEdge),
11828
- ...scenes2 ? { scenes: scenes2.toJSON().scenes } : {}
11837
+ nodes: options.getNodes().map((n3) => omit(n3, keys.node)),
11838
+ edges: options.getEdges().map((e) => omit(e, keys.edge)),
11839
+ ...scenes2 ? { scenes: scenes2.toJSON().scenes } : {},
11840
+ ...options.getViewport ? { viewport: { ...options.getViewport() } } : {}
11829
11841
  });
11830
11842
  const apply = (doc) => {
11831
11843
  options.setNodes(doc.nodes.map((n3) => ({ ...n3 })));
11832
11844
  options.setEdges(doc.edges.map((e) => ({ ...e })));
11833
11845
  if (scenes2) scenes2.load(doc.scenes ?? []);
11846
+ if (doc.viewport) options.setViewport?.({ ...doc.viewport });
11847
+ };
11848
+ const check = (document2) => {
11849
+ checkCanvasDocument(document2);
11850
+ const next = document2;
11851
+ if (options.validateNode) {
11852
+ next.nodes.forEach((node, i) => {
11853
+ const problem = options.validateNode(node, i);
11854
+ if (problem) throw new Error(`Node "${node.id}" (nodes[${i}]): ${problem}`);
11855
+ });
11856
+ }
11857
+ return next;
11834
11858
  };
11835
11859
  return defineEditorDocument({
11836
11860
  kind: "canvas",
11861
+ formatVersion: options.formatVersion,
11862
+ migrations: options.migrations,
11863
+ assets: options.assets,
11837
11864
  get: snapshot,
11838
11865
  load: (document2, { history: mode }) => {
11839
- checkCanvasDocument(document2);
11840
- const next = document2;
11866
+ const next = check(options.normalize ? options.normalize(document2) : document2);
11841
11867
  if (mode === "record") {
11842
11868
  const before = snapshot();
11843
11869
  history.execute({ name: "Load canvas", execute: () => apply(next), undo: () => apply(before) });
@@ -11863,7 +11889,7 @@ function createCanvasEditorDocument(options) {
11863
11889
  function createCanvasGestureRecorder(options) {
11864
11890
  let before = null;
11865
11891
  const take = () => ({ nodes: options.getNodes(), edges: options.getEdges?.() });
11866
- const key = (s) => JSON.stringify([s.nodes.map(stripNode), s.edges?.map(stripEdge)]);
11892
+ const key = (s) => canvasDocumentContentKey(s.nodes, s.edges ?? []);
11867
11893
  const restore = (s) => {
11868
11894
  options.setNodes(s.nodes);
11869
11895
  if (s.edges && options.setEdges) options.setEdges(s.edges);
@@ -12273,6 +12299,7 @@ export {
12273
12299
  canCombineShapeNodes,
12274
12300
  canOffsetShapeNodes,
12275
12301
  canOutlineShapeNodeStrokes,
12302
+ canvasDocumentContentKey,
12276
12303
  canvasEffectErrorReason,
12277
12304
  canvasEffectStatus,
12278
12305
  canvasEffectsPool,
@@ -0,0 +1,255 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
+
3
+
4
+ var _chunkJAOSL334cjs = require('./chunk-JAOSL334.cjs');
5
+
6
+ // src/effects/templates.ts
7
+ var SLOT_NAME = /^[A-Za-z][\w-]*$/;
8
+ var COLOR = /^#[0-9a-fA-F]{6}$/;
9
+ var EFFECT_SEQUENCE_NAME = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
10
+ var isObject = (v) => !!v && typeof v === "object" && !Array.isArray(v);
11
+ var isSubjectTemplateSlot = (slot) => slot.type === "image" || slot.type === "video" || slot.type === "svg";
12
+ function effectSubjectKind(subject) {
13
+ if (!isObject(subject)) return void 0;
14
+ for (const k of ["slot", "image", "video", "svg", "text"]) if (typeof subject[k] === "string") return k;
15
+ return void 0;
16
+ }
17
+ 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)}`;
18
+ function range(slot) {
19
+ const whole = slot.integer ? "whole number" : "number";
20
+ if (slot.min !== void 0 && slot.max !== void 0) return `a ${whole} from ${slot.min} to ${slot.max}`;
21
+ if (slot.min !== void 0) return `a ${whole} of at least ${slot.min}`;
22
+ if (slot.max !== void 0) return `a ${whole} of at most ${slot.max}`;
23
+ return `a ${whole}`;
24
+ }
25
+ function templateSlotTakes(slot) {
26
+ switch (slot.type) {
27
+ case "text":
28
+ return `words${slot.maxLength !== void 0 ? ` (up to ${slot.maxLength} characters)` : ""}`;
29
+ case "color":
30
+ return `a colour written #RRGGBB, like "${slot.default}"`;
31
+ case "number":
32
+ return range(slot);
33
+ case "video":
34
+ return "a video URL";
35
+ case "svg":
36
+ return "SVG markup or an SVG URL";
37
+ default:
38
+ return "a picture: a URL, a data: URL or <svg> markup";
39
+ }
40
+ }
41
+ function templateValueProblem(slot, value) {
42
+ const no = (extra = "") => `Slot "${slot.name}" takes ${templateSlotTakes(slot)}${extra}, not ${typeName(value)}.`;
43
+ switch (slot.type) {
44
+ case "text":
45
+ if (typeof value !== "string") return no();
46
+ 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.`;
47
+ return void 0;
48
+ case "color":
49
+ return typeof value === "string" && COLOR.test(value) ? void 0 : no();
50
+ case "number":
51
+ if (typeof value !== "number" || !Number.isFinite(value)) return no();
52
+ if (slot.integer && !Number.isInteger(value)) return `Slot "${slot.name}" takes ${range(slot)}; ${value} is not whole.`;
53
+ 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.`;
54
+ return void 0;
55
+ default: {
56
+ const host = ` (or { "slot": "${slot.name}" } to leave it for the host)`;
57
+ if (typeof value === "string") return value.trim() ? void 0 : no(host);
58
+ const kind = effectSubjectKind(value);
59
+ if (!kind) return no(host);
60
+ 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.`;
61
+ const fits = kind === slot.type || slot.type === "image" && kind === "svg";
62
+ if (!fits) return `Slot "${slot.name}" takes { "${slot.type}": \u2026 }${slot.type === "image" ? ' or { "svg": \u2026 }' : ""}, not { "${kind}": \u2026 }.`;
63
+ return value[kind].trim() ? void 0 : `Slot "${slot.name}"'s "${kind}" is a non-empty string.`;
64
+ }
65
+ }
66
+ }
67
+ var slotList = (slots) => slots.length ? `the slots are ${slots.map((s) => `${s.name} (${s.type})`).join(", ")}` : "the template has no slots";
68
+ function checkTemplateValues(slots, values) {
69
+ if (values === void 0) return [];
70
+ if (!isObject(values)) return [`Values are an object of slot names to values; ${slotList(slots)}.`];
71
+ const byName = new Map(slots.map((s) => [s.name, s]));
72
+ const errors = [];
73
+ for (const [name, value] of Object.entries(values)) {
74
+ const slot = byName.get(name);
75
+ if (!slot) errors.push(`There is no slot "${name}"; ${slotList(slots)}.`);
76
+ else if (value !== void 0) {
77
+ const problem = templateValueProblem(slot, value);
78
+ if (problem) errors.push(problem);
79
+ }
80
+ }
81
+ return errors;
82
+ }
83
+ function templateSlotSchema(slot) {
84
+ const about = `${slot.label}${slot.description ? `: ${slot.description}` : ""}.`;
85
+ switch (slot.type) {
86
+ case "text":
87
+ 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)}.` };
88
+ case "color":
89
+ return { type: "string", pattern: COLOR.source, description: `${about} A colour as #RRGGBB. Default ${slot.default}.` };
90
+ case "number":
91
+ return {
92
+ type: slot.integer ? "integer" : "number",
93
+ ...slot.min !== void 0 ? { minimum: slot.min } : {},
94
+ ...slot.max !== void 0 ? { maximum: slot.max } : {},
95
+ description: `${about} ${range(slot).replace(/^a /, "A ")}. Default ${slot.default}.`
96
+ };
97
+ default: {
98
+ const key = slot.type;
99
+ const object = (k, what) => ({ type: "object", properties: { [k]: { type: "string", description: what } }, required: [k], additionalProperties: false, description: `{ "${k}": \u2026 }` });
100
+ return {
101
+ anyOf: [
102
+ { 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." },
103
+ object(key, key === "video" ? "A video URL." : key === "svg" ? "SVG markup or an SVG URL." : "A picture URL or a data: URL."),
104
+ ...key === "image" ? [object("svg", "SVG markup.")] : [],
105
+ object("slot", "A slot name, to leave the subject for the host to fill.")
106
+ ],
107
+ description: `${about} ${templateSlotTakes(slot).replace(/^a /, "A ")}. ${slot.hasDefault ? "Default: a placeholder picture." : "No default: left out, the host fills it."}`
108
+ };
109
+ }
110
+ }
111
+ }
112
+ function templateValuesSchema(slots) {
113
+ return {
114
+ type: "object",
115
+ properties: Object.fromEntries(slots.map((s) => [s.name, templateSlotSchema(s)])),
116
+ additionalProperties: false,
117
+ 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."}`
118
+ };
119
+ }
120
+ function templateDefaultValues(slots) {
121
+ const out = {};
122
+ for (const s of slots) if (!isSubjectTemplateSlot(s)) out[s.name] = s.default;
123
+ return out;
124
+ }
125
+ function templateSlotSummary(slot) {
126
+ const fallback = isSubjectTemplateSlot(slot) ? slot.hasDefault ? "a placeholder by default" : "the host fills it when none is given" : `default ${JSON.stringify(slot.default)}`;
127
+ return `${slot.name} (${slot.type}): ${slot.label}; takes ${templateSlotTakes(slot)}; ${fallback}.`;
128
+ }
129
+ function searchTemplateSummaries(catalog, options = {}) {
130
+ const words = (_nullishCoalesce(options.query, () => ( ""))).toLowerCase().split(/\s+/).filter(Boolean);
131
+ const scored = [];
132
+ for (const t of catalog) {
133
+ if (!_chunkJAOSL334cjs.hasEffectTags.call(void 0, t, options.tags)) continue;
134
+ let score = 0;
135
+ const name = t.name.toLowerCase();
136
+ const rest = [t.id, ..._nullishCoalesce(t.tags, () => ( [])), t.description].join(" ").toLowerCase();
137
+ if (!words.every((w) => name.includes(w) || rest.includes(w))) continue;
138
+ for (const w of words) score += name.includes(w) ? 2 : 1;
139
+ scored.push({ t, score });
140
+ }
141
+ scored.sort((a, b) => b.score - a.score);
142
+ const out = scored.map((s) => s.t);
143
+ return options.limit !== void 0 ? out.slice(0, Math.max(0, options.limit)) : out;
144
+ }
145
+ var effectLayerRole = (layer) => _nullishCoalesce(layer.role, () => ( (layer.rect ? "subject" : "background")));
146
+ function effectLayerInput(description) {
147
+ const images = description.inputs.filter((i) => i.kind === "image");
148
+ return _optionalChain([(_nullishCoalesce(images.find((i) => i.name === "source"), () => ( images.find((i) => i.name !== "from" && i.name !== "to")))), 'optionalAccess', _ => _.name]);
149
+ }
150
+ var EFFECT_LAYER_USES = ["generator", "filter", "overlay", "title"];
151
+ var effectLayerOffered = (e) => (e.kind === "shader" || e.kind === "vector") && e.uses.some((u) => EFFECT_LAYER_USES.includes(u));
152
+ var isRect = (r) => isObject(r) && ["x", "y", "width", "height"].every((k) => Number.isFinite(r[k])) && r.width > 0 && r.height > 0;
153
+ var isLayerTime = (t) => typeof t === "number" && Number.isFinite(t) && t >= 0 || isObject(t) && Number.isInteger(t.shots) && t.shots >= 1;
154
+ function effectSubjectProblem(subject) {
155
+ const kind = effectSubjectKind(subject);
156
+ if (!kind) return `a subject is one of { image }, { video }, { svg }, { text } or { slot }, not ${typeName(subject)}`;
157
+ if (!subject[kind].trim()) return `a subject's "${kind}" is a non-empty string`;
158
+ return void 0;
159
+ }
160
+ function checkEffectSequence(sequence, catalog) {
161
+ const problems = [];
162
+ if (!isObject(sequence)) return ["A sequence is an object with name, stage and shots."];
163
+ if (typeof sequence.name !== "string" || !sequence.name) problems.push("The sequence needs a name.");
164
+ const stage = sequence.stage;
165
+ if (!isObject(stage) || !(Number(stage.width) > 0) || !(Number(stage.height) > 0)) problems.push("The sequence needs a stage { width, height } in pixels, both > 0.");
166
+ if (!Array.isArray(sequence.shots) || !sequence.shots.length) return [...problems, "The sequence needs at least one shot."];
167
+ const byId = catalog ? new Map(catalog.map((e) => [e.id, e])) : void 0;
168
+ const ids = /* @__PURE__ */ new Set();
169
+ sequence.shots.forEach((shot, i) => {
170
+ const at = `shot ${i + 1}`;
171
+ if (!isObject(shot)) return void problems.push(`${at} is not an object.`);
172
+ if (!(Number.isFinite(shot.hold) && shot.hold >= 0)) problems.push(`${at}: hold must be ms \u2265 0.`);
173
+ for (const k of ["title", "caption"]) if (shot[k] !== void 0 && typeof shot[k] !== "string") problems.push(`${at}: ${k} must be words.`);
174
+ if (shot.camera !== void 0) {
175
+ const camera = shot.camera;
176
+ if (!isObject(camera)) problems.push(`${at}: camera must be an object.`);
177
+ 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.`);
178
+ }
179
+ if (!Array.isArray(shot.layers)) problems.push(`${at}: layers must be a list (it may be empty).`);
180
+ else
181
+ shot.layers.forEach((layer, j) => {
182
+ const where = `${at}, layer ${j + 1}`;
183
+ if (!isObject(layer)) return void problems.push(`${where} is not an object.`);
184
+ if (layer.id !== void 0) {
185
+ if (typeof layer.id !== "string" || !layer.id) problems.push(`${where}: id must be a non-empty string.`);
186
+ else if (ids.has(layer.id)) problems.push(`${where}: id "${layer.id}" is used twice.`);
187
+ else ids.add(layer.id);
188
+ }
189
+ if (layer.effect === void 0 && layer.subject === void 0) problems.push(`${where} has neither an effect nor a subject.`);
190
+ if (layer.effect !== void 0 && (typeof layer.effect !== "string" || !layer.effect)) problems.push(`${where}: effect must be an effect id.`);
191
+ else if (typeof layer.effect === "string" && byId) {
192
+ const e = byId.get(layer.effect);
193
+ if (!e) problems.push(`${where}: the provider has no effect "${layer.effect}".`);
194
+ 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.`);
195
+ }
196
+ if (layer.subject !== void 0) {
197
+ const p = effectSubjectProblem(layer.subject);
198
+ if (p) problems.push(`${where}: ${p}.`);
199
+ }
200
+ if (layer.role !== void 0 && !_chunkJAOSL334cjs.EFFECT_LAYER_ROLES.includes(layer.role)) problems.push(`${where}: role is one of ${_chunkJAOSL334cjs.EFFECT_LAYER_ROLES.join(", ")}.`);
201
+ if (layer.rect !== void 0 && !isRect(layer.rect)) problems.push(`${where}: rect must be { x, y, width, height } with width and height > 0.`);
202
+ 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.`);
203
+ if (layer.opacity !== void 0 && !(typeof layer.opacity === "number" && layer.opacity >= 0 && layer.opacity <= 1)) problems.push(`${where}: opacity is 0\u20131.`);
204
+ if (layer.fade !== void 0 && !(typeof layer.fade === "number" && layer.fade >= 0)) problems.push(`${where}: fade is ms \u2265 0.`);
205
+ if (layer.values !== void 0 && !isObject(layer.values)) problems.push(`${where}: values must be an object of control values.`);
206
+ });
207
+ if (shot.transition !== void 0) {
208
+ const t = shot.transition;
209
+ if (i === 0) problems.push(`${at} has a transition, but there is no shot before it.`);
210
+ if (!isObject(t) || typeof t.effect !== "string" || !t.effect) problems.push(`${at}: transition needs an effect id.`);
211
+ else {
212
+ if (t.ms !== void 0 && !(typeof t.ms === "number" && t.ms > 0)) problems.push(`${at}: transition ms must be > 0.`);
213
+ const e = _optionalChain([byId, 'optionalAccess', _2 => _2.get, 'call', _3 => _3(t.effect)]);
214
+ if (byId && !e) problems.push(`${at}: the provider has no transition "${t.effect}".`);
215
+ else if (e && !e.uses.includes("transition")) problems.push(`${at}: "${t.effect}" is not a transition (its uses are ${e.uses.join(", ")}).`);
216
+ }
217
+ }
218
+ });
219
+ return problems;
220
+ }
221
+ function effectSequenceEffects(sequence) {
222
+ const out = /* @__PURE__ */ new Set();
223
+ for (const shot of sequence.shots) {
224
+ for (const l of shot.layers) if (l.effect) out.add(l.effect);
225
+ if (shot.transition) out.add(shot.transition.effect);
226
+ }
227
+ return [...out];
228
+ }
229
+ function effectSequenceSlots(sequence) {
230
+ const out = /* @__PURE__ */ new Set();
231
+ for (const shot of sequence.shots) for (const l of shot.layers) if (l.subject && "slot" in l.subject) out.add(l.subject.slot);
232
+ return [...out];
233
+ }
234
+
235
+
236
+
237
+
238
+
239
+
240
+
241
+
242
+
243
+
244
+
245
+
246
+
247
+
248
+
249
+
250
+
251
+
252
+
253
+
254
+
255
+ exports.EFFECT_SEQUENCE_NAME = EFFECT_SEQUENCE_NAME; exports.isSubjectTemplateSlot = isSubjectTemplateSlot; exports.effectSubjectKind = effectSubjectKind; exports.templateSlotTakes = templateSlotTakes; exports.templateValueProblem = templateValueProblem; exports.checkTemplateValues = checkTemplateValues; exports.templateSlotSchema = templateSlotSchema; exports.templateValuesSchema = templateValuesSchema; exports.templateDefaultValues = templateDefaultValues; exports.templateSlotSummary = templateSlotSummary; exports.searchTemplateSummaries = searchTemplateSummaries; exports.effectLayerRole = effectLayerRole; exports.effectLayerInput = effectLayerInput; exports.EFFECT_LAYER_USES = EFFECT_LAYER_USES; exports.effectLayerOffered = effectLayerOffered; exports.effectSubjectProblem = effectSubjectProblem; exports.checkEffectSequence = checkEffectSequence; exports.effectSequenceEffects = effectSequenceEffects; exports.effectSequenceSlots = effectSequenceSlots;
@@ -3,7 +3,7 @@
3
3
 
4
4
 
5
5
 
6
- var _chunk2K5TELHVcjs = require('./chunk-2K5TELHV.cjs');
6
+ var _chunkJAOSL334cjs = require('./chunk-JAOSL334.cjs');
7
7
 
8
8
 
9
9
  var _chunkFJ2MSI43cjs = require('./chunk-FJ2MSI43.cjs');
@@ -26,7 +26,7 @@ function documentErrors(doc, description) {
26
26
  const isRecord = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
27
27
  if (doc.values !== void 0) {
28
28
  if (!isRecord(doc.values)) errors.push({ path: "/values", message: "must be an object of control values" });
29
- else errors.push(..._chunk2K5TELHVcjs.effectValueErrors.call(void 0, description, doc.values).map((e) => ({ ...e, path: `/values${e.path}` })));
29
+ else errors.push(..._chunkJAOSL334cjs.effectValueErrors.call(void 0, description, doc.values).map((e) => ({ ...e, path: `/values${e.path}` })));
30
30
  }
31
31
  if (doc.tracks !== void 0) {
32
32
  if (!isRecord(doc.tracks)) errors.push({ path: "/tracks", message: "must be an object of keyframe lists" });
@@ -39,7 +39,7 @@ function documentErrors(doc, description) {
39
39
  kfs.forEach((kf, i) => {
40
40
  if (!isRecord(kf)) return errors.push({ path: `${at}/${i}`, message: "must be a keyframe object" });
41
41
  if (typeof kf.time !== "number" || !Number.isFinite(kf.time) || kf.time < 0) errors.push({ path: `${at}/${i}/time`, message: "must be a finite number of ms >= 0" });
42
- errors.push(..._chunk2K5TELHVcjs.effectValueErrors.call(void 0, description, { [control]: kf.value }).map((e) => ({ ...e, path: `${at}/${i}/value` })));
42
+ errors.push(..._chunkJAOSL334cjs.effectValueErrors.call(void 0, description, { [control]: kf.value }).map((e) => ({ ...e, path: `${at}/${i}/value` })));
43
43
  if (kf.easing !== void 0 && !_chunkDWJJI6RTcjs.isAnimationEasing.call(void 0, kf.easing)) errors.push({ path: `${at}/${i}/easing`, message: "is not a valid easing" });
44
44
  });
45
45
  }
@@ -49,7 +49,7 @@ function documentErrors(doc, description) {
49
49
  else
50
50
  doc.presets.forEach((p, i) => {
51
51
  if (!isRecord(p) || typeof p.name !== "string" || !p.name) return errors.push({ path: `/presets/${i}`, message: "must have a name" });
52
- errors.push(..._chunk2K5TELHVcjs.effectValueErrors.call(void 0, description, p.values).map((e) => ({ ...e, path: `/presets/${i}/values${e.path}` })));
52
+ errors.push(..._chunkJAOSL334cjs.effectValueErrors.call(void 0, description, p.values).map((e) => ({ ...e, path: `/presets/${i}/values${e.path}` })));
53
53
  });
54
54
  }
55
55
  if (doc.duration !== void 0 && (typeof doc.duration !== "number" || !Number.isFinite(doc.duration) || !(doc.duration > 0))) {
@@ -170,7 +170,7 @@ async function createEffectAuthoringSession(source, options) {
170
170
  if (isDocumentSource(source)) {
171
171
  const doc = source.document;
172
172
  if (doc.version !== 1 || !doc.effectId) {
173
- throw new (0, _chunk2K5TELHVcjs.EffectUnsupportedError)("Invalid effect authoring document: version 1 required");
173
+ throw new (0, _chunkJAOSL334cjs.EffectUnsupportedError)("Invalid effect authoring document: version 1 required");
174
174
  }
175
175
  effectId = doc.effectId;
176
176
  initialDoc = doc;
@@ -178,15 +178,15 @@ async function createEffectAuthoringSession(source, options) {
178
178
  effectId = source.effectId;
179
179
  requestedPreset = source.preset;
180
180
  } else {
181
- throw new (0, _chunk2K5TELHVcjs.EffectUnsupportedError)("Invalid effect authoring source");
181
+ throw new (0, _chunkJAOSL334cjs.EffectUnsupportedError)("Invalid effect authoring source");
182
182
  }
183
183
  const description = await provider.describe(effectId);
184
184
  if (initialDoc) {
185
185
  const problems = documentErrors(initialDoc, description);
186
- if (problems.length) throw new (0, _chunk2K5TELHVcjs.EffectControlError)(effectId, problems);
186
+ if (problems.length) throw new (0, _chunkJAOSL334cjs.EffectControlError)(effectId, problems);
187
187
  }
188
188
  if (description.kind === "motion") {
189
- throw new (0, _chunk2K5TELHVcjs.EffectUnsupportedError)("Motion effects cannot be authored as pixel effects", effectId);
189
+ throw new (0, _chunkJAOSL334cjs.EffectUnsupportedError)("Motion effects cannot be authored as pixel effects", effectId);
190
190
  }
191
191
  let disposed = false;
192
192
  let playing = false;
@@ -207,7 +207,7 @@ async function createEffectAuthoringSession(source, options) {
207
207
  const found = description.presets.find((p) => p.name === requestedPreset);
208
208
  if (!found) {
209
209
  const validNames = description.presets.map((p) => `"${p.name}"`).join(", ");
210
- throw new (0, _chunk2K5TELHVcjs.EffectUnsupportedError)(
210
+ throw new (0, _chunkJAOSL334cjs.EffectUnsupportedError)(
211
211
  `Unknown preset "${requestedPreset}" for effect "${effectId}". Valid presets are: ${validNames || "none"}`,
212
212
  effectId
213
213
  );
@@ -321,7 +321,7 @@ async function createEffectAuthoringSession(source, options) {
321
321
  if (!validNames.includes(name)) {
322
322
  return { ok: false, message: `there is no control "${name}"; the controls are ${validNames.join(", ")}` };
323
323
  }
324
- const errors = _chunk2K5TELHVcjs.effectValueErrors.call(void 0, description, { [name]: value });
324
+ const errors = _chunkJAOSL334cjs.effectValueErrors.call(void 0, description, { [name]: value });
325
325
  if (errors.length > 0) {
326
326
  return { ok: false, message: valueErrorMessage(errors) };
327
327
  }
@@ -391,7 +391,7 @@ async function createEffectAuthoringSession(source, options) {
391
391
  if (!validNames.includes(k)) {
392
392
  return { ok: false, message: `there is no control "${k}"; the controls are ${validNames.join(", ")}` };
393
393
  }
394
- const errors = _chunk2K5TELHVcjs.effectValueErrors.call(void 0, description, { [k]: v });
394
+ const errors = _chunkJAOSL334cjs.effectValueErrors.call(void 0, description, { [k]: v });
395
395
  if (errors.length > 0) {
396
396
  return { ok: false, message: valueErrorMessage(errors) };
397
397
  }
@@ -528,7 +528,7 @@ async function createEffectAuthoringSession(source, options) {
528
528
  return { ok: false, message: `invalid easing: ${String(easing)}` };
529
529
  }
530
530
  const targetValue = value !== void 0 ? value : valuesAtTime(time, baseValues, tracks)[name];
531
- const errors = _chunk2K5TELHVcjs.effectValueErrors.call(void 0, description, { [name]: targetValue });
531
+ const errors = _chunkJAOSL334cjs.effectValueErrors.call(void 0, description, { [name]: targetValue });
532
532
  if (errors.length > 0) {
533
533
  return { ok: false, message: valueErrorMessage(errors) };
534
534
  }
@@ -705,7 +705,7 @@ async function createEffectAuthoringSession(source, options) {
705
705
  },
706
706
  async createPreview(opts) {
707
707
  if (disposed) {
708
- throw new (0, _chunk2K5TELHVcjs.EffectDisposedError)(effectId);
708
+ throw new (0, _chunkJAOSL334cjs.EffectDisposedError)(effectId);
709
709
  }
710
710
  let renderer;
711
711
  try {
@@ -730,7 +730,7 @@ async function createEffectAuthoringSession(source, options) {
730
730
  height: renderer.height,
731
731
  depth: renderer.depth,
732
732
  render: async (req) => {
733
- if (disposed) throw new (0, _chunk2K5TELHVcjs.EffectDisposedError)(effectId);
733
+ if (disposed) throw new (0, _chunkJAOSL334cjs.EffectDisposedError)(effectId);
734
734
  const effectiveValues = _nullishCoalesce(req.values, () => ( valuesAtTime(req.time, baseValues, tracks)));
735
735
  const pixels = await renderer.render({
736
736
  ...req,
@@ -37,7 +37,14 @@ var MOTION_ISSUE_CODES = {
37
37
  "camera-move-first-shot": { severity: "note", wording: "The first shot cuts to its framing, so the move its camera gets in with does not play." },
38
38
  "camera-move-not-played": { severity: "note", wording: "A shot names a camera move, but there is no effects provider with camera moves to play it, so the camera eases instead." },
39
39
  "camera-move-unknown": { severity: "error", wording: "A shot names a camera move the effects provider does not have, or one of the wrong role." },
40
- "camera-move-values": { severity: "error", wording: "A camera move's preset or values do not fit its controls." }
40
+ "camera-move-values": { severity: "error", wording: "A camera move's preset or values do not fit its controls." },
41
+ "layer-effect-unknown": { severity: "error", wording: "A shot layer names an effect the provider does not have, one that cannot be a layer, or a subject its effect cannot take." },
42
+ "layer-effect-values": { severity: "error", wording: "A shot layer's preset or values do not fit its effect's controls." },
43
+ "layer-not-drawn": { severity: "note", wording: "Shot layers name provider effects, but there is no effects provider to draw them, so they are left out of frames." },
44
+ "layer-slot-empty": { severity: "warning", wording: "A shot layer's subject is a slot nobody has filled, so it draws nothing." },
45
+ "transition-unknown": { severity: "error", wording: "A shot names a transition the provider does not have, or an effect that is not a transition." },
46
+ "transition-first-shot": { severity: "note", wording: "The first shot has a transition, but there is no shot before it, so it does not play." },
47
+ "transition-not-played": { severity: "note", wording: "Shots name transitions, but there is no effects provider to play them, so they crossfade." }
41
48
  };
42
49
  function motionIssue(code, message, extra = {}) {
43
50
  return { code, severity: MOTION_ISSUE_CODES[code].severity, message, ...extra };
@@ -37,7 +37,14 @@ var MOTION_ISSUE_CODES = {
37
37
  "camera-move-first-shot": { severity: "note", wording: "The first shot cuts to its framing, so the move its camera gets in with does not play." },
38
38
  "camera-move-not-played": { severity: "note", wording: "A shot names a camera move, but there is no effects provider with camera moves to play it, so the camera eases instead." },
39
39
  "camera-move-unknown": { severity: "error", wording: "A shot names a camera move the effects provider does not have, or one of the wrong role." },
40
- "camera-move-values": { severity: "error", wording: "A camera move's preset or values do not fit its controls." }
40
+ "camera-move-values": { severity: "error", wording: "A camera move's preset or values do not fit its controls." },
41
+ "layer-effect-unknown": { severity: "error", wording: "A shot layer names an effect the provider does not have, one that cannot be a layer, or a subject its effect cannot take." },
42
+ "layer-effect-values": { severity: "error", wording: "A shot layer's preset or values do not fit its effect's controls." },
43
+ "layer-not-drawn": { severity: "note", wording: "Shot layers name provider effects, but there is no effects provider to draw them, so they are left out of frames." },
44
+ "layer-slot-empty": { severity: "warning", wording: "A shot layer's subject is a slot nobody has filled, so it draws nothing." },
45
+ "transition-unknown": { severity: "error", wording: "A shot names a transition the provider does not have, or an effect that is not a transition." },
46
+ "transition-first-shot": { severity: "note", wording: "The first shot has a transition, but there is no shot before it, so it does not play." },
47
+ "transition-not-played": { severity: "note", wording: "Shots name transitions, but there is no effects provider to play them, so they crossfade." }
41
48
  };
42
49
  function motionIssue(code, message, extra = {}) {
43
50
  return { code, severity: MOTION_ISSUE_CODES[code].severity, message, ...extra };