@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.
Files changed (36) hide show
  1. package/assets/ai-plugins/apps.mjs +5 -5
  2. package/assets/ai-plugins/version.json +1 -1
  3. package/assets/docs/api/SKILL.md +2 -2
  4. package/assets/docs/api/index.d.ts +19 -3
  5. package/assets/docs/guide/SKILL.md +2 -2
  6. package/assets/docs/guide/actions.md +430 -0
  7. package/assets/docs/guide/api/node/interfaces/assetstylepreset.md +1 -1
  8. package/assets/docs/guide/api/node/type-aliases/exportoptions.md +1 -0
  9. package/assets/docs/guide/concepts/import-export.md +125 -0
  10. package/assets/docs/guide/concepts/plugin-architecture.md +187 -0
  11. package/assets/docs/guide/concepts.md +2 -0
  12. package/assets/docs/guide/conversion/to-pdf.md +1 -0
  13. package/assets/docs/guide/export-save-publish/export/compress.md +1 -0
  14. package/assets/docs/guide/export-save-publish/export/overview.md +5 -1
  15. package/assets/docs/guide/export-save-publish/export/to-pdf.md +17 -1
  16. package/assets/docs/guide/export-save-publish/for-printing.md +5 -0
  17. package/assets/docs/guide/file-format-support.md +3 -0
  18. package/assets/docs/guide/get-started/agent-skills.md +136 -34
  19. package/assets/docs/guide/get-started/cesdk-plugin-coding-agents.md +32 -10
  20. package/assets/docs/guide/guides.md +1 -0
  21. package/assets/docs/guide/open-the-editor/import-design/from-indesign.md +2 -0
  22. package/assets/docs/guide/open-the-editor/import-design/from-photoshop.md +4 -2
  23. package/assets/docs/guide/references/update-check.md +85 -0
  24. package/assets/docs/guide/rules/asset-handling.md +17 -6
  25. package/assets/docs/guide/rules/common-pitfalls.md +33 -22
  26. package/assets/docs/guide/rules/content-fill-mode.md +4 -4
  27. package/assets/docs/guide/rules/silent-init-errors.md +1 -1
  28. package/assets/docs/guide/rules/verify-properties-before-use.md +11 -2
  29. package/dist/assets/inline.generated.d.ts.map +1 -1
  30. package/dist/assets/inline.generated.js +28 -25
  31. package/dist/assets/inline.generated.js.map +1 -1
  32. package/dist/cli/trial-license.generated.d.ts +1 -1
  33. package/dist/cli/trial-license.generated.js +1 -1
  34. package/dist/cli/trial-license.generated.js.map +1 -1
  35. package/package.json +9 -9
  36. package/assets/docs/guide/api-reference/overview.md +0 -20
@@ -1,3 +1,3 @@
1
1
  {
2
- "version": "1.81.0-nightly.20260805"
2
+ "version": "1.81.1"
3
3
  }
@@ -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** | **9328** | `offset=9327, limit=300` |
53
- | VariableAPI | 10925 | `offset=10924, limit=100` |
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 text content is never
1374
- * touched, and its size only changes when the preset asks for it (`fontSize.resizeExistingOnApply`,
1375
- * or a `text/path` baseline adopting its bounding box).
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.0-nightly.20260805
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}|api-reference:{overview.md}|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,pages.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 -->
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 content is never touched, and its size only changes when the preset asks for it (`fontSize.resizeExistingOnApply`, or a `text/path` baseline adopting its bounding box). |
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