@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.
- package/dist/animation-editor/compile.d.cts +3 -0
- package/dist/animation-editor/compile.d.ts +3 -0
- package/dist/animation-editor/controller.d.cts +67 -2
- package/dist/animation-editor/controller.d.ts +67 -2
- package/dist/animation-editor/edit.d.cts +1 -1
- package/dist/animation-editor/edit.d.ts +1 -1
- package/dist/animation-editor/evaluate.d.cts +8 -1
- package/dist/animation-editor/evaluate.d.ts +8 -1
- package/dist/animation-editor/index.cjs +1202 -371
- package/dist/animation-editor/index.d.cts +3 -0
- package/dist/animation-editor/index.d.ts +3 -0
- package/dist/animation-editor/index.js +1032 -201
- package/dist/animation-editor/issues.d.cts +28 -0
- package/dist/animation-editor/issues.d.ts +28 -0
- package/dist/animation-editor/layer-edit.d.cts +55 -0
- package/dist/animation-editor/layer-edit.d.ts +55 -0
- package/dist/animation-editor/layer-tools.d.cts +11 -0
- package/dist/animation-editor/layer-tools.d.ts +11 -0
- package/dist/animation-editor/layers.d.cts +166 -0
- package/dist/animation-editor/layers.d.ts +166 -0
- package/dist/animation-editor/parse.d.cts +2 -0
- package/dist/animation-editor/parse.d.ts +2 -0
- package/dist/animation-editor/types.d.cts +44 -1
- package/dist/animation-editor/types.d.ts +44 -1
- package/dist/canvas/editorDocument.d.cts +49 -4
- package/dist/canvas/editorDocument.d.ts +49 -4
- package/dist/canvas/index.cjs +57 -30
- package/dist/canvas/index.js +44 -17
- package/dist/chunk-6RZVFYGJ.cjs +255 -0
- package/dist/{chunk-RG4O6K2A.cjs → chunk-A7PQNIBX.cjs} +14 -14
- package/dist/{chunk-ERJA5CGT.cjs → chunk-DGWOGQJ5.cjs} +8 -1
- package/dist/{chunk-TYCJGFCF.js → chunk-EUKY4KFX.js} +8 -1
- package/dist/chunk-I277KJLQ.js +255 -0
- package/dist/{chunk-2K5TELHV.cjs → chunk-JAOSL334.cjs} +10 -10
- package/dist/{chunk-MUSZYMBX.js → chunk-TEFQISBY.js} +1 -1
- package/dist/{chunk-6QLTUGMO.js → chunk-WDDUPWVG.js} +1 -1
- package/dist/{chunk-A653N65Q.cjs → chunk-ZQIWBJGH.cjs} +7 -7
- package/dist/effects/index.cjs +114 -322
- package/dist/effects/index.js +23 -231
- package/dist/image-editor/index.cjs +16 -16
- package/dist/image-editor/index.js +4 -4
- package/dist/paint-editor/index.cjs +10 -10
- package/dist/paint-editor/index.js +5 -5
- package/dist/vector/index.cjs +6 -6
- package/dist/vector/index.js +1 -1
- package/dist/video-editor/index.cjs +339 -339
- package/dist/video-editor/index.js +5 -5
- package/package.json +1 -1
- package/skills/pixerate-animation-editor/SKILL.md +10 -0
- package/skills/pixerate-animation-motion-graphics/SKILL.md +4 -0
- package/skills/pixerate-canvas/SKILL.md +2 -2
- package/skills/pixerate-video-editor/SKILL.md +11 -0
- package/skills/pixerate-video-montage/SKILL.md +2 -0
- package/dist/{chunk-PQYDJ2AV.js → chunk-SIK3LT6M.js} +16 -16
package/dist/canvas/index.js
CHANGED
|
@@ -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-
|
|
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
|
|
11790
|
-
|
|
11791
|
-
|
|
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
|
|
11795
|
-
|
|
11796
|
-
|
|
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(
|
|
11827
|
-
edges: options.getEdges().map(
|
|
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
|
-
|
|
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) =>
|
|
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
|
|
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(...
|
|
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(...
|
|
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(...
|
|
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,
|
|
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,
|
|
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,
|
|
186
|
+
if (problems.length) throw new (0, _chunkJAOSL334cjs.EffectControlError)(effectId, problems);
|
|
187
187
|
}
|
|
188
188
|
if (description.kind === "motion") {
|
|
189
|
-
throw new (0,
|
|
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,
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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,
|
|
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,
|
|
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 };
|