@pixerate/editor 0.125.0 → 0.127.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/index.d.cts +2 -3
- package/dist/animation/index.d.ts +2 -3
- package/dist/animation-editor/index.cjs +71 -73
- package/dist/animation-editor/index.cjs.map +1 -1
- package/dist/animation-editor/index.d.cts +6 -8
- package/dist/animation-editor/index.d.ts +6 -8
- package/dist/animation-editor/index.js +11 -13
- package/dist/animation-editor/index.js.map +1 -1
- package/dist/{bezier-CBzKKDjl.d.cts → bezier-DBz0IgEt.d.cts} +22 -2
- package/dist/{bezier-CWv6LQal.d.ts → bezier-DWI5MEkI.d.ts} +22 -2
- package/dist/{brushstrokeRender-LRV7GXGD.js → brushstrokeRender-7RUITO42.js} +3 -3
- package/dist/{brushstrokeRender-EELTV7U4.cjs → brushstrokeRender-OW6ENCZG.cjs} +7 -7
- package/dist/{brushstrokeRender-EELTV7U4.cjs.map → brushstrokeRender-OW6ENCZG.cjs.map} +1 -1
- package/dist/canvas/index.cjs +423 -37
- package/dist/canvas/index.cjs.map +1 -1
- package/dist/canvas/index.d.cts +189 -11
- package/dist/canvas/index.d.ts +189 -11
- package/dist/canvas/index.js +395 -9
- package/dist/canvas/index.js.map +1 -1
- package/dist/{chunk-7LQO6OHH.cjs → chunk-33SO3QWP.cjs} +4 -4
- package/dist/{chunk-7LQO6OHH.cjs.map → chunk-33SO3QWP.cjs.map} +1 -1
- package/dist/{chunk-MPQAO33O.js → chunk-A6KHMKI4.js} +3 -3
- package/dist/{chunk-V5YGPRCZ.cjs → chunk-BEGEWQHD.cjs} +41 -41
- package/dist/{chunk-V5YGPRCZ.cjs.map → chunk-BEGEWQHD.cjs.map} +1 -1
- package/dist/{chunk-N3FVUOZD.cjs → chunk-BJTCSLF6.cjs} +7 -7
- package/dist/{chunk-N3FVUOZD.cjs.map → chunk-BJTCSLF6.cjs.map} +1 -1
- package/dist/{chunk-WUDPFWAN.js → chunk-F7Q2NE2Y.js} +3 -3
- package/dist/{chunk-G6WXWS4Y.js → chunk-FICSDDDF.js} +2 -2
- package/dist/{chunk-GUZ47CJM.cjs → chunk-IZ4WRXZA.cjs} +1 -1
- package/dist/{chunk-GUZ47CJM.cjs.map → chunk-IZ4WRXZA.cjs.map} +1 -1
- package/dist/{chunk-QDJKUBWE.cjs → chunk-JODTP4DP.cjs} +176 -5
- package/dist/chunk-JODTP4DP.cjs.map +1 -0
- package/dist/{chunk-GLWZXQ4Q.js → chunk-KHNZ6MOU.js} +1 -1
- package/dist/chunk-KHNZ6MOU.js.map +1 -0
- package/dist/{chunk-GCJWMEYW.cjs → chunk-KSJLDRHK.cjs} +46 -46
- package/dist/{chunk-GCJWMEYW.cjs.map → chunk-KSJLDRHK.cjs.map} +1 -1
- package/dist/{chunk-QQKTOA4U.cjs → chunk-ORE334I6.cjs} +132 -132
- package/dist/{chunk-QQKTOA4U.cjs.map → chunk-ORE334I6.cjs.map} +1 -1
- package/dist/{chunk-X6KTSFAE.js → chunk-Q4NBEVV5.js} +2 -2
- package/dist/{chunk-XZWOLXWA.js → chunk-QFSTQHZY.js} +174 -3
- package/dist/chunk-QFSTQHZY.js.map +1 -0
- package/dist/{chunk-FPRIUR4T.js → chunk-ROZFX4QI.js} +3 -3
- package/dist/{chunk-UXFI3CDZ.cjs → chunk-SFCPGMCT.cjs} +8 -8
- package/dist/{chunk-UXFI3CDZ.cjs.map → chunk-SFCPGMCT.cjs.map} +1 -1
- package/dist/{chunk-J67OLQUQ.js → chunk-UABQTYQF.js} +3 -3
- package/dist/{chunk-O5RVCDEC.cjs → chunk-XLUYXUBD.cjs} +88 -88
- package/dist/{chunk-O5RVCDEC.cjs.map → chunk-XLUYXUBD.cjs.map} +1 -1
- package/dist/{chunk-FG274FYT.js → chunk-YGJIER2R.js} +2 -2
- package/dist/effects/index.cjs +32 -34
- package/dist/effects/index.cjs.map +1 -1
- package/dist/effects/index.d.cts +6 -38
- package/dist/effects/index.d.ts +6 -38
- package/dist/effects/index.js +3 -5
- package/dist/effects/index.js.map +1 -1
- package/dist/evaluate-BbCeF6pt.d.ts +114 -0
- package/dist/evaluate-BsxYieLN.d.cts +114 -0
- package/dist/{export-DVl4fWy5.d.cts → export-Cbr9IqpJ.d.cts} +1 -1
- package/dist/{export-Bp7ji2r4.d.cts → export-CcldobdN.d.cts} +3 -3
- package/dist/{export-C1s4eolZ.d.ts → export-ClPKUB-v.d.ts} +1 -1
- package/dist/{export-DAyPY94f.d.ts → export-PGhOpDmz.d.ts} +3 -3
- package/dist/{helpers-i95Ob6Vi.d.cts → helpers-C5aAd44p.d.cts} +67 -4
- package/dist/{helpers-BBLlekuM.d.ts → helpers-CPWcK504.d.ts} +67 -4
- package/dist/image-editor/index.cjs +619 -621
- package/dist/image-editor/index.cjs.map +1 -1
- package/dist/image-editor/index.d.cts +9 -11
- package/dist/image-editor/index.d.ts +9 -11
- package/dist/image-editor/index.js +6 -8
- package/dist/image-editor/index.js.map +1 -1
- package/dist/{opentype-14PDI5D2.d.ts → opentype-01rMIuQR.d.ts} +1 -1
- package/dist/{opentype-D80AVmMu.d.cts → opentype-BgqvmGT-.d.cts} +1 -1
- package/dist/paint-editor/index.cjs +737 -117
- package/dist/paint-editor/index.cjs.map +1 -1
- package/dist/paint-editor/index.d.cts +248 -13
- package/dist/paint-editor/index.d.ts +248 -13
- package/dist/paint-editor/index.js +635 -15
- package/dist/paint-editor/index.js.map +1 -1
- package/dist/{pathfinder-DjISxkUv.d.ts → pathfinder-D-h0Imus.d.ts} +1 -1
- package/dist/{pathfinder-C0UoFypx.d.cts → pathfinder-DgG0Z9Lr.d.cts} +1 -1
- package/dist/{player-cGLrngL_.d.ts → player-BK2kKbfd.d.ts} +1 -1
- package/dist/{player-CBtEoU2x.d.cts → player-CmbY3218.d.cts} +1 -1
- package/dist/pool-C7GtrL34.d.cts +34 -0
- package/dist/pool-CTrtciaN.d.ts +34 -0
- package/dist/{svg-DJKriJ4A.d.ts → svg-BRLwcibA.d.ts} +2 -3
- package/dist/{svg-BkRL-fZJ.d.cts → svg-DLBBPQP9.d.cts} +2 -3
- package/dist/{tools-CM8Oe8F3.d.ts → tools-AugT22z3.d.ts} +1 -1
- package/dist/{tools-DZCv2kX1.d.cts → tools-BpCmUNxb.d.cts} +1 -1
- package/dist/vector/index.cjs +923 -925
- package/dist/vector/index.cjs.map +1 -1
- package/dist/vector/index.d.cts +10 -12
- package/dist/vector/index.d.ts +10 -12
- package/dist/vector/index.js +11 -13
- package/dist/vector/index.js.map +1 -1
- package/dist/video-editor/index.cjs +269 -271
- package/dist/video-editor/index.cjs.map +1 -1
- package/dist/video-editor/index.d.cts +6 -8
- package/dist/video-editor/index.d.ts +6 -8
- package/dist/video-editor/index.js +3 -5
- package/dist/video-editor/index.js.map +1 -1
- package/dist/{warp-CH9MM435.d.cts → warp-C13L_GRn.d.cts} +1 -1
- package/dist/{warp-k_PdtXOG.d.ts → warp-q8FK5HHi.d.ts} +1 -1
- package/package.json +1 -1
- package/skills/pixerate-canvas/SKILL.md +19 -0
- package/skills/pixerate-paint-editor/SKILL.md +40 -1
- package/dist/behavior-Ymbld6jL.d.cts +0 -60
- package/dist/behavior-Ymbld6jL.d.ts +0 -60
- package/dist/chunk-GLWZXQ4Q.js.map +0 -1
- package/dist/chunk-IOXKXQNW.cjs +0 -178
- package/dist/chunk-IOXKXQNW.cjs.map +0 -1
- package/dist/chunk-QDJKUBWE.cjs.map +0 -1
- package/dist/chunk-TGKT5QAB.js +0 -178
- package/dist/chunk-TGKT5QAB.js.map +0 -1
- package/dist/chunk-XZWOLXWA.js.map +0 -1
- package/dist/evaluate-2S3vSPLy.d.cts +0 -55
- package/dist/evaluate-CfmT6xA3.d.ts +0 -55
- package/dist/gradient-KDfCvhuj.d.cts +0 -66
- package/dist/gradient-KDfCvhuj.d.ts +0 -66
- /package/dist/{brushstrokeRender-LRV7GXGD.js.map → brushstrokeRender-7RUITO42.js.map} +0 -0
- /package/dist/{chunk-MPQAO33O.js.map → chunk-A6KHMKI4.js.map} +0 -0
- /package/dist/{chunk-WUDPFWAN.js.map → chunk-F7Q2NE2Y.js.map} +0 -0
- /package/dist/{chunk-G6WXWS4Y.js.map → chunk-FICSDDDF.js.map} +0 -0
- /package/dist/{chunk-X6KTSFAE.js.map → chunk-Q4NBEVV5.js.map} +0 -0
- /package/dist/{chunk-FPRIUR4T.js.map → chunk-ROZFX4QI.js.map} +0 -0
- /package/dist/{chunk-J67OLQUQ.js.map → chunk-UABQTYQF.js.map} +0 -0
- /package/dist/{chunk-FG274FYT.js.map → chunk-YGJIER2R.js.map} +0 -0
package/dist/canvas/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
hatchPath,
|
|
7
7
|
interiorPoint,
|
|
8
8
|
pathfinder
|
|
9
|
-
} from "../chunk-
|
|
9
|
+
} from "../chunk-Q4NBEVV5.js";
|
|
10
10
|
import {
|
|
11
11
|
ARCH_METRICS,
|
|
12
12
|
GANTT_METRICS,
|
|
@@ -50,7 +50,7 @@ import {
|
|
|
50
50
|
profileAlongPolyline,
|
|
51
51
|
renderShapeBrushstroke,
|
|
52
52
|
validateCanvasBrush
|
|
53
|
-
} from "../chunk-
|
|
53
|
+
} from "../chunk-UABQTYQF.js";
|
|
54
54
|
import {
|
|
55
55
|
TokenError,
|
|
56
56
|
getTokenCollection,
|
|
@@ -82,6 +82,9 @@ import {
|
|
|
82
82
|
CAPTURE_OVERLAY_SELECTORS,
|
|
83
83
|
rasterizeElement
|
|
84
84
|
} from "../chunk-O2W2SP3C.js";
|
|
85
|
+
import {
|
|
86
|
+
EffectRendererPool
|
|
87
|
+
} from "../chunk-FJ3324TZ.js";
|
|
85
88
|
import {
|
|
86
89
|
createCaptureToolProvider,
|
|
87
90
|
unionCaptureRects
|
|
@@ -153,7 +156,7 @@ import {
|
|
|
153
156
|
unitePaths,
|
|
154
157
|
windingNumber,
|
|
155
158
|
xorPolygons
|
|
156
|
-
} from "../chunk-
|
|
159
|
+
} from "../chunk-YGJIER2R.js";
|
|
157
160
|
import {
|
|
158
161
|
CANVAS_GRADIENT_PRESETS,
|
|
159
162
|
PIXERATE_BRAND_GRADIENT,
|
|
@@ -180,7 +183,14 @@ import {
|
|
|
180
183
|
resolveCanvasGradient,
|
|
181
184
|
shapeToPolygon,
|
|
182
185
|
simplifyRing
|
|
183
|
-
} from "../chunk-
|
|
186
|
+
} from "../chunk-KHNZ6MOU.js";
|
|
187
|
+
import {
|
|
188
|
+
EffectUnsupportedError,
|
|
189
|
+
EffectsSlot,
|
|
190
|
+
createEffectToolProvider,
|
|
191
|
+
resolveEffectValues
|
|
192
|
+
} from "../chunk-QFSTQHZY.js";
|
|
193
|
+
import "../chunk-4FX5ACVG.js";
|
|
184
194
|
import {
|
|
185
195
|
ANIMATION_TIME_EPSILON,
|
|
186
196
|
AnimationPlayer,
|
|
@@ -1599,6 +1609,8 @@ function cloneScene(scene) {
|
|
|
1599
1609
|
viewport: { x: scene.viewport.x, y: scene.viewport.y, zoom: scene.viewport.zoom }
|
|
1600
1610
|
};
|
|
1601
1611
|
if (scene.nodeIds) copy.nodeIds = [...scene.nodeIds];
|
|
1612
|
+
const t = scene.transition;
|
|
1613
|
+
if (t && typeof t.effect === "string" && t.effect) copy.transition = JSON.parse(JSON.stringify(t));
|
|
1602
1614
|
return copy;
|
|
1603
1615
|
}
|
|
1604
1616
|
function parseCanvasScenes(input) {
|
|
@@ -7975,11 +7987,11 @@ function createCanvasComponentsController(options) {
|
|
|
7975
7987
|
},
|
|
7976
7988
|
canResetOverrides(id) {
|
|
7977
7989
|
const at = target(id);
|
|
7978
|
-
const
|
|
7979
|
-
if (!
|
|
7980
|
-
const changedProps = !
|
|
7981
|
-
const own =
|
|
7982
|
-
return own ||
|
|
7990
|
+
const info2 = at ? inspectCanvasInstance(nodes(), at) : void 0;
|
|
7991
|
+
if (!info2) return "Select an instance or a layer inside one.";
|
|
7992
|
+
const changedProps = !info2.nested && info2.properties.some((p) => p.value !== p.default);
|
|
7993
|
+
const own = info2.id === at ? info2.overrides.length > 0 : getNodeOverrides(nodes().find((n3) => n3.id === at)).length > 0;
|
|
7994
|
+
return own || info2.id === at && changedProps ? true : "No overrides to reset.";
|
|
7983
7995
|
},
|
|
7984
7996
|
/** Push the (outermost) instance's overrides to its main component. */
|
|
7985
7997
|
pushOverrides(id) {
|
|
@@ -11601,6 +11613,371 @@ function createCanvasCaptureToolProvider(options) {
|
|
|
11601
11613
|
id: options.id ?? "canvas-capture"
|
|
11602
11614
|
});
|
|
11603
11615
|
}
|
|
11616
|
+
|
|
11617
|
+
// src/canvas/effects.ts
|
|
11618
|
+
var CANVAS_EFFECT_PLACES = {
|
|
11619
|
+
/** Paints a shape's inside. */
|
|
11620
|
+
fill: ["generator", "interactive"],
|
|
11621
|
+
/** Draws over a node's box. */
|
|
11622
|
+
overlay: ["overlay", "title", "interactive", "generator"],
|
|
11623
|
+
transition: ["transition"]
|
|
11624
|
+
};
|
|
11625
|
+
function canvasNodeEffect(node) {
|
|
11626
|
+
const shape = node.data?.shape;
|
|
11627
|
+
return isShapeDescription(shape) ? shape.effect : void 0;
|
|
11628
|
+
}
|
|
11629
|
+
function createCanvasEffectsController(options) {
|
|
11630
|
+
const slot = new EffectsSlot();
|
|
11631
|
+
if (options.effects) slot.set(options.effects);
|
|
11632
|
+
const describe = async (effect, place2) => {
|
|
11633
|
+
const d = await slot.require().describe(effect);
|
|
11634
|
+
const allowed = CANVAS_EFFECT_PLACES[place2];
|
|
11635
|
+
if (d.kind === "motion" || !d.uses.some((u) => allowed.includes(u))) {
|
|
11636
|
+
const where = place2 === "transition" ? "a scene transition" : place2 === "fill" ? "a fill" : "an overlay";
|
|
11637
|
+
throw new EffectUnsupportedError(`"${d.id}" (${d.name}) is a ${d.uses.join(" / ")} effect and cannot be ${where}, which takes ${allowed.join(" or ")} effects; search_effects with use "${allowed[0]}" lists ones that fit.`, d.id);
|
|
11638
|
+
}
|
|
11639
|
+
return d;
|
|
11640
|
+
};
|
|
11641
|
+
const shapeNode = (id) => {
|
|
11642
|
+
const node = options.getNodes().find((n3) => n3.id === id);
|
|
11643
|
+
if (!node) throw new Error(`There is no node "${id}"; the nodes are ${options.getNodes().map((n3) => `"${n3.id}"`).slice(0, 20).join(", ") || "none"}.`);
|
|
11644
|
+
const shape = node.data?.shape;
|
|
11645
|
+
if (!isShapeDescription(shape)) throw new Error(`Node "${id}" is not a shape; effects draw on shape nodes (data.shape).`);
|
|
11646
|
+
return { node, shape };
|
|
11647
|
+
};
|
|
11648
|
+
const commit = (label, next) => {
|
|
11649
|
+
const before = options.getNodes();
|
|
11650
|
+
if (options.history) options.history.execute({ name: label, execute: () => options.setNodes(next), undo: () => options.setNodes(before), redo: () => options.setNodes(next) });
|
|
11651
|
+
else options.setNodes(next);
|
|
11652
|
+
};
|
|
11653
|
+
const withEffect = (id, effect) => options.getNodes().map((n3) => {
|
|
11654
|
+
if (n3.id !== id) return n3;
|
|
11655
|
+
const shape = { ...n3.data.shape };
|
|
11656
|
+
if (effect) shape.effect = effect;
|
|
11657
|
+
else delete shape.effect;
|
|
11658
|
+
return { ...n3, data: { ...n3.data, shape } };
|
|
11659
|
+
});
|
|
11660
|
+
const mergeValues = (d, was, values) => {
|
|
11661
|
+
const base = { ...was };
|
|
11662
|
+
const given = {};
|
|
11663
|
+
for (const [k, v] of Object.entries(values)) {
|
|
11664
|
+
if (v !== null) given[k] = v;
|
|
11665
|
+
else if (k in d.controls.properties) base[k] = d.defaults[k];
|
|
11666
|
+
else throw new Error(`"${k}" is not a control of "${d.id}"; its controls are ${Object.keys(d.controls.properties).join(", ")}.`);
|
|
11667
|
+
}
|
|
11668
|
+
return { ...base, ...resolveEffectValues({ ...d, defaults: base }, given) };
|
|
11669
|
+
};
|
|
11670
|
+
return {
|
|
11671
|
+
/** The provider slot. */
|
|
11672
|
+
effects: slot,
|
|
11673
|
+
get effectsProvider() {
|
|
11674
|
+
return slot.provider;
|
|
11675
|
+
},
|
|
11676
|
+
/** Registers (or with `null` removes) the effects provider. */
|
|
11677
|
+
setEffectsProvider(provider) {
|
|
11678
|
+
slot.set(provider);
|
|
11679
|
+
},
|
|
11680
|
+
/** Registers `provider` and returns a function that removes it again. */
|
|
11681
|
+
useEffects(provider) {
|
|
11682
|
+
return slot.use(provider);
|
|
11683
|
+
},
|
|
11684
|
+
/** The shape nodes that carry effects (or one node's). */
|
|
11685
|
+
list(nodeId) {
|
|
11686
|
+
return options.getNodes().filter((n3) => !nodeId || n3.id === nodeId).map((n3) => ({ nodeId: n3.id, effect: canvasNodeEffect(n3) })).filter((e) => !!e.effect);
|
|
11687
|
+
},
|
|
11688
|
+
/**
|
|
11689
|
+
* Draws a provider effect on a shape node: `fill` paints its inside (generators), `overlay`
|
|
11690
|
+
* draws over its box (overlays, titles, interactive effects). Replaces any effect it had. One
|
|
11691
|
+
* undoable step. Returns the effect.
|
|
11692
|
+
*/
|
|
11693
|
+
async applyNodeEffect(nodeId, effect, opts = {}) {
|
|
11694
|
+
shapeNode(nodeId);
|
|
11695
|
+
const mode = opts.mode ?? "fill";
|
|
11696
|
+
const d = await describe(effect, mode);
|
|
11697
|
+
if (opts.opacity !== void 0 && !(opts.opacity >= 0 && opts.opacity <= 1)) throw new Error("opacity must be from 0 to 1.");
|
|
11698
|
+
const next = { effect: d.id, provider: slot.require().id, name: d.name, values: resolveEffectValues(d, opts.values), mode, ...opts.opacity !== void 0 && opts.opacity !== 1 ? { opacity: opts.opacity } : {} };
|
|
11699
|
+
commit(`Add effect ${d.name}`, withEffect(nodeId, next));
|
|
11700
|
+
return next;
|
|
11701
|
+
},
|
|
11702
|
+
/** Changes a node's effect: `values` merged (`null` resets), `mode`, `opacity`, `playing`. One undoable step. */
|
|
11703
|
+
async updateNodeEffect(nodeId, changes) {
|
|
11704
|
+
const { shape } = shapeNode(nodeId);
|
|
11705
|
+
const was = shape.effect;
|
|
11706
|
+
if (!was) throw new Error(`Node "${nodeId}" has no effect; add one with apply_effect.`);
|
|
11707
|
+
const next = { ...was };
|
|
11708
|
+
if (changes.values || changes.mode) {
|
|
11709
|
+
const d = await describe(was.effect, changes.mode ?? was.mode);
|
|
11710
|
+
if (changes.values) next.values = mergeValues(d, was.values, changes.values);
|
|
11711
|
+
if (changes.mode) next.mode = changes.mode;
|
|
11712
|
+
} else slot.require();
|
|
11713
|
+
if (changes.opacity !== void 0) {
|
|
11714
|
+
if (!(changes.opacity >= 0 && changes.opacity <= 1)) throw new Error("opacity must be from 0 to 1.");
|
|
11715
|
+
if (changes.opacity === 1) delete next.opacity;
|
|
11716
|
+
else next.opacity = changes.opacity;
|
|
11717
|
+
}
|
|
11718
|
+
if (changes.playing !== void 0) {
|
|
11719
|
+
if (changes.playing) delete next.playing;
|
|
11720
|
+
else next.playing = false;
|
|
11721
|
+
}
|
|
11722
|
+
commit(`Change effect ${was.name ?? was.effect}`, withEffect(nodeId, next));
|
|
11723
|
+
return next;
|
|
11724
|
+
},
|
|
11725
|
+
/** Removes a node's effect (works without a provider). One undoable step. */
|
|
11726
|
+
removeNodeEffect(nodeId) {
|
|
11727
|
+
const { shape } = shapeNode(nodeId);
|
|
11728
|
+
if (!shape.effect) throw new Error(`Node "${nodeId}" has no effect.`);
|
|
11729
|
+
commit(`Remove effect ${shape.effect.name ?? shape.effect.effect}`, withEffect(nodeId, void 0));
|
|
11730
|
+
return shape.effect;
|
|
11731
|
+
},
|
|
11732
|
+
/** The scenes, in order (empty without a Scenes store). */
|
|
11733
|
+
scenes() {
|
|
11734
|
+
return options.scenes?.getState().scenes ?? [];
|
|
11735
|
+
},
|
|
11736
|
+
/** The transition into a scene, if it has one. */
|
|
11737
|
+
sceneTransition(sceneId) {
|
|
11738
|
+
return options.scenes?.getScene(sceneId)?.transition;
|
|
11739
|
+
},
|
|
11740
|
+
/**
|
|
11741
|
+
* Sets (or with `effect` null removes) the provider transition played when the canvas moves to
|
|
11742
|
+
* a scene. Returns the transition.
|
|
11743
|
+
*/
|
|
11744
|
+
async setSceneTransition(sceneId, effect, opts = {}) {
|
|
11745
|
+
const scenes2 = options.scenes;
|
|
11746
|
+
if (!scenes2) throw new Error("This canvas has no Scenes store.");
|
|
11747
|
+
if (!scenes2.getScene(sceneId)) throw new Error(`There is no scene "${sceneId}"; the scenes are ${scenes2.getState().scenes.map((s) => `"${s.id}"`).join(", ") || "none"}.`);
|
|
11748
|
+
if (effect === null) {
|
|
11749
|
+
scenes2.update(sceneId, { transition: void 0 });
|
|
11750
|
+
return null;
|
|
11751
|
+
}
|
|
11752
|
+
const d = await describe(effect, "transition");
|
|
11753
|
+
const duration = opts.duration ?? d.duration ?? 600;
|
|
11754
|
+
if (!(duration > 0)) throw new Error("duration must be a number of ms above 0.");
|
|
11755
|
+
const transition = { effect: d.id, provider: slot.require().id, name: d.name, values: resolveEffectValues(d, opts.values), duration };
|
|
11756
|
+
scenes2.update(sceneId, { transition });
|
|
11757
|
+
return transition;
|
|
11758
|
+
}
|
|
11759
|
+
};
|
|
11760
|
+
}
|
|
11761
|
+
|
|
11762
|
+
// src/canvas/effect-player.ts
|
|
11763
|
+
var defaultClock = {
|
|
11764
|
+
now: () => typeof performance !== "undefined" ? performance.now() : Date.now(),
|
|
11765
|
+
frame: (cb) => {
|
|
11766
|
+
if (typeof requestAnimationFrame === "undefined") {
|
|
11767
|
+
const t = setTimeout(cb, 16);
|
|
11768
|
+
return () => clearTimeout(t);
|
|
11769
|
+
}
|
|
11770
|
+
const id = requestAnimationFrame(cb);
|
|
11771
|
+
return () => cancelAnimationFrame(id);
|
|
11772
|
+
}
|
|
11773
|
+
};
|
|
11774
|
+
var canvasEffectsPool = new EffectRendererPool({ maxRenderers: 6 });
|
|
11775
|
+
function draw(target, p) {
|
|
11776
|
+
const ctx = target.getContext("2d");
|
|
11777
|
+
if (!ctx || typeof ImageData === "undefined") return;
|
|
11778
|
+
ctx.putImageData(new ImageData(new Uint8ClampedArray(p.data), p.width, p.height), 0, 0);
|
|
11779
|
+
}
|
|
11780
|
+
function runCanvasNodeEffect(options) {
|
|
11781
|
+
const { provider, effect, target } = options;
|
|
11782
|
+
const clock = options.clock ?? defaultClock;
|
|
11783
|
+
const pool = options.pool ?? canvasEffectsPool;
|
|
11784
|
+
const size2 = { width: Math.max(1, Math.round(target.width)), height: Math.max(1, Math.round(target.height)) };
|
|
11785
|
+
const start = clock.now();
|
|
11786
|
+
let stopped = false;
|
|
11787
|
+
let cancel = () => {
|
|
11788
|
+
};
|
|
11789
|
+
const tick = () => {
|
|
11790
|
+
if (stopped) return;
|
|
11791
|
+
const time = options.animate === false || effect.playing === false ? 0 : clock.now() - start;
|
|
11792
|
+
pool.render(provider, effect.effect, size2, { time, values: effect.values }).then(
|
|
11793
|
+
(p) => {
|
|
11794
|
+
if (stopped) return;
|
|
11795
|
+
draw(target, p);
|
|
11796
|
+
if (options.animate !== false && effect.playing !== false) cancel = clock.frame(tick);
|
|
11797
|
+
},
|
|
11798
|
+
(e) => {
|
|
11799
|
+
if (!stopped) options.onError?.(e);
|
|
11800
|
+
}
|
|
11801
|
+
);
|
|
11802
|
+
};
|
|
11803
|
+
tick();
|
|
11804
|
+
return {
|
|
11805
|
+
stop() {
|
|
11806
|
+
stopped = true;
|
|
11807
|
+
cancel();
|
|
11808
|
+
}
|
|
11809
|
+
};
|
|
11810
|
+
}
|
|
11811
|
+
async function playCanvasSceneTransition(options) {
|
|
11812
|
+
const { provider, transition, from, to, target } = options;
|
|
11813
|
+
const clock = options.clock ?? defaultClock;
|
|
11814
|
+
const pool = options.pool ?? canvasEffectsPool;
|
|
11815
|
+
const duration = transition.duration ?? 600;
|
|
11816
|
+
const size2 = { width: from.width, height: from.height };
|
|
11817
|
+
const start = clock.now();
|
|
11818
|
+
for (; ; ) {
|
|
11819
|
+
const time = Math.min(duration, clock.now() - start);
|
|
11820
|
+
const p = await pool.render(provider, transition.effect, size2, { time, progress: time / duration, values: transition.values, inputs: { from, to } });
|
|
11821
|
+
draw(target, p);
|
|
11822
|
+
if (time >= duration) return;
|
|
11823
|
+
await new Promise((resolve) => clock.frame(resolve));
|
|
11824
|
+
}
|
|
11825
|
+
}
|
|
11826
|
+
async function captureCanvasView(element, size2) {
|
|
11827
|
+
const url = await rasterizeElement(element, { pixelWidth: size2.width, pixelHeight: size2.height, exclude: CAPTURE_OVERLAY_SELECTORS });
|
|
11828
|
+
const doc = element.ownerDocument;
|
|
11829
|
+
const image = new doc.defaultView.Image();
|
|
11830
|
+
await new Promise((resolve, reject) => {
|
|
11831
|
+
image.onload = () => resolve();
|
|
11832
|
+
image.onerror = () => reject(new Error("The canvas view could not be captured."));
|
|
11833
|
+
image.src = url;
|
|
11834
|
+
});
|
|
11835
|
+
const canvas = doc.createElement("canvas");
|
|
11836
|
+
canvas.width = size2.width;
|
|
11837
|
+
canvas.height = size2.height;
|
|
11838
|
+
const ctx = canvas.getContext("2d");
|
|
11839
|
+
if (!ctx) throw new Error("The canvas view could not be captured (no 2D canvas).");
|
|
11840
|
+
ctx.drawImage(image, 0, 0, size2.width, size2.height);
|
|
11841
|
+
const data = ctx.getImageData(0, 0, size2.width, size2.height).data;
|
|
11842
|
+
return { width: size2.width, height: size2.height, data };
|
|
11843
|
+
}
|
|
11844
|
+
async function transitionCanvasView(options) {
|
|
11845
|
+
const { element } = options;
|
|
11846
|
+
const clock = options.clock ?? defaultClock;
|
|
11847
|
+
const scale = options.scale ?? Math.min(1, typeof devicePixelRatio === "number" ? devicePixelRatio : 1);
|
|
11848
|
+
const size2 = { width: Math.max(1, Math.round(element.clientWidth * scale)), height: Math.max(1, Math.round(element.clientHeight * scale)) };
|
|
11849
|
+
let from;
|
|
11850
|
+
try {
|
|
11851
|
+
from = await captureCanvasView(element, size2);
|
|
11852
|
+
} catch {
|
|
11853
|
+
options.jump();
|
|
11854
|
+
return;
|
|
11855
|
+
}
|
|
11856
|
+
const overlay = element.ownerDocument.createElement("canvas");
|
|
11857
|
+
overlay.width = size2.width;
|
|
11858
|
+
overlay.height = size2.height;
|
|
11859
|
+
overlay.setAttribute("data-capture", "overlay");
|
|
11860
|
+
overlay.setAttribute("data-canvas-transition", options.transition.effect);
|
|
11861
|
+
Object.assign(overlay.style, { position: "absolute", inset: "0", width: "100%", height: "100%", pointerEvents: "none", zIndex: "1000" });
|
|
11862
|
+
overlay.getContext("2d")?.putImageData(new ImageData(new Uint8ClampedArray(from.data), size2.width, size2.height), 0, 0);
|
|
11863
|
+
if (getComputedStyle(element).position === "static") element.style.position = "relative";
|
|
11864
|
+
element.appendChild(overlay);
|
|
11865
|
+
try {
|
|
11866
|
+
options.jump();
|
|
11867
|
+
await new Promise((r) => clock.frame(() => clock.frame(r)));
|
|
11868
|
+
const to = await captureCanvasView(element, size2);
|
|
11869
|
+
await playCanvasSceneTransition({ provider: options.provider, transition: options.transition, from, to, target: overlay, clock });
|
|
11870
|
+
} catch {
|
|
11871
|
+
} finally {
|
|
11872
|
+
overlay.remove();
|
|
11873
|
+
}
|
|
11874
|
+
}
|
|
11875
|
+
|
|
11876
|
+
// src/canvas/effect-tools.ts
|
|
11877
|
+
var info = (e) => ({
|
|
11878
|
+
id: "effect",
|
|
11879
|
+
effect: e.effect,
|
|
11880
|
+
...e.name ? { name: e.name } : {},
|
|
11881
|
+
...e.provider ? { provider: e.provider } : {},
|
|
11882
|
+
role: e.mode === "fill" ? "fill" : "overlay",
|
|
11883
|
+
enabled: e.playing !== false,
|
|
11884
|
+
opacity: e.opacity ?? 1,
|
|
11885
|
+
values: { ...e.values }
|
|
11886
|
+
});
|
|
11887
|
+
function createCanvasEffectsToolProvider(controller, options = {}) {
|
|
11888
|
+
const readOnlyReason = () => {
|
|
11889
|
+
const ro = typeof options.readOnly === "function" ? options.readOnly() : options.readOnly;
|
|
11890
|
+
return ro ? typeof ro === "string" ? ro : "The canvas is read-only." : null;
|
|
11891
|
+
};
|
|
11892
|
+
const result = (nodeId, effect) => {
|
|
11893
|
+
const now = controller.list(nodeId)[0]?.effect;
|
|
11894
|
+
return { target: nodeId, effect: info(effect ?? now), effects: now ? [info(now)] : [] };
|
|
11895
|
+
};
|
|
11896
|
+
const once = (instance) => {
|
|
11897
|
+
if (instance !== "effect") throw new Error('A shape node has one effect, "effect".');
|
|
11898
|
+
};
|
|
11899
|
+
return createEffectToolProvider({
|
|
11900
|
+
id: options.id ?? "canvas-effects",
|
|
11901
|
+
namespace: options.namespace,
|
|
11902
|
+
target: { noun: "node", id: "A shape node id on the canvas (a node with data.shape)." },
|
|
11903
|
+
applyUses: ["generator", "overlay", "title", "interactive"],
|
|
11904
|
+
applyDetails: "Generators fill the shape (clipped to its outline); overlays, titles and interactive effects draw over the node's box (set_canvas_effect_mode switches). A node has one effect: this replaces it. enabled false holds the first frame; opacity mixes it. index does not apply.",
|
|
11905
|
+
provider: () => controller.effectsProvider,
|
|
11906
|
+
readOnlyReason,
|
|
11907
|
+
list: (target) => controller.list(target).map((e) => ({ target: e.nodeId, effects: [info(e.effect)] })),
|
|
11908
|
+
apply: async (target, effect, args) => {
|
|
11909
|
+
if (args.index !== void 0) throw new Error("index does not apply: a shape node has one effect.");
|
|
11910
|
+
const provider = controller.effectsProvider;
|
|
11911
|
+
const d = provider ? await provider.describe(effect) : null;
|
|
11912
|
+
const mode = d && !d.uses.includes("generator") ? "overlay" : "fill";
|
|
11913
|
+
const applied = await controller.applyNodeEffect(target, effect, { mode, values: args.values, opacity: args.opacity });
|
|
11914
|
+
if (args.enabled === false) await controller.updateNodeEffect(target, { playing: false });
|
|
11915
|
+
return result(target, args.enabled === false ? { ...applied, playing: false } : applied);
|
|
11916
|
+
},
|
|
11917
|
+
update: async (target, instance, changes) => {
|
|
11918
|
+
once(instance);
|
|
11919
|
+
if (changes.index !== void 0) throw new Error("index does not apply: a shape node has one effect.");
|
|
11920
|
+
const e = await controller.updateNodeEffect(target, { values: changes.values, opacity: changes.opacity, playing: changes.enabled });
|
|
11921
|
+
return result(target, e);
|
|
11922
|
+
},
|
|
11923
|
+
remove: async (target, instance) => {
|
|
11924
|
+
once(instance);
|
|
11925
|
+
const was = controller.removeNodeEffect(target);
|
|
11926
|
+
return { target, effect: info(was), effects: [] };
|
|
11927
|
+
},
|
|
11928
|
+
subscribe: options.subscribe ? (notify) => options.subscribe(notify) : (notify) => controller.effects.subscribe(() => notify()),
|
|
11929
|
+
extraTools: (ctx) => [
|
|
11930
|
+
{
|
|
11931
|
+
name: "set_canvas_effect_mode",
|
|
11932
|
+
title: "Set a node effect's mode",
|
|
11933
|
+
description: "Switches a shape node's effect between fill (paints the inside, clipped to the outline) and overlay (draws over the node's box). One undoable step. Returns the effect.",
|
|
11934
|
+
inputSchema: {
|
|
11935
|
+
type: "object",
|
|
11936
|
+
properties: {
|
|
11937
|
+
node: { type: "string", minLength: 1, description: "A shape node id from list_applied_effects." },
|
|
11938
|
+
mode: { type: "string", enum: ["fill", "overlay"], description: "fill or overlay." }
|
|
11939
|
+
},
|
|
11940
|
+
required: ["node", "mode"],
|
|
11941
|
+
additionalProperties: false
|
|
11942
|
+
},
|
|
11943
|
+
annotations: { title: "Set a node effect's mode", ...ctx.annotations.writeIdempotent },
|
|
11944
|
+
handler: async (args) => {
|
|
11945
|
+
ctx.requireProvider();
|
|
11946
|
+
return { node: args.node, effect: info(await controller.updateNodeEffect(args.node, { mode: args.mode })) };
|
|
11947
|
+
}
|
|
11948
|
+
},
|
|
11949
|
+
{
|
|
11950
|
+
name: "list_scene_transitions",
|
|
11951
|
+
title: "List scene transitions",
|
|
11952
|
+
description: "Lists the canvas Scenes in order with the transition effect played when moving to each (or null). Works without a provider.",
|
|
11953
|
+
inputSchema: { type: "object", properties: {}, additionalProperties: false },
|
|
11954
|
+
annotations: { title: "List scene transitions", ...ctx.annotations.read },
|
|
11955
|
+
handler: () => ({ scenes: controller.scenes().map((s) => ({ id: s.id, name: s.name, transition: s.transition ?? null })) })
|
|
11956
|
+
},
|
|
11957
|
+
{
|
|
11958
|
+
name: "set_scene_transition",
|
|
11959
|
+
title: "Set a scene transition",
|
|
11960
|
+
description: "Sets the provider transition effect (search_effects with use transition) played when the canvas moves to a scene: the view before and after are captured and the effect blends between them. effect null removes it. Returns the transition.",
|
|
11961
|
+
inputSchema: {
|
|
11962
|
+
type: "object",
|
|
11963
|
+
properties: {
|
|
11964
|
+
scene: { type: "string", minLength: 1, description: "A scene id from list_scene_transitions." },
|
|
11965
|
+
effect: { anyOf: [ctx.effectIdSchema(["transition"]), { type: "null" }], description: "A transition effect id from search_effects, or null to remove the transition." },
|
|
11966
|
+
values: ctx.valuesSchema("Control values over the effect's defaults"),
|
|
11967
|
+
duration: { type: "number", exclusiveMinimum: 0, description: "Length in ms (default: the effect's own, else 600)." }
|
|
11968
|
+
},
|
|
11969
|
+
required: ["scene", "effect"],
|
|
11970
|
+
additionalProperties: false
|
|
11971
|
+
},
|
|
11972
|
+
annotations: { title: "Set a scene transition", ...ctx.annotations.writeIdempotent },
|
|
11973
|
+
handler: async (args) => {
|
|
11974
|
+
if (args.effect !== null) ctx.requireProvider();
|
|
11975
|
+
return { scene: args.scene, transition: await controller.setSceneTransition(args.scene, args.effect, { values: args.values, duration: args.duration }) };
|
|
11976
|
+
}
|
|
11977
|
+
}
|
|
11978
|
+
]
|
|
11979
|
+
});
|
|
11980
|
+
}
|
|
11604
11981
|
export {
|
|
11605
11982
|
ANIMATABLE_PROPERTIES,
|
|
11606
11983
|
ANIMATION_DATA_KEY,
|
|
@@ -11615,6 +11992,7 @@ export {
|
|
|
11615
11992
|
CANVAS_CAPTURE_OVERLAY_SELECTORS,
|
|
11616
11993
|
CANVAS_CAPTURE_VIEWPORT_SELECTOR,
|
|
11617
11994
|
CANVAS_COMPONENT_DRAG_TYPE,
|
|
11995
|
+
CANVAS_EFFECT_PLACES,
|
|
11618
11996
|
CANVAS_GRADIENT_PRESETS,
|
|
11619
11997
|
CANVAS_TOKEN_PROPERTIES,
|
|
11620
11998
|
CARD_INSPECTION_ZONES,
|
|
@@ -11697,8 +12075,11 @@ export {
|
|
|
11697
12075
|
canCombineShapeNodes,
|
|
11698
12076
|
canOffsetShapeNodes,
|
|
11699
12077
|
canOutlineShapeNodeStrokes,
|
|
12078
|
+
canvasEffectsPool,
|
|
11700
12079
|
canvasHeight,
|
|
11701
12080
|
canvasNodeCaptureRect,
|
|
12081
|
+
canvasNodeEffect,
|
|
12082
|
+
captureCanvasView,
|
|
11702
12083
|
centerNodes,
|
|
11703
12084
|
centre,
|
|
11704
12085
|
clampAnimationValue,
|
|
@@ -11728,6 +12109,8 @@ export {
|
|
|
11728
12109
|
createCanvasComponent,
|
|
11729
12110
|
createCanvasComponentsController,
|
|
11730
12111
|
createCanvasDrawController,
|
|
12112
|
+
createCanvasEffectsController,
|
|
12113
|
+
createCanvasEffectsToolProvider,
|
|
11731
12114
|
createCanvasInstance,
|
|
11732
12115
|
createCanvasScenesStore,
|
|
11733
12116
|
createDefaultStrokeStyle,
|
|
@@ -11964,6 +12347,7 @@ export {
|
|
|
11964
12347
|
pieScene,
|
|
11965
12348
|
placeBeside,
|
|
11966
12349
|
planarSplit,
|
|
12350
|
+
playCanvasSceneTransition,
|
|
11967
12351
|
playWebAnimations,
|
|
11968
12352
|
pointInBezierPath,
|
|
11969
12353
|
pointInMultiPolygon,
|
|
@@ -12009,6 +12393,7 @@ export {
|
|
|
12009
12393
|
revertShapeCombination,
|
|
12010
12394
|
rgbToOklab,
|
|
12011
12395
|
ringSignedArea,
|
|
12396
|
+
runCanvasNodeEffect,
|
|
12012
12397
|
runMultiNodeTransition,
|
|
12013
12398
|
sampleAnimationFrames,
|
|
12014
12399
|
scaleKeyframes,
|
|
@@ -12067,6 +12452,7 @@ export {
|
|
|
12067
12452
|
toWebAnimations,
|
|
12068
12453
|
toggleLockNodes,
|
|
12069
12454
|
transformBezierPath,
|
|
12455
|
+
transitionCanvasView,
|
|
12070
12456
|
trimSegments,
|
|
12071
12457
|
unionPolygons,
|
|
12072
12458
|
unitePaths,
|