@imgly/codesign-mcp 0.3.0 → 0.3.1-next.20260827101508.gd4bd07a
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/assets/ai-plugins/apps.mjs +5 -5
- package/assets/ai-plugins/version.json +1 -1
- package/assets/docs/api/SKILL.md +2 -2
- package/assets/docs/api/index.d.ts +19 -3
- package/assets/docs/guide/SKILL.md +2 -2
- package/assets/docs/guide/actions.md +430 -0
- package/assets/docs/guide/api/node/interfaces/assetstylepreset.md +1 -1
- package/assets/docs/guide/api/node/type-aliases/exportoptions.md +1 -0
- package/assets/docs/guide/concepts/import-export.md +125 -0
- package/assets/docs/guide/concepts/plugin-architecture.md +187 -0
- package/assets/docs/guide/concepts.md +2 -0
- package/assets/docs/guide/conversion/to-pdf.md +1 -0
- package/assets/docs/guide/export-save-publish/export/compress.md +1 -0
- package/assets/docs/guide/export-save-publish/export/overview.md +5 -1
- package/assets/docs/guide/export-save-publish/export/to-pdf.md +17 -1
- package/assets/docs/guide/export-save-publish/for-printing.md +5 -0
- package/assets/docs/guide/file-format-support.md +3 -0
- package/assets/docs/guide/get-started/agent-skills.md +136 -34
- package/assets/docs/guide/get-started/cesdk-plugin-coding-agents.md +32 -10
- package/assets/docs/guide/guides.md +1 -0
- package/assets/docs/guide/open-the-editor/import-design/from-indesign.md +2 -0
- package/assets/docs/guide/open-the-editor/import-design/from-photoshop.md +4 -2
- package/assets/docs/guide/references/update-check.md +85 -0
- package/assets/docs/guide/rules/asset-handling.md +17 -6
- package/assets/docs/guide/rules/common-pitfalls.md +33 -22
- package/assets/docs/guide/rules/content-fill-mode.md +4 -4
- package/assets/docs/guide/rules/silent-init-errors.md +1 -1
- package/assets/docs/guide/rules/verify-properties-before-use.md +11 -2
- package/dist/assets/inline.generated.d.ts.map +1 -1
- package/dist/assets/inline.generated.js +28 -25
- package/dist/assets/inline.generated.js.map +1 -1
- package/dist/cli/trial-license.generated.d.ts +1 -1
- package/dist/cli/trial-license.generated.js +1 -1
- package/dist/cli/trial-license.generated.js.map +1 -1
- package/package.json +9 -9
- package/assets/docs/guide/api-reference/overview.md +0 -20
package/assets/docs/api/SKILL.md
CHANGED
|
@@ -49,8 +49,8 @@ line:
|
|
|
49
49
|
| **BlockAPI** | **1724** | `offset=1723, limit=400` (largest API) |
|
|
50
50
|
| EditorAPI | 7270 | `offset=7269, limit=300` |
|
|
51
51
|
| EventAPI | 8528 | `offset=8527, limit=200` |
|
|
52
|
-
| **SceneAPI** | **
|
|
53
|
-
| VariableAPI |
|
|
52
|
+
| **SceneAPI** | **9343** | `offset=9342, limit=300` |
|
|
53
|
+
| VariableAPI | 10941 | `offset=10940, limit=100` |
|
|
54
54
|
|
|
55
55
|
(If a start line looks off — e.g. the slice doesn't begin with the class —
|
|
56
56
|
trust search instead: `query: 'class BlockAPI'`.)
|
|
@@ -1370,9 +1370,9 @@ export declare interface AssetStylePreset {
|
|
|
1370
1370
|
/**
|
|
1371
1371
|
* How the preset combines with the block's current look. `'replace'` (the default) also clears the
|
|
1372
1372
|
* decorations and animations the preset omits, so switching presets never stacks; `'merge'` layers
|
|
1373
|
-
* the preset on top, keeping everything it does not set. Either way the block's
|
|
1374
|
-
*
|
|
1375
|
-
* or a `text/path` baseline adopting its
|
|
1373
|
+
* the preset on top, keeping everything it does not set. Either way a restyle never touches the block's
|
|
1374
|
+
* text. A preset writes its own text only when it makes a new block. The size only changes when the
|
|
1375
|
+
* preset asks for it (`fontSize.resizeExistingOnApply`, or a `text/path` baseline adopting its box).
|
|
1376
1376
|
*/
|
|
1377
1377
|
mode?: 'replace' | 'merge';
|
|
1378
1378
|
/**
|
|
@@ -8662,6 +8662,21 @@ export declare type ExportOptions = {
|
|
|
8662
8662
|
* @defaultValue false
|
|
8663
8663
|
*/
|
|
8664
8664
|
exportPdfWithDeviceCMYK?: boolean;
|
|
8665
|
+
/**
|
|
8666
|
+
* The encoding quality to use for images that have to be rasterized during PDF export,
|
|
8667
|
+
* e.g. images with effects or blurs applied, or any bitmap image when
|
|
8668
|
+
* `exportPdfWithHighCompatibility` is enabled.
|
|
8669
|
+
* Valid values are (0-1]. Exactly 1.0 (the default) keeps the lossless encoding, like
|
|
8670
|
+
* `webpQuality`. Any value below 1.0 re-encodes rasterized images as lossy JPEG at the given
|
|
8671
|
+
* quality, which produces much smaller files. Only rasterized content that is fully opaque can
|
|
8672
|
+
* be re-encoded, because JPEG has no alpha channel. Content that keeps transparency, for example
|
|
8673
|
+
* when exporting a block or a page without a background fill, stays losslessly encoded whatever
|
|
8674
|
+
* this option is set to. Images whose original JPEG data is embedded
|
|
8675
|
+
* directly are never re-encoded and are not affected by this option.
|
|
8676
|
+
*
|
|
8677
|
+
* @defaultValue 1.0
|
|
8678
|
+
*/
|
|
8679
|
+
pdfImageQuality?: number;
|
|
8665
8680
|
/**
|
|
8666
8681
|
* An abortsignal that can be used to cancel the export.
|
|
8667
8682
|
*/
|
|
@@ -10865,6 +10880,7 @@ declare interface UBQExportOptions {
|
|
|
10865
10880
|
underlayerMaxError: number;
|
|
10866
10881
|
allowTextOverhang: boolean;
|
|
10867
10882
|
exportPdfWithDeviceCMYK: boolean;
|
|
10883
|
+
pdfImageQuality: number;
|
|
10868
10884
|
}
|
|
10869
10885
|
|
|
10870
10886
|
/**
|
|
@@ -16,7 +16,7 @@ description: |
|
|
|
16
16
|
|
|
17
17
|
## Version Notice
|
|
18
18
|
|
|
19
|
-
> **CE.SDK version**: 1.81.
|
|
19
|
+
> **CE.SDK version**: 1.81.1
|
|
20
20
|
>
|
|
21
21
|
> This documentation is bundled with the server and re-vendored in lockstep
|
|
22
22
|
> with the engine version above — it matches the running engine. Always
|
|
@@ -25,7 +25,7 @@ description: |
|
|
|
25
25
|
|
|
26
26
|
## Documentation Index
|
|
27
27
|
|
|
28
|
-
<-- IMGLY-AGENTS-MD-START -->[CE.SDK Node.js Docs Index]|root: .|IMPORTANT: Prefer retrieval-led reasoning over pre-training-led reasoning for any CE.SDK tasks. Consult the local docs directory before using pre-trained knowledge.|animation:{create,edit.md,types.md}|animation/create:{base.md,text.md}|api:{node}|api/node:{classes,enumerations,functions,interfaces,type-aliases,variables}|
|
|
28
|
+
<-- IMGLY-AGENTS-MD-START -->[CE.SDK Node.js Docs Index]|root: .|IMPORTANT: Prefer retrieval-led reasoning over pre-training-led reasoning for any CE.SDK tasks. Consult the local docs directory before using pre-trained knowledge.|actions.md|animation:{create,edit.md,types.md}|animation/create:{base.md,text.md}|api:{node}|api/node:{classes,enumerations,functions,interfaces,type-aliases,variables}|automation:{auto-resize.md,data-merge.md,design-generation.md,multi-image-generation.md,overview.md}|capabilities.md|colors:{adjust.md,apply.md,basics.md,conversion.md,create-color-palette.md,extract-colors.md,for-print,for-screen,overview.md,replace.md}|colors/for-print:{cmyk.md,spot.md}|colors/for-screen:{p3.md,srgb.md}|compatibility.md|concepts:{architecture.md,assets.md,blocks.md,buffers.md,design-units.md,editing-workflow.md,error-catalog.md,events.md,headless-mode.md,import-export.md,pages.md,plugin-architecture.md,resources.md,scenes.md,templating.md,terminology.md,undo-and-history.md}|configuration.md|conversion:{overview.md,to-base64.md,to-pdf.md,to-png.md}|create-audio:{audio}|create-audio/audio:{add-music.md,add-sound-effects.md,adjust-speed.md,adjust-volume.md,fade.md,loop.md}|create-composition:{add-background.md,blend-modes.md,collage.md,group-and-ungroup.md,layer-management.md,layout.md,lock-design.md,multi-page.md,overview.md,position-and-align.md,programmatic.md}|create-templates:{add-dynamic-content,add-to-template-library.md,edit-or-remove.md,from-scratch.md,import,lock.md,overview.md}|create-templates/add-dynamic-content:{placeholders.md,set-editing-constraints.md,text-variables.md}|create-templates/import:{from-scene-file.md}|create-video:{control.md,limitations.md}|edit-image:{add-watermark.md,overview.md,remove-bg.md,replace-colors.md,transform}|edit-image/transform:{crop.md,flip.md,move.md,resize.md,rotate.md,scale.md}|edit-video:{add-captions.md,add-watermark.md,join-and-arrange.md,redaction.md,split.md,transform,trim.md}|edit-video/transform:{crop.md,flip.md,move.md,resize.md,rotate.md,scale.md}|engine-interface.md|export-counting.md|export-save-publish:{create-thumbnail.md,export,for-printing.md,for-social-media.md,pre-export-validation.md,save.md,store-custom-metadata.md}|export-save-publish/export:{audio.md,compress.md,overview.md,partial-export.md,size-limits.md,to-jpeg.md,to-pdf.md,to-png.md,to-raw-data.md,to-webp.md,with-color-mask.md}|file-format-support.md|fills:{color.md,gradient.md,image.md,overview.md,video.md}|filters-and-effects:{apply.md,blur.md,chroma-key-green-screen.md,create-custom-filters.md,create-custom-lut-filter.md,distortion.md,duotone.md,overview.md,support.md}|get-started:{agent-skills.md,build-with-ai.md,bun.md,cesdk-plugin-coding-agents.md,deno.md,mcp-server.md,overview.md,vanilla.md,vanilla-aws-lambda.md,vanilla-clone-github-project.md}|guides.md|import-media:{asset-library,concepts.md,content-json-schema.md,default-assets.md,edit-or-remove-assets.md,file-format-support.md,from-remote-source,overview.md,retrieve-mimetype.md,size-limits.md,source-sets.md}|import-media/asset-library:{refresh-assets.md}|import-media/from-remote-source:{asset-versioning.md,remote-asset.md}|insert-media:{audio.md,images.md,overview.md,shapes-or-stickers.md,videos.md}|key-capabilities.md|key-concepts.md|licensing.md|llms-txt.md|open-the-editor:{blank-canvas.md,from-image.md,from-template.md,from-video.md,import-design,load-scene.md,overview.md,uri-resolver.md}|open-the-editor/import-design:{from-archive.md,from-indesign.md,from-photoshop.md}|outlines:{overview.md,shadows-and-glows.md,strokes.md}|overview.md|performance.md|plugins:{print-ready-pdf.md}|rules:{asset-handling.md,common-pitfalls.md,content-fill-mode.md,enforce-brand-guidelines.md,lock-content.md,moderate-content.md,overview.md,silent-init-errors.md,verify-properties-before-use.md}|security.md|serve-assets.md|settings.md|shapes.md|stickers.md|stickers-and-shapes:{combine.md,create-cutout.md,create-edit,insert-qr-code.md}|stickers-and-shapes/create-edit:{create-shapes.md,create-stickers.md,edit-shapes.md}|text:{add.md,adjust-spacing.md,auto-size.md,edit.md,effects.md,emojis.md,language-support.md,overview.md,styling.md,text-designs.md}|to-v1-19.md|upgrade.md|use-templates:{apply-template.md,generate.md,overview.md,programmatic.md,replace-content.md}|what-is-cesdk.md|<-- IMGLY-AGENTS-MD-END -->
|
|
29
29
|
|
|
30
30
|
## API Index
|
|
31
31
|
|
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
> This is one page of the CE.SDK Node.js documentation. For a complete overview, see the [Node.js Documentation Index](https://img.ly/docs/cesdk/node.md). For all docs in one file, see [llms-full.txt](./llms-full.txt.md).
|
|
2
|
+
|
|
3
|
+
**Navigation:** [Guides](./guides.md) > [Actions](./actions.md)
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
The Actions API provides a centralized way to manage and customize actions when running CE.SDK headlessly on Node.js.
|
|
8
|
+
|
|
9
|
+
> **Note:** The Actions API is available after engine initialization through
|
|
10
|
+
> `engine.actions`. The `@cesdk/node` package exposes the same actions API as
|
|
11
|
+
> the browser engine. There is no prebuilt editor in a headless environment, so
|
|
12
|
+
> the host UI actions of the browser editor (`saveScene`, `exportDesign`,
|
|
13
|
+
> `uploadFile`, and the rest) are not registered.
|
|
14
|
+
|
|
15
|
+
```typescript file=@cesdk_web_examples/guides-actions-server-js/server-js.ts reference-only
|
|
16
|
+
import CreativeEngine from '@cesdk/node';
|
|
17
|
+
import { config } from 'dotenv';
|
|
18
|
+
import { mkdir, writeFile } from 'fs/promises';
|
|
19
|
+
|
|
20
|
+
config();
|
|
21
|
+
|
|
22
|
+
async function main() {
|
|
23
|
+
const engine = await CreativeEngine.init({
|
|
24
|
+
baseURL: process.env.IMGLY_LOCAL_ASSETS_URL
|
|
25
|
+
// license: process.env.CESDK_LICENSE,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
// Create a scene with a page and a selected block so selection-based
|
|
30
|
+
// actions have a target
|
|
31
|
+
engine.scene.create('VerticalStack', {
|
|
32
|
+
page: { size: { width: 800, height: 600 } }
|
|
33
|
+
});
|
|
34
|
+
const page = engine.block.findByType('page')[0];
|
|
35
|
+
|
|
36
|
+
const block = engine.block.create('graphic');
|
|
37
|
+
engine.block.setShape(block, engine.block.createShape('rect'));
|
|
38
|
+
engine.block.setWidth(block, 200);
|
|
39
|
+
engine.block.setHeight(block, 150);
|
|
40
|
+
engine.block.setPositionX(block, 100);
|
|
41
|
+
engine.block.setPositionY(block, 100);
|
|
42
|
+
engine.block.appendChild(page, block);
|
|
43
|
+
engine.block.setSelected(block, true);
|
|
44
|
+
|
|
45
|
+
// Engine defaults act on the current selection
|
|
46
|
+
const moved = await engine.actions.run('nudge', { dx: 10, dy: 0 });
|
|
47
|
+
console.log('Selection moved:', moved); // true
|
|
48
|
+
|
|
49
|
+
await engine.actions.run('selection.duplicate');
|
|
50
|
+
console.log('Blocks on page:', engine.block.getChildren(page).length);
|
|
51
|
+
|
|
52
|
+
// Explicitly targeted actions take their targets as arguments
|
|
53
|
+
await engine.actions.run('select', { ids: [block] });
|
|
54
|
+
console.log('Selected blocks:', engine.block.findAllSelected()); // [block]
|
|
55
|
+
|
|
56
|
+
// Register a custom action under your own id
|
|
57
|
+
engine.actions.register('myCompany.audit', (event: string) => {
|
|
58
|
+
const selected = engine.block.findAllSelected();
|
|
59
|
+
return { event, selectedBlocks: selected.length };
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const audit = await engine.actions.run('myCompany.audit', 'export');
|
|
63
|
+
console.log('Audit result:', audit); // { event: 'export', selectedBlocks: 1 }
|
|
64
|
+
|
|
65
|
+
// Override an engine default: hide instead of destroy
|
|
66
|
+
engine.actions.register('selection.delete', () => {
|
|
67
|
+
const selected = engine.block.findAllSelected();
|
|
68
|
+
selected.forEach((id) => engine.block.setVisible(id, false));
|
|
69
|
+
return selected.length;
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const hidden = await engine.actions.run('selection.delete');
|
|
73
|
+
console.log('Hidden blocks:', hidden); // 1
|
|
74
|
+
|
|
75
|
+
// Unregistering an overridden engine default restores the built-in behavior
|
|
76
|
+
engine.actions.unregister('selection.delete');
|
|
77
|
+
|
|
78
|
+
// Discover registered actions, optionally filtered by a glob matcher
|
|
79
|
+
const all = engine.actions.list();
|
|
80
|
+
console.log('Registered actions:', all.length);
|
|
81
|
+
|
|
82
|
+
const selectionActions = engine.actions.list({ matcher: 'selection.*' });
|
|
83
|
+
selectionActions.forEach(({ id, enabled }) => {
|
|
84
|
+
console.log(`${id} (enabled: ${enabled})`);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// Test for an action by id
|
|
88
|
+
console.log('Has nudge:', engine.actions.has('nudge')); // true
|
|
89
|
+
|
|
90
|
+
// get() returns the raw function for actions you registered ...
|
|
91
|
+
const auditFn = engine.actions.get('myCompany.audit');
|
|
92
|
+
if (auditFn != null) {
|
|
93
|
+
console.log('Sync call:', auditFn('archive'));
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// ... and undefined for engine-default native actions - use run() for those
|
|
97
|
+
console.log('Get nudge:', engine.actions.get('nudge')); // undefined
|
|
98
|
+
|
|
99
|
+
// Remove a custom action entirely
|
|
100
|
+
engine.actions.unregister('myCompany.audit');
|
|
101
|
+
console.log('Has audit:', engine.actions.has('myCompany.audit')); // false
|
|
102
|
+
|
|
103
|
+
// Export the scene as an image to verify the result
|
|
104
|
+
await mkdir('output', { recursive: true });
|
|
105
|
+
const blob = await engine.block.export(page, { mimeType: 'image/png' });
|
|
106
|
+
await writeFile('output/actions.png', Buffer.from(await blob.arrayBuffer()));
|
|
107
|
+
console.log('Exported preview: output/actions.png');
|
|
108
|
+
|
|
109
|
+
} finally {
|
|
110
|
+
engine.dispose();
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
main().catch(console.error);
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## The Action Registry
|
|
118
|
+
|
|
119
|
+
An action is a named function stored under a string id, such as `history.undo`, `text.toggleBold`, or `zoom`. You run actions by id, override what a built-in id does, add your own, or list what is available.
|
|
120
|
+
|
|
121
|
+
Registries are isolated per engine: actions registered on one `CreativeEngine` instance are not visible to another.
|
|
122
|
+
|
|
123
|
+
### Running an Action
|
|
124
|
+
|
|
125
|
+
Call `run(id, ...args)` to execute an action. It returns a `Promise` that resolves to the action's result — most engine defaults resolve to `true` or `false` (changed or no-change), a few to `null`.
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
// Undo the last change.
|
|
129
|
+
await engine.actions.run('history.undo');
|
|
130
|
+
|
|
131
|
+
// Nudge the current selection 10px to the right.
|
|
132
|
+
await engine.actions.run('nudge', { dx: 10, dy: 0 });
|
|
133
|
+
|
|
134
|
+
// Set the fill color of the selected blocks.
|
|
135
|
+
await engine.actions.run('fill.color', { color: { r: 1, g: 0, b: 0, a: 1 } });
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Selection verbs act on the current selection (`engine.block.findAllSelected()`); explicitly targeted actions take ids in their arguments. In a headless script there are no pointer events, so select blocks programmatically with `engine.block.setSelected()` before running a selection verb — without a selection it is a no-op and resolves to `false`.
|
|
139
|
+
|
|
140
|
+
### Registering and Overriding
|
|
141
|
+
|
|
142
|
+
Call `register(id, fn)` to add a new action or replace an existing one. Re-registering a default id overrides its behavior everywhere that id is used — including the engine's own dispatches.
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
// Add your own command.
|
|
146
|
+
engine.actions.register('myCompany.report', async (payload) => {
|
|
147
|
+
await sendAnalytics(payload);
|
|
148
|
+
return { ok: true };
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
// Override a built-in: hide instead of destroy.
|
|
152
|
+
engine.actions.register('selection.delete', () => {
|
|
153
|
+
engine.block
|
|
154
|
+
.findAllSelected()
|
|
155
|
+
.forEach((id) => engine.block.setVisible(id, false));
|
|
156
|
+
});
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
An action you register runs directly in JavaScript, so arguments and results pass by reference — non-serializable values such as `Buffer`s or callbacks work. The engine's own dispatches and calls that reach an engine-default native action go through a JSON boundary, so values that cross it must be JSON-serializable.
|
|
160
|
+
|
|
161
|
+
### Listing and Inspecting
|
|
162
|
+
|
|
163
|
+
Call `list(options?)` to discover registered actions. It returns an array of `{ id, enabled, argSchema }` objects. Pass a `matcher` glob to filter by id.
|
|
164
|
+
|
|
165
|
+
```ts
|
|
166
|
+
// Every registered action.
|
|
167
|
+
const all = engine.actions.list();
|
|
168
|
+
|
|
169
|
+
// Just the engine defaults under the `text.` namespace.
|
|
170
|
+
const textActions = engine.actions.list({ matcher: 'text.*' });
|
|
171
|
+
// => [{ id: 'text.toggleBold', enabled: true, argSchema: '…' }, …]
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Use `has(id)` to test for an action, `unregister(id)` to remove a custom action or revert an overridden built-in to its default, and `get(id)` to read back a function you registered so you can call it synchronously (it returns `undefined` for engine-default native actions; use `run` for those).
|
|
175
|
+
|
|
176
|
+
```ts
|
|
177
|
+
engine.actions.has('zoom'); // true
|
|
178
|
+
const report = engine.actions.get('myCompany.report'); // the raw fn
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## API Methods
|
|
182
|
+
|
|
183
|
+
The Actions API provides four methods:
|
|
184
|
+
|
|
185
|
+
- `register(actionId, handler)` - Register an action function for a specific event
|
|
186
|
+
- `get(actionId)` - Retrieve a registered action function
|
|
187
|
+
- `run(actionId, ...args)` - Execute a registered action with the provided arguments (throws if not registered)
|
|
188
|
+
- `list(matcher)` - Lists registered action IDs, optionally filtered by wildcard pattern
|
|
189
|
+
|
|
190
|
+
## Getting Started
|
|
191
|
+
|
|
192
|
+
Register actions after initializing the headless engine:
|
|
193
|
+
|
|
194
|
+
```javascript
|
|
195
|
+
import CreativeEngine from '@cesdk/node';
|
|
196
|
+
|
|
197
|
+
const engine = await CreativeEngine.init({
|
|
198
|
+
// license: 'YOUR_CESDK_LICENSE_KEY',
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
try {
|
|
202
|
+
// Register an action
|
|
203
|
+
engine.actions.register('actionType', async (...args) => {
|
|
204
|
+
// Your custom implementation
|
|
205
|
+
return result;
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
// Execute a registered action
|
|
209
|
+
await engine.actions.run('actionType', arg1, arg2);
|
|
210
|
+
|
|
211
|
+
// Or retrieve an action to call it later
|
|
212
|
+
const action = engine.actions.get('actionType');
|
|
213
|
+
|
|
214
|
+
// List all registered actions
|
|
215
|
+
const allActions = engine.actions.list();
|
|
216
|
+
|
|
217
|
+
// List actions matching a pattern
|
|
218
|
+
const textActions = engine.actions.list({ matcher: 'text.*' });
|
|
219
|
+
} finally {
|
|
220
|
+
// Dispose the engine when your script is done
|
|
221
|
+
engine.dispose();
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## Engine-Default Actions
|
|
226
|
+
|
|
227
|
+
The engine seeds its registry with the editor's command vocabulary. These run wherever the engine runs, including headless mode via `@cesdk/node`. Run any of them by id or override them. The full set is discoverable at runtime with `list()`:
|
|
228
|
+
|
|
229
|
+
### History
|
|
230
|
+
|
|
231
|
+
- `history.undo` - Undo the last change
|
|
232
|
+
- `history.redo` - Redo the last undone change
|
|
233
|
+
|
|
234
|
+
### Lifecycle / selection
|
|
235
|
+
|
|
236
|
+
- `selection.delete` - Delete the selected blocks
|
|
237
|
+
- `selection.duplicate` - Duplicate the selected blocks
|
|
238
|
+
- `selection.group` - Group the selected blocks
|
|
239
|
+
- `selection.ungroup` - Ungroup the selected group
|
|
240
|
+
- `group.enter` - Enter the selected group for editing
|
|
241
|
+
- `group.exit` - Exit the current group
|
|
242
|
+
- `select` - Select blocks by id (dispatched by the engine on click)
|
|
243
|
+
- `selection.all` - Select all blocks on the current page
|
|
244
|
+
- `select.byType` - Select all blocks of a given type
|
|
245
|
+
- `selection.parentOrDeselect` - Select the parent group, or deselect if none
|
|
246
|
+
- `rename` - Rename the selected block
|
|
247
|
+
- `lock.toggle` - Toggle the lock state of the selected blocks
|
|
248
|
+
|
|
249
|
+
### Transform / arrange
|
|
250
|
+
|
|
251
|
+
- `nudge` - Move the selection by a pixel delta (`{ dx, dy }`)
|
|
252
|
+
- `transform` - Apply position/size/rotation to blocks
|
|
253
|
+
- `resize` - Resize the selection by a delta or scale
|
|
254
|
+
- `scale` - Scale the selection around an anchor
|
|
255
|
+
- `rotate` - Rotate the selection by degrees (absolute or relative)
|
|
256
|
+
- `flip.horizontal` - Flip the selection horizontally
|
|
257
|
+
- `flip.vertical` - Flip the selection vertically
|
|
258
|
+
- `align.horizontal` - Align the selection horizontally (left/center/right)
|
|
259
|
+
- `align.vertical` - Align the selection vertically (top/center/bottom)
|
|
260
|
+
- `distribute.horizontal` - Distribute the selection horizontally
|
|
261
|
+
- `distribute.vertical` - Distribute the selection vertically
|
|
262
|
+
- `matchSize` - Match the size of the selection to a reference block
|
|
263
|
+
- `bringToFront` - Bring the selection to the front
|
|
264
|
+
- `bringForward` - Bring the selection forward one step
|
|
265
|
+
- `sendBackward` - Send the selection backward one step
|
|
266
|
+
- `sendToBack` - Send the selection to the back
|
|
267
|
+
- `reorder.moveToIndex` - Move the selection to a specific layer index
|
|
268
|
+
- `reparent` - Move the selection under a new parent
|
|
269
|
+
|
|
270
|
+
### Appearance
|
|
271
|
+
|
|
272
|
+
- `opacity` - Set the opacity of the selection
|
|
273
|
+
- `visibility.toggle` - Toggle visibility of the selection
|
|
274
|
+
- `blendMode` - Set the blend mode of the selection
|
|
275
|
+
- `fill.color` - Set the solid fill color
|
|
276
|
+
- `fill.toggle` - Toggle the fill on or off
|
|
277
|
+
- `contentFillMode` - Set the content fill mode (crop/cover/contain)
|
|
278
|
+
- `stroke.toggle` - Toggle the stroke on or off
|
|
279
|
+
- `stroke.color` - Set the stroke color
|
|
280
|
+
- `stroke.width` - Set the stroke width
|
|
281
|
+
- `dropShadow.toggle` - Toggle the drop shadow on or off
|
|
282
|
+
- `dropShadow.color` - Set the drop shadow color
|
|
283
|
+
- `dropShadow.offset` - Set the drop shadow offset
|
|
284
|
+
- `dropShadow.blur` - Set the drop shadow blur
|
|
285
|
+
- `blur.toggle` - Toggle the block blur on or off
|
|
286
|
+
- `blur.set` - Set the block blur type
|
|
287
|
+
- `effect.append` - Append an effect to the selection
|
|
288
|
+
- `effect.remove` - Remove an effect by index
|
|
289
|
+
- `effect.clear` - Remove all effects from the selection
|
|
290
|
+
|
|
291
|
+
### Crop / edit mode
|
|
292
|
+
|
|
293
|
+
- `crop.enter` - Enter crop mode (dispatched by the engine on double-click)
|
|
294
|
+
- `crop.reset` - Reset the crop to its default
|
|
295
|
+
- `crop.fillFrame` - Fill the frame with the cropped content
|
|
296
|
+
- `editmode.exit` - Exit the current edit mode
|
|
297
|
+
- `text.edit` - Enter text editing (dispatched by the engine on double-click)
|
|
298
|
+
|
|
299
|
+
### Text
|
|
300
|
+
|
|
301
|
+
- `text.toggleBold` - Toggle bold on the selected text
|
|
302
|
+
- `text.toggleItalic` - Toggle italic on the selected text
|
|
303
|
+
- `text.fontSize` - Set the font size
|
|
304
|
+
- `text.align` - Set the text alignment (left/center/right)
|
|
305
|
+
- `text.case` - Set the text case (normal/upper/lower/title)
|
|
306
|
+
- `text.color` - Set the text color
|
|
307
|
+
- `text.lineHeight` - Set the line height
|
|
308
|
+
- `text.letterSpacing` - Set the letter spacing
|
|
309
|
+
- `text.list` - Set the list style (none/unordered/ordered)
|
|
310
|
+
- `text.typeface` - Set the typeface
|
|
311
|
+
|
|
312
|
+
### Pages
|
|
313
|
+
|
|
314
|
+
- `page.add` - Add a new page
|
|
315
|
+
- `page.selectNext` - Scroll to the next page
|
|
316
|
+
- `page.selectPrevious` - Scroll to the previous page
|
|
317
|
+
- `page.remove` - Remove a page
|
|
318
|
+
- `page.duplicate` - Duplicate a page
|
|
319
|
+
- `page.size` - Set a page's size
|
|
320
|
+
- `page.background.toggle` - Toggle a page's background fill
|
|
321
|
+
- `page.title.edit` - Edit a page's title (dispatched by the engine)
|
|
322
|
+
|
|
323
|
+
### Scene / view
|
|
324
|
+
|
|
325
|
+
- `scene.layout` - Set the scene layout (free/stacks)
|
|
326
|
+
- `scene.size` - Set the scene size
|
|
327
|
+
- `zoom` - Set the zoom level/factor around a pivot
|
|
328
|
+
- `zoom.toBlock` - Zoom the camera to fit a block
|
|
329
|
+
- `zoom.toPage` - Zoom the camera to fit a page
|
|
330
|
+
- `zoom.autoFit.toggle` - Toggle auto-fit zoom on an axis
|
|
331
|
+
- `pan` - Pan the viewport by a delta
|
|
332
|
+
|
|
333
|
+
### Video / timeline / playback
|
|
334
|
+
|
|
335
|
+
- `selection.split` - Split the selected clip at the playhead
|
|
336
|
+
- `video.playPause` - Toggle playback of the current page
|
|
337
|
+
- `playback.seek` - Seek playback to a time
|
|
338
|
+
- `duration` - Set the duration of the selection
|
|
339
|
+
- `trim.offset` - Set the trim offset of the selection
|
|
340
|
+
- `trim.length` - Set the trim length of the selection
|
|
341
|
+
- `playbackSpeed` - Set the playback speed of the selection
|
|
342
|
+
- `volume` - Set the volume of the selection
|
|
343
|
+
- `mute.toggle` - Toggle mute on the selection
|
|
344
|
+
- `loop.toggle` - Toggle looping on the selection
|
|
345
|
+
- `timeOffset` - Set the time offset of the selection
|
|
346
|
+
- `animation.in` / `animation.in.remove` - Set or remove the in animation
|
|
347
|
+
- `animation.out` / `animation.out.remove` - Set or remove the out animation
|
|
348
|
+
- `animation.loop` / `animation.loop.remove` - Set or remove the loop animation
|
|
349
|
+
|
|
350
|
+
### Canvas interaction primitives
|
|
351
|
+
|
|
352
|
+
These exist for editor hosts that forward pointer input; they are rarely useful in a headless script.
|
|
353
|
+
|
|
354
|
+
- `drag.begin` - Begin a drag gesture on blocks
|
|
355
|
+
- `drag.end` - End a drag gesture on blocks
|
|
356
|
+
- `secondaryAction` - The secondary (context) action at a position
|
|
357
|
+
|
|
358
|
+
## Overriding Engine Defaults Safely
|
|
359
|
+
|
|
360
|
+
Some actions are dispatched by the engine itself in response to user input — for example `select` (on click), `crop.enter` and `text.edit` (on double-click), and `page.title.edit`. The engine reads the result of these within the same update, so an override of one of them must apply its effect **synchronously**.
|
|
361
|
+
|
|
362
|
+
```ts
|
|
363
|
+
// Synchronous override — runs in the same tick, so the engine sees the result.
|
|
364
|
+
engine.actions.register('select', ({ ids }) => {
|
|
365
|
+
applyMySelection(ids);
|
|
366
|
+
});
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
> **Caution:** When you override a self-dispatched action (`select`, `crop.enter`,
|
|
370
|
+
> `text.edit`, `page.title.edit`), apply the effect synchronously. An override
|
|
371
|
+
> that defers its work (for example by `await`-ing before applying it) lands a
|
|
372
|
+
> microtask too late for the engine's same-tick read, so the result is ignored
|
|
373
|
+
> for that input. Overriding actions you trigger yourself with `run` has no such
|
|
374
|
+
> constraint.
|
|
375
|
+
|
|
376
|
+
## Registering Custom Actions with Custom IDs
|
|
377
|
+
|
|
378
|
+
Beyond the predefined action types, you can register actions with custom IDs for your own application-specific needs:
|
|
379
|
+
|
|
380
|
+
```javascript
|
|
381
|
+
// Register a custom action
|
|
382
|
+
engine.actions.register('myCustomAction', async data => {
|
|
383
|
+
console.log('Custom action triggered with:', data);
|
|
384
|
+
return { success: true, processedData: data };
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
// Execute the custom action using run
|
|
388
|
+
const result = await engine.actions.run('myCustomAction', { someData: 'value' });
|
|
389
|
+
|
|
390
|
+
// Or retrieve it for conditional execution
|
|
391
|
+
const customAction = engine.actions.get('myCustomAction');
|
|
392
|
+
if (customAction) {
|
|
393
|
+
const result = await customAction({ someData: 'value' });
|
|
394
|
+
}
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
## Discovering Registered Actions
|
|
398
|
+
|
|
399
|
+
Use `list()` to get all registered action IDs or find actions matching a pattern:
|
|
400
|
+
|
|
401
|
+
```javascript
|
|
402
|
+
// Get all registered action IDs
|
|
403
|
+
const registeredActions = engine.actions.list();
|
|
404
|
+
console.log('Available actions:', registeredActions);
|
|
405
|
+
|
|
406
|
+
// Find actions matching a pattern
|
|
407
|
+
const selectionActions = engine.actions.list({ matcher: 'selection.*' });
|
|
408
|
+
console.log('Selection actions:', selectionActions);
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
## Differences from the Browser
|
|
412
|
+
|
|
413
|
+
The actions API itself is identical across `@cesdk/node`, `@cesdk/engine`, and the prebuilt editor's `cesdk.actions` — they all write to the same kind of registry. What differs on Node.js is which ids are pre-registered:
|
|
414
|
+
|
|
415
|
+
- **Host UI actions are absent.** The prebuilt browser editor registers convenience actions such as `saveScene`, `shareScene`, `importScene`, `exportScene`, `exportDesign`, `uploadFile`, `asset.delete`, `scene.create`, and the `video.*.checkSupport` and `timeline.*` actions. On Node.js these ids do not exist — use the engine APIs directly (for example `engine.scene.saveToString()` or `engine.block.export()`), or register your own implementations under the same ids.
|
|
416
|
+
- **Editor keyboard adapters are absent.** Ids the browser editor layers on top of the engine defaults — `copy`, `cut`, `paste`, `zoom.toFit`, `group.enterOrExit`, `selection.nudgeUp`/`Down`/`Left`/`Right` (and their `…Extended` variants), `text.toggleUnderline`, `text.toggleStrikethrough`, `vectorPath.deleteNodeOrPoint` - are not registered. The underlying engine defaults (`nudge`, `group.enter`, `group.exit`, `zoom.toBlock`, and so on) cover the same operations.
|
|
417
|
+
- **No dialogs or downloads.** Engine defaults never open UI, so everything in the registry runs headlessly. Anything you register yourself should also avoid DOM APIs.
|
|
418
|
+
|
|
419
|
+
Prefer `list()` over hardcoding assumptions when your code needs to know whether an id is available in the current environment.
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
|
|
423
|
+
---
|
|
424
|
+
|
|
425
|
+
## More Resources
|
|
426
|
+
|
|
427
|
+
- **[Node.js Documentation Index](https://img.ly/docs/cesdk/node.md)** - Browse all Node.js documentation
|
|
428
|
+
- **[Complete Documentation](./llms-full.txt.md)** - Full documentation in one file (for LLMs)
|
|
429
|
+
- **[Web Documentation](./node.md)** - Interactive documentation with examples
|
|
430
|
+
- **[Support](mailto:support@img.ly)** - Contact IMG.LY support
|
|
@@ -13,7 +13,7 @@ size-relative scaling and animations.
|
|
|
13
13
|
| Property | Type | Description |
|
|
14
14
|
| ------ | ------ | ------ |
|
|
15
15
|
| `blockType?` | `"//ly.img.ubq/text"` | `"//ly.img.ubq/caption"` | The block type this preset is for. Used as the type to create when the preset is applied with no target block, and as the apply filter (it only restyles a block of this type). Omitted applies to any block. Style presets target text and caption blocks; the value is the longhand id, which the engine matches against the block's `getType()`. |
|
|
16
|
-
| `mode?` | `"replace"` | `"merge"` | How the preset combines with the block's current look. `'replace'` (the default) also clears the decorations and animations the preset omits, so switching presets never stacks; `'merge'` layers the preset on top, keeping everything it does not set. Either way the block's text
|
|
16
|
+
| `mode?` | `"replace"` | `"merge"` | How the preset combines with the block's current look. `'replace'` (the default) also clears the decorations and animations the preset omits, so switching presets never stacks; `'merge'` layers the preset on top, keeping everything it does not set. Either way a restyle never touches the block's text. A preset writes its own text only when it makes a new block. The size only changes when the preset asks for it (`fontSize.resizeExistingOnApply`, or a `text/path` baseline adopting its box). |
|
|
17
17
|
| `typeface?` | `object` | Font to apply. The engine resolves `family` against the registered typefaces and matches `weight`/`style`. Ignored when the family is empty or not registered. |
|
|
18
18
|
| `typeface.family` | `string` | - |
|
|
19
19
|
| `typeface.weight?` | [`FontWeight`](./api/node/type-aliases/fontweight.md) | - |
|
|
@@ -43,6 +43,7 @@ Defines the possible options for exporting a design block.
|
|
|
43
43
|
| `underlayerMaxError?` | `number` | `2.0` | Maximum acceptable curve-fit error, in pixels, when vectorising the underlayer contour. Smaller values produce tighter fits at the cost of more path complexity. Useful together with `underlayerRenderRatio` for small text on large pages. Values `<= 0` fall back to 2.0. `NaN` / `Infinity` are rejected at the binding boundary with a `StructError`; pass a real number or leave the field undefined to use the default. |
|
|
44
44
|
| `allowTextOverhang?` | `boolean` | `false` | If true, the export will include text bounding boxes that account for glyph overhangs. When enabled, text blocks with glyphs that extend beyond their frame (e.g., decorative fonts with swashes) will be exported with the full glyph bounds visible, preventing text clipping. |
|
|
45
45
|
| `exportPdfWithDeviceCMYK?` | `boolean` | `false` | Export CMYK colors using their native color spaces in the PDF. When enabled, direct CMYK colors are written as DeviceCMYK (k/K operators) and spot colors with CMYK values (set via setSpotColorCMYK) are written as DeviceN with process CMYK components. When disabled (default), all colors are exported as DeviceRGB. |
|
|
46
|
+
| `pdfImageQuality?` | `number` | `1.0` | The encoding quality to use for images that have to be rasterized during PDF export, e.g. images with effects or blurs applied, or any bitmap image when `exportPdfWithHighCompatibility` is enabled. Valid values are (0-1]. Exactly 1.0 (the default) keeps the lossless encoding, like `webpQuality`. Any value below 1.0 re-encodes rasterized images as lossy JPEG at the given quality, which produces much smaller files. Only rasterized content that is fully opaque can be re-encoded, because JPEG has no alpha channel. Content that keeps transparency, for example when exporting a block or a page without a background fill, stays losslessly encoded whatever this option is set to. Images whose original JPEG data is embedded directly are never re-encoded and are not affected by this option. |
|
|
46
47
|
| `abortSignal?` | `AbortSignal` | `undefined` | An abortsignal that can be used to cancel the export. |
|
|
47
48
|
|
|
48
49
|
|