@pixerate/editor 0.233.0 → 0.235.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/controller.d.cts +25 -0
- package/dist/animation-editor/controller.d.ts +25 -0
- package/dist/animation-editor/index.cjs +159 -50
- package/dist/animation-editor/index.d.cts +1 -0
- package/dist/animation-editor/index.d.ts +1 -0
- package/dist/animation-editor/index.js +115 -6
- package/dist/animation-editor/layers.d.cts +2 -0
- package/dist/animation-editor/layers.d.ts +2 -0
- package/dist/animation-editor/sequence.d.cts +33 -0
- package/dist/animation-editor/sequence.d.ts +33 -0
- package/dist/canvas/editorDocument.d.cts +49 -4
- package/dist/canvas/editorDocument.d.ts +49 -4
- package/dist/canvas/index.cjs +47 -20
- package/dist/canvas/index.js +40 -13
- package/dist/{chunk-I277KJLQ.js → chunk-G3RUKJ5C.js} +105 -1
- package/dist/{chunk-6RZVFYGJ.cjs → chunk-JWCKJNDR.cjs} +105 -1
- package/dist/effects/index.cjs +19 -11
- package/dist/effects/index.d.cts +1 -0
- package/dist/effects/index.d.ts +1 -0
- package/dist/effects/index.js +9 -1
- package/dist/effects/template-tools.d.cts +25 -0
- package/dist/effects/template-tools.d.ts +25 -0
- package/dist/effects/templates.d.cts +30 -1
- package/dist/effects/templates.d.ts +30 -1
- package/dist/video-editor/controller.d.cts +26 -0
- package/dist/video-editor/controller.d.ts +26 -0
- package/dist/video-editor/index.cjs +187 -42
- package/dist/video-editor/index.d.cts +1 -0
- package/dist/video-editor/index.d.ts +1 -0
- package/dist/video-editor/index.js +145 -0
- package/dist/video-editor/sequence.d.cts +38 -0
- package/dist/video-editor/sequence.d.ts +38 -0
- 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
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
effectLayerInput,
|
|
3
|
-
effectLayerOffered,
|
|
4
|
-
effectLayerRole,
|
|
5
|
-
effectSubjectKind
|
|
6
|
-
} from "../chunk-I277KJLQ.js";
|
|
7
1
|
import {
|
|
8
2
|
createVectorMorph
|
|
9
3
|
} from "../chunk-YMREOA67.js";
|
|
@@ -15,6 +9,14 @@ import {
|
|
|
15
9
|
namedWithSuggestion,
|
|
16
10
|
suggestName
|
|
17
11
|
} from "../chunk-EUKY4KFX.js";
|
|
12
|
+
import {
|
|
13
|
+
effectLayerInput,
|
|
14
|
+
effectLayerOffered,
|
|
15
|
+
effectLayerRole,
|
|
16
|
+
effectSubjectKind,
|
|
17
|
+
effectTemplateTools,
|
|
18
|
+
fillEffectTemplate
|
|
19
|
+
} from "../chunk-G3RUKJ5C.js";
|
|
18
20
|
import {
|
|
19
21
|
IDENTITY_MATRIX,
|
|
20
22
|
applyMatrix,
|
|
@@ -1802,7 +1804,10 @@ var MotionLayersEngine = class {
|
|
|
1802
1804
|
this.reset();
|
|
1803
1805
|
this.listeners.clear();
|
|
1804
1806
|
}
|
|
1807
|
+
/** Goes up each time pictures come in or are cleared, so a view that caches frames knows to draw again. */
|
|
1808
|
+
revision = 0;
|
|
1805
1809
|
notify() {
|
|
1810
|
+
this.revision++;
|
|
1806
1811
|
this.listeners.forEach((l) => l());
|
|
1807
1812
|
}
|
|
1808
1813
|
size(b) {
|
|
@@ -4484,6 +4489,57 @@ async function checkMotionShotLayers(scene, provider) {
|
|
|
4484
4489
|
return issues;
|
|
4485
4490
|
}
|
|
4486
4491
|
|
|
4492
|
+
// src/animation-editor/sequence.ts
|
|
4493
|
+
var fresh = (used, base) => {
|
|
4494
|
+
const clean = base.replace(/[^\w.-]+/g, "-").replace(/^[^A-Za-z_]+/, "") || "item";
|
|
4495
|
+
if (!used.has(clean)) return used.add(clean), clean;
|
|
4496
|
+
for (let i = 2; ; i++) if (!used.has(`${clean}-${i}`)) return used.add(`${clean}-${i}`), `${clean}-${i}`;
|
|
4497
|
+
};
|
|
4498
|
+
function motionShotsFromSequence(sequence, options = {}) {
|
|
4499
|
+
const sx = (options.width ?? sequence.stage.width) / sequence.stage.width;
|
|
4500
|
+
const sy = (options.height ?? sequence.stage.height) / sequence.stage.height;
|
|
4501
|
+
const scale = (r) => ({ x: r.x * sx, y: r.y * sy, width: r.width * sx, height: r.height * sy });
|
|
4502
|
+
const full = { x: 0, y: 0, width: sequence.stage.width * sx, height: sequence.stage.height * sy };
|
|
4503
|
+
const shotIds = new Set(options.shotIds ?? []);
|
|
4504
|
+
const layerIds = new Set(options.layerIds ?? []);
|
|
4505
|
+
const notes = [];
|
|
4506
|
+
const provider = options.provider ? { provider: options.provider } : {};
|
|
4507
|
+
const shots = sequence.shots.map((s, i) => {
|
|
4508
|
+
const id = fresh(shotIds, `shot${i + 1}`);
|
|
4509
|
+
const framing = s.camera?.framing ? scale(s.camera.framing) : void 0;
|
|
4510
|
+
const view = framing ?? full;
|
|
4511
|
+
const layers = [];
|
|
4512
|
+
for (const layer of s.layers) {
|
|
4513
|
+
if (layer.subject && "video" in layer.subject) {
|
|
4514
|
+
notes.push(`Shot ${i + 1}: a layer plays a video, which an animation cannot; it was left out (the video editor plays it).`);
|
|
4515
|
+
continue;
|
|
4516
|
+
}
|
|
4517
|
+
const { id: given, rect, subject, ...rest } = layer;
|
|
4518
|
+
layers.push({ ...rest, id: fresh(layerIds, given ?? "layer"), ...subject ? { subject } : {}, ...rect ? { rect: scale(rect) } : {}, ...layer.effect ? provider : {} });
|
|
4519
|
+
}
|
|
4520
|
+
if (s.title) layers.push({ id: fresh(layerIds, `${id}-title`), subject: { text: s.title }, role: "overlay", rect: { x: view.x + view.width * 0.1, y: view.y + view.height * 0.38, width: view.width * 0.8, height: view.height * 0.24 } });
|
|
4521
|
+
if (s.caption) layers.push({ id: fresh(layerIds, `${id}-caption`), subject: { text: s.caption }, role: "overlay", rect: { x: view.x + view.width * 0.1, y: view.y + view.height * 0.8, width: view.width * 0.8, height: view.height * 0.1 } });
|
|
4522
|
+
const camera = framing || s.camera?.in !== void 0 || s.camera?.during !== void 0 ? { ...framing ?? {}, ...s.camera?.in !== void 0 ? { in: s.camera.in } : {}, ...s.camera?.during !== void 0 ? { during: s.camera.during } : {} } : void 0;
|
|
4523
|
+
return {
|
|
4524
|
+
id,
|
|
4525
|
+
label: s.title ?? s.caption ?? `Shot ${i + 1}`,
|
|
4526
|
+
...camera ? { camera } : {},
|
|
4527
|
+
run: [],
|
|
4528
|
+
hold: s.hold,
|
|
4529
|
+
...layers.length ? { layers } : {},
|
|
4530
|
+
...i > 0 && s.transition ? { transition: { ...s.transition, ...provider } } : {}
|
|
4531
|
+
};
|
|
4532
|
+
});
|
|
4533
|
+
return { shots, notes };
|
|
4534
|
+
}
|
|
4535
|
+
function motionSceneFromSequence(sequence, options = {}) {
|
|
4536
|
+
const { shots, notes } = motionShotsFromSequence(sequence, options);
|
|
4537
|
+
return {
|
|
4538
|
+
scene: { version: 1, name: sequence.name, ...sequence.title ? { description: sequence.title } : {}, artwork: { width: sequence.stage.width, height: sequence.stage.height, background: options.background ?? "#000000", nodes: [] }, shots },
|
|
4539
|
+
notes
|
|
4540
|
+
};
|
|
4541
|
+
}
|
|
4542
|
+
|
|
4487
4543
|
// src/animation-editor/effects.ts
|
|
4488
4544
|
var sourceOf = (c) => c.source;
|
|
4489
4545
|
function motionSceneEffects(scene) {
|
|
@@ -4667,6 +4723,7 @@ var AnimationEditorController = class {
|
|
|
4667
4723
|
redoLabel: h.redoName,
|
|
4668
4724
|
revision: this.revision,
|
|
4669
4725
|
effectsProvider: this.effects.provider,
|
|
4726
|
+
layerPictures: this.layers.revision,
|
|
4670
4727
|
recording: this.recording ? {
|
|
4671
4728
|
shot: this.recording.options.id,
|
|
4672
4729
|
at: this.recording.options.at,
|
|
@@ -5175,6 +5232,42 @@ var AnimationEditorController = class {
|
|
|
5175
5232
|
if (!r.ok) return r;
|
|
5176
5233
|
return this.layerResult(shot, void 0);
|
|
5177
5234
|
}
|
|
5235
|
+
/**
|
|
5236
|
+
* Fills a provider sequence template and loads it: `replace` (default) makes a new scene the
|
|
5237
|
+
* size of the template's stage from its shots; `append` adds its shots after the current ones,
|
|
5238
|
+
* scaled to the artwork. Values are checked first and every problem is refused at once. One
|
|
5239
|
+
* undo step. Returns the new shot and layer ids, slots left open and notes.
|
|
5240
|
+
*/
|
|
5241
|
+
async fillTemplate(template, values = {}, options = {}) {
|
|
5242
|
+
const reason = this.readOnlyReason();
|
|
5243
|
+
if (reason) return this.refuse(reason);
|
|
5244
|
+
const mode = options.mode ?? "replace";
|
|
5245
|
+
let filled;
|
|
5246
|
+
try {
|
|
5247
|
+
filled = await fillEffectTemplate(this.effects.provider, template, values, options.name ? { name: options.name } : {});
|
|
5248
|
+
} catch (error) {
|
|
5249
|
+
if (isEffectError(error) || error instanceof Error) return this.refuse(error.message);
|
|
5250
|
+
throw error;
|
|
5251
|
+
}
|
|
5252
|
+
const provider = this.effects.provider.id;
|
|
5253
|
+
const label = `Template ${filled.template.name}`;
|
|
5254
|
+
let shots;
|
|
5255
|
+
let notes;
|
|
5256
|
+
let r;
|
|
5257
|
+
if (mode === "replace") {
|
|
5258
|
+
const made = motionSceneFromSequence(filled.sequence, { provider });
|
|
5259
|
+
shots = made.scene.shots;
|
|
5260
|
+
notes = made.notes;
|
|
5261
|
+
r = this.apply({ op: "replace_scene", scene: made.scene }, label);
|
|
5262
|
+
} else {
|
|
5263
|
+
const made = motionShotsFromSequence(filled.sequence, { provider, width: this.scene.artwork.width, height: this.scene.artwork.height, shotIds: this.scene.shots.map((s) => s.id), layerIds: this.scene.shots.flatMap((s) => (s.layers ?? []).map((l) => l.id)) });
|
|
5264
|
+
shots = made.shots;
|
|
5265
|
+
notes = made.notes;
|
|
5266
|
+
r = this.apply({ op: "insert_shots", shots: made.shots }, label);
|
|
5267
|
+
}
|
|
5268
|
+
if (!r.ok) return r;
|
|
5269
|
+
return { ok: true, template, mode, shots: shots.map((s) => s.id), layers: shots.flatMap((s) => (s.layers ?? []).map((l) => l.id)), openSlots: filled.openSlots, notes: [...filled.notes, ...notes] };
|
|
5270
|
+
}
|
|
5178
5271
|
// ---------------------------------------------------------------------------------------
|
|
5179
5272
|
// Recording
|
|
5180
5273
|
// ---------------------------------------------------------------------------------------
|
|
@@ -7087,6 +7180,20 @@ function createAnimationEffectsToolProvider(controller, options = {}) {
|
|
|
7087
7180
|
extraTools: (ctx) => [
|
|
7088
7181
|
...animationCameraMoveTools(controller, ctx),
|
|
7089
7182
|
...animationShotLayerTools(controller, ctx),
|
|
7183
|
+
...effectTemplateTools(
|
|
7184
|
+
{
|
|
7185
|
+
provider: () => controller.effectsProvider,
|
|
7186
|
+
fillDetails: "mode replace (default) makes a new scene from the template's shots, the size of its stage; mode append adds its shots after the current ones, scaled to the artwork. Each shot keeps its framing and camera moves, its layers and its transition; its title and caption become overlay word layers. Returns { template, mode, shots (new shot ids), layers (new layer ids), openSlots, notes }. Check the result with render_animation_frame.",
|
|
7187
|
+
fillOptions: { mode: { type: "string", enum: ["replace", "append"], description: "replace (default): a new scene from the template; append: its shots after the current ones." } },
|
|
7188
|
+
fill: async (template, values, options2) => {
|
|
7189
|
+
const r = await controller.fillTemplate(template, values, { name: options2.name, mode: options2.mode });
|
|
7190
|
+
if (!r.ok) throw new Error(r.error);
|
|
7191
|
+
const { ok: _ok, ...rest } = r;
|
|
7192
|
+
return rest;
|
|
7193
|
+
}
|
|
7194
|
+
},
|
|
7195
|
+
ctx
|
|
7196
|
+
),
|
|
7090
7197
|
{
|
|
7091
7198
|
name: "add_vector_effect",
|
|
7092
7199
|
title: "Add a vector effect",
|
|
@@ -7296,6 +7403,7 @@ export {
|
|
|
7296
7403
|
motionRevealPadding,
|
|
7297
7404
|
motionRulerTicks,
|
|
7298
7405
|
motionSceneEffects,
|
|
7406
|
+
motionSceneFromSequence,
|
|
7299
7407
|
motionSceneHasLayers,
|
|
7300
7408
|
motionSceneShapeProblems,
|
|
7301
7409
|
motionSceneToJson,
|
|
@@ -7304,6 +7412,7 @@ export {
|
|
|
7304
7412
|
motionShotCueTime,
|
|
7305
7413
|
motionShotLayersInfo,
|
|
7306
7414
|
motionShotTimeScale,
|
|
7415
|
+
motionShotsFromSequence,
|
|
7307
7416
|
motionStageSvg,
|
|
7308
7417
|
motionTakeProblems,
|
|
7309
7418
|
motionTakeShot,
|
|
@@ -144,6 +144,8 @@ export declare class MotionLayersEngine implements MotionLayerPictures {
|
|
|
144
144
|
/** Forgets every picture and failure (a new provider, or the host changed). */
|
|
145
145
|
reset(): void;
|
|
146
146
|
dispose(): void;
|
|
147
|
+
/** Goes up each time pictures come in or are cleared, so a view that caches frames knows to draw again. */
|
|
148
|
+
revision: number;
|
|
147
149
|
private notify;
|
|
148
150
|
private size;
|
|
149
151
|
private snap;
|
|
@@ -144,6 +144,8 @@ export declare class MotionLayersEngine implements MotionLayerPictures {
|
|
|
144
144
|
/** Forgets every picture and failure (a new provider, or the host changed). */
|
|
145
145
|
reset(): void;
|
|
146
146
|
dispose(): void;
|
|
147
|
+
/** Goes up each time pictures come in or are cleared, so a view that caches frames knows to draw again. */
|
|
148
|
+
revision: number;
|
|
147
149
|
private notify;
|
|
148
150
|
private size;
|
|
149
151
|
private snap;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An effects provider's `EffectSequence` (what a sequence template fills to) as animation shots:
|
|
3
|
+
* each shot keeps its framing and camera moves, its layers and its transition. Its title and
|
|
4
|
+
* caption become overlay word layers placed in the shot's framing. Rects and framings are scaled
|
|
5
|
+
* from the sequence's stage to the artwork.
|
|
6
|
+
*/
|
|
7
|
+
import type { EffectSequence } from '../effects/types.cjs';
|
|
8
|
+
import type { MotionScene, MotionShot } from './types.cjs';
|
|
9
|
+
export interface MotionShotsFromSequence {
|
|
10
|
+
shots: MotionShot[];
|
|
11
|
+
/** What could not be carried over, in sentences. */
|
|
12
|
+
notes: string[];
|
|
13
|
+
}
|
|
14
|
+
export interface MotionSequenceOptions {
|
|
15
|
+
/** The artwork size the shots are for (default the sequence's stage). */
|
|
16
|
+
width?: number;
|
|
17
|
+
height?: number;
|
|
18
|
+
/** Shot ids already used (new ones avoid them). */
|
|
19
|
+
shotIds?: Iterable<string>;
|
|
20
|
+
/** Layer ids already used (new ones avoid them). */
|
|
21
|
+
layerIds?: Iterable<string>;
|
|
22
|
+
/** The provider the sequence's effects come from, saved on layers and transitions. */
|
|
23
|
+
provider?: string;
|
|
24
|
+
}
|
|
25
|
+
/** The shots of a sequence, sized for the artwork (see the module comment). */
|
|
26
|
+
export declare function motionShotsFromSequence(sequence: EffectSequence, options?: MotionSequenceOptions): MotionShotsFromSequence;
|
|
27
|
+
/** A new scene from a sequence: an empty artwork the size of its stage, and its shots. */
|
|
28
|
+
export declare function motionSceneFromSequence(sequence: EffectSequence, options?: Pick<MotionSequenceOptions, 'provider'> & {
|
|
29
|
+
background?: string;
|
|
30
|
+
}): {
|
|
31
|
+
scene: MotionScene;
|
|
32
|
+
notes: string[];
|
|
33
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An effects provider's `EffectSequence` (what a sequence template fills to) as animation shots:
|
|
3
|
+
* each shot keeps its framing and camera moves, its layers and its transition. Its title and
|
|
4
|
+
* caption become overlay word layers placed in the shot's framing. Rects and framings are scaled
|
|
5
|
+
* from the sequence's stage to the artwork.
|
|
6
|
+
*/
|
|
7
|
+
import type { EffectSequence } from '../effects/types.js';
|
|
8
|
+
import type { MotionScene, MotionShot } from './types.js';
|
|
9
|
+
export interface MotionShotsFromSequence {
|
|
10
|
+
shots: MotionShot[];
|
|
11
|
+
/** What could not be carried over, in sentences. */
|
|
12
|
+
notes: string[];
|
|
13
|
+
}
|
|
14
|
+
export interface MotionSequenceOptions {
|
|
15
|
+
/** The artwork size the shots are for (default the sequence's stage). */
|
|
16
|
+
width?: number;
|
|
17
|
+
height?: number;
|
|
18
|
+
/** Shot ids already used (new ones avoid them). */
|
|
19
|
+
shotIds?: Iterable<string>;
|
|
20
|
+
/** Layer ids already used (new ones avoid them). */
|
|
21
|
+
layerIds?: Iterable<string>;
|
|
22
|
+
/** The provider the sequence's effects come from, saved on layers and transitions. */
|
|
23
|
+
provider?: string;
|
|
24
|
+
}
|
|
25
|
+
/** The shots of a sequence, sized for the artwork (see the module comment). */
|
|
26
|
+
export declare function motionShotsFromSequence(sequence: EffectSequence, options?: MotionSequenceOptions): MotionShotsFromSequence;
|
|
27
|
+
/** A new scene from a sequence: an empty artwork the size of its stage, and its shots. */
|
|
28
|
+
export declare function motionSceneFromSequence(sequence: EffectSequence, options?: Pick<MotionSequenceOptions, 'provider'> & {
|
|
29
|
+
background?: string;
|
|
30
|
+
}): {
|
|
31
|
+
scene: MotionScene;
|
|
32
|
+
notes: string[];
|
|
33
|
+
};
|
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
import type { HistoryManager } from '../history/HistoryManager.cjs';
|
|
2
|
+
import type { EditorAssetRegistry } from '../persistence/assets.cjs';
|
|
2
3
|
import { type EditorDocument } from '../persistence/editorDocument.cjs';
|
|
3
|
-
import type { CanvasScene, CanvasScenesStore } from './scenes.cjs';
|
|
4
|
+
import type { CanvasScene, CanvasScenesStore, CanvasViewport } from './scenes.cjs';
|
|
4
5
|
import type { CanvasEdge, CanvasNode } from './types.cjs';
|
|
5
6
|
/** What the document needs of an edge (React Flow's and Svelte Flow's edges fit). */
|
|
6
7
|
export type CanvasEdgeLike = Pick<CanvasEdge, 'id' | 'source' | 'target'> & {
|
|
7
8
|
selected?: boolean;
|
|
8
9
|
};
|
|
9
|
-
/** A canvas as it is saved: its nodes, edges
|
|
10
|
+
/** A canvas as it is saved: its nodes, edges, (with a scenes store) scenes and (with `getViewport`) the view. */
|
|
10
11
|
export interface CanvasEditorDocument<TNode extends CanvasNode = CanvasNode, TEdge extends CanvasEdgeLike = CanvasEdge> {
|
|
11
12
|
nodes: TNode[];
|
|
12
13
|
edges: TEdge[];
|
|
13
14
|
scenes?: CanvasScene[];
|
|
15
|
+
/** Where the canvas was looking when it was saved. */
|
|
16
|
+
viewport?: CanvasViewport;
|
|
14
17
|
}
|
|
15
18
|
export interface CanvasEditorDocumentOptions<TNode extends CanvasNode = CanvasNode, TEdge extends CanvasEdgeLike = CanvasEdge> {
|
|
16
19
|
getNodes: () => TNode[];
|
|
@@ -28,12 +31,54 @@ export interface CanvasEditorDocumentOptions<TNode extends CanvasNode = CanvasNo
|
|
|
28
31
|
subscribe?: (listener: () => void) => () => void;
|
|
29
32
|
/** Why the canvas cannot be changed (a sentence), or `false`. */
|
|
30
33
|
readOnly?: () => string | false;
|
|
34
|
+
/**
|
|
35
|
+
* The view saved with the document and restored on load. Panning and zooming are not
|
|
36
|
+
* document changes: they do not bump the revision, so they alone do not trigger a save.
|
|
37
|
+
*/
|
|
38
|
+
getViewport?: () => CanvasViewport;
|
|
39
|
+
setViewport?: (viewport: CanvasViewport) => void;
|
|
40
|
+
/** Node fields left out of the document, besides `selected`, `dragging`, `measured` and `resizing`. */
|
|
41
|
+
omitNodeKeys?: readonly string[];
|
|
42
|
+
/** Edge fields left out of the document, besides `selected`. */
|
|
43
|
+
omitEdgeKeys?: readonly string[];
|
|
44
|
+
/**
|
|
45
|
+
* Checks a node of a document being loaded, after the built-in checks. Return what is wrong
|
|
46
|
+
* (a sentence) to refuse the whole load, or nothing to accept the node.
|
|
47
|
+
*/
|
|
48
|
+
validateNode?: (node: TNode, index: number) => string | void;
|
|
49
|
+
/**
|
|
50
|
+
* Turns any document handed to `loadDocument` (a raw one or a migrated file) into the current
|
|
51
|
+
* shape before it is checked, e.g. an older layout the host stored without a file envelope.
|
|
52
|
+
*/
|
|
53
|
+
normalize?: (document: unknown) => unknown;
|
|
54
|
+
/** The host's format version of the document (default 1); files with an older one are migrated. */
|
|
55
|
+
formatVersion?: number;
|
|
56
|
+
/** `migrations[v]` turns a version `v` file's document into version `v + 1`. Only files carry a version. */
|
|
57
|
+
migrations?: Record<number, (document: unknown) => unknown>;
|
|
58
|
+
/**
|
|
59
|
+
* Keeps inline binary data in node and edge data (image data URLs, long base64) out of the
|
|
60
|
+
* document as asset references; autosave and the document store save the bytes with it.
|
|
61
|
+
*/
|
|
62
|
+
assets?: EditorAssetRegistry;
|
|
63
|
+
}
|
|
64
|
+
/** What to leave out of canvas nodes and edges: the runtime fields plus the host's own. */
|
|
65
|
+
export interface CanvasDocumentOmitOptions {
|
|
66
|
+
omitNodeKeys?: readonly string[];
|
|
67
|
+
omitEdgeKeys?: readonly string[];
|
|
31
68
|
}
|
|
69
|
+
/**
|
|
70
|
+
* A string that changes only when the saved part of the nodes or edges changes (not selection,
|
|
71
|
+
* measuring or the omitted fields). The React and Svelte document bindings compare it to count
|
|
72
|
+
* changes the history does not see.
|
|
73
|
+
*/
|
|
74
|
+
export declare function canvasDocumentContentKey(nodes: readonly CanvasNode[], edges: readonly CanvasEdgeLike[], options?: CanvasDocumentOmitOptions): string;
|
|
32
75
|
/**
|
|
33
76
|
* The save / load / undo contract for a canvas whose nodes and edges live in the host (React
|
|
34
77
|
* Flow or Svelte Flow state), kind `canvas`. The document is the nodes and edges without
|
|
35
|
-
* selection or
|
|
36
|
-
*
|
|
78
|
+
* selection, measurement or `omitNodeKeys` / `omitEdgeKeys`, plus the scenes when a store is
|
|
79
|
+
* given and the viewport with `getViewport`. Loads are normalized, then checked (built-in
|
|
80
|
+
* checks, then `validateNode`) before anything changes. Recorded loads are one undo step in the
|
|
81
|
+
* shared `history`; opening (`history: "reset"`) clears it.
|
|
37
82
|
*/
|
|
38
83
|
export declare function createCanvasEditorDocument<TNode extends CanvasNode = CanvasNode, TEdge extends CanvasEdgeLike = CanvasEdge>(options: CanvasEditorDocumentOptions<TNode, TEdge>): EditorDocument<CanvasEditorDocument<TNode, TEdge>>;
|
|
39
84
|
export interface CanvasGestureRecorderOptions<TNode extends CanvasNode = CanvasNode, TEdge extends CanvasEdgeLike = CanvasEdge> {
|
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
import type { HistoryManager } from '../history/HistoryManager.js';
|
|
2
|
+
import type { EditorAssetRegistry } from '../persistence/assets.js';
|
|
2
3
|
import { type EditorDocument } from '../persistence/editorDocument.js';
|
|
3
|
-
import type { CanvasScene, CanvasScenesStore } from './scenes.js';
|
|
4
|
+
import type { CanvasScene, CanvasScenesStore, CanvasViewport } from './scenes.js';
|
|
4
5
|
import type { CanvasEdge, CanvasNode } from './types.js';
|
|
5
6
|
/** What the document needs of an edge (React Flow's and Svelte Flow's edges fit). */
|
|
6
7
|
export type CanvasEdgeLike = Pick<CanvasEdge, 'id' | 'source' | 'target'> & {
|
|
7
8
|
selected?: boolean;
|
|
8
9
|
};
|
|
9
|
-
/** A canvas as it is saved: its nodes, edges
|
|
10
|
+
/** A canvas as it is saved: its nodes, edges, (with a scenes store) scenes and (with `getViewport`) the view. */
|
|
10
11
|
export interface CanvasEditorDocument<TNode extends CanvasNode = CanvasNode, TEdge extends CanvasEdgeLike = CanvasEdge> {
|
|
11
12
|
nodes: TNode[];
|
|
12
13
|
edges: TEdge[];
|
|
13
14
|
scenes?: CanvasScene[];
|
|
15
|
+
/** Where the canvas was looking when it was saved. */
|
|
16
|
+
viewport?: CanvasViewport;
|
|
14
17
|
}
|
|
15
18
|
export interface CanvasEditorDocumentOptions<TNode extends CanvasNode = CanvasNode, TEdge extends CanvasEdgeLike = CanvasEdge> {
|
|
16
19
|
getNodes: () => TNode[];
|
|
@@ -28,12 +31,54 @@ export interface CanvasEditorDocumentOptions<TNode extends CanvasNode = CanvasNo
|
|
|
28
31
|
subscribe?: (listener: () => void) => () => void;
|
|
29
32
|
/** Why the canvas cannot be changed (a sentence), or `false`. */
|
|
30
33
|
readOnly?: () => string | false;
|
|
34
|
+
/**
|
|
35
|
+
* The view saved with the document and restored on load. Panning and zooming are not
|
|
36
|
+
* document changes: they do not bump the revision, so they alone do not trigger a save.
|
|
37
|
+
*/
|
|
38
|
+
getViewport?: () => CanvasViewport;
|
|
39
|
+
setViewport?: (viewport: CanvasViewport) => void;
|
|
40
|
+
/** Node fields left out of the document, besides `selected`, `dragging`, `measured` and `resizing`. */
|
|
41
|
+
omitNodeKeys?: readonly string[];
|
|
42
|
+
/** Edge fields left out of the document, besides `selected`. */
|
|
43
|
+
omitEdgeKeys?: readonly string[];
|
|
44
|
+
/**
|
|
45
|
+
* Checks a node of a document being loaded, after the built-in checks. Return what is wrong
|
|
46
|
+
* (a sentence) to refuse the whole load, or nothing to accept the node.
|
|
47
|
+
*/
|
|
48
|
+
validateNode?: (node: TNode, index: number) => string | void;
|
|
49
|
+
/**
|
|
50
|
+
* Turns any document handed to `loadDocument` (a raw one or a migrated file) into the current
|
|
51
|
+
* shape before it is checked, e.g. an older layout the host stored without a file envelope.
|
|
52
|
+
*/
|
|
53
|
+
normalize?: (document: unknown) => unknown;
|
|
54
|
+
/** The host's format version of the document (default 1); files with an older one are migrated. */
|
|
55
|
+
formatVersion?: number;
|
|
56
|
+
/** `migrations[v]` turns a version `v` file's document into version `v + 1`. Only files carry a version. */
|
|
57
|
+
migrations?: Record<number, (document: unknown) => unknown>;
|
|
58
|
+
/**
|
|
59
|
+
* Keeps inline binary data in node and edge data (image data URLs, long base64) out of the
|
|
60
|
+
* document as asset references; autosave and the document store save the bytes with it.
|
|
61
|
+
*/
|
|
62
|
+
assets?: EditorAssetRegistry;
|
|
63
|
+
}
|
|
64
|
+
/** What to leave out of canvas nodes and edges: the runtime fields plus the host's own. */
|
|
65
|
+
export interface CanvasDocumentOmitOptions {
|
|
66
|
+
omitNodeKeys?: readonly string[];
|
|
67
|
+
omitEdgeKeys?: readonly string[];
|
|
31
68
|
}
|
|
69
|
+
/**
|
|
70
|
+
* A string that changes only when the saved part of the nodes or edges changes (not selection,
|
|
71
|
+
* measuring or the omitted fields). The React and Svelte document bindings compare it to count
|
|
72
|
+
* changes the history does not see.
|
|
73
|
+
*/
|
|
74
|
+
export declare function canvasDocumentContentKey(nodes: readonly CanvasNode[], edges: readonly CanvasEdgeLike[], options?: CanvasDocumentOmitOptions): string;
|
|
32
75
|
/**
|
|
33
76
|
* The save / load / undo contract for a canvas whose nodes and edges live in the host (React
|
|
34
77
|
* Flow or Svelte Flow state), kind `canvas`. The document is the nodes and edges without
|
|
35
|
-
* selection or
|
|
36
|
-
*
|
|
78
|
+
* selection, measurement or `omitNodeKeys` / `omitEdgeKeys`, plus the scenes when a store is
|
|
79
|
+
* given and the viewport with `getViewport`. Loads are normalized, then checked (built-in
|
|
80
|
+
* checks, then `validateNode`) before anything changes. Recorded loads are one undo step in the
|
|
81
|
+
* shared `history`; opening (`history: "reset"`) clears it.
|
|
37
82
|
*/
|
|
38
83
|
export declare function createCanvasEditorDocument<TNode extends CanvasNode = CanvasNode, TEdge extends CanvasEdgeLike = CanvasEdge>(options: CanvasEditorDocumentOptions<TNode, TEdge>): EditorDocument<CanvasEditorDocument<TNode, TEdge>>;
|
|
39
84
|
export interface CanvasGestureRecorderOptions<TNode extends CanvasNode = CanvasNode, TEdge extends CanvasEdgeLike = CanvasEdge> {
|