@cesdk/node-native 1.77.0-nightly.20260610
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/LICENSE.md +137 -0
- package/README.md +474 -0
- package/ThirdPartyLicenses.md +1041 -0
- package/assets/ly.img.cesdk/fonts/imgly_font_inter_semibold.otf +0 -0
- package/assets/ly.img.cesdk/icons/ErrorAudio.svg +5 -0
- package/assets/ly.img.cesdk/icons/ErrorConnection.svg +5 -0
- package/assets/ly.img.cesdk/icons/ErrorImage.svg +6 -0
- package/assets/ly.img.cesdk/icons/ErrorUnknown.svg +3 -0
- package/assets/ly.img.cesdk/icons/ErrorVideo.svg +6 -0
- package/assets/ly.img.cesdk/icons/Move.svg +3 -0
- package/assets/ly.img.cesdk/icons/RotateIndicator.svg +5 -0
- package/assets/ly.img.cesdk/icu/icudt74l.dat +0 -0
- package/assets/ly.img.cesdk/presets/.keep +0 -0
- package/assets/ly.img.cesdk/shaders/adjustments.sksl +106 -0
- package/assets/ly.img.cesdk/shaders/black_and_white_color_mixer.sksl +152 -0
- package/assets/ly.img.cesdk/shaders/common/ubq_adjustments.sksl +102 -0
- package/assets/ly.img.cesdk/shaders/common/ubq_color_conversions.sksl +354 -0
- package/assets/ly.img.cesdk/shaders/common/ubq_constants.sksl +13 -0
- package/assets/ly.img.cesdk/shaders/common/ubq_hue_constants.sksl +86 -0
- package/assets/ly.img.cesdk/shaders/common/ubq_noise.sksl +82 -0
- package/assets/ly.img.cesdk/shaders/cross_cut.sksl +38 -0
- package/assets/ly.img.cesdk/shaders/dot_pattern.sksl +29 -0
- package/assets/ly.img.cesdk/shaders/duotone_filter.sksl +26 -0
- package/assets/ly.img.cesdk/shaders/extrude_blur.sksl +85 -0
- package/assets/ly.img.cesdk/shaders/glow.sksl +31 -0
- package/assets/ly.img.cesdk/shaders/half_tone.sksl +14 -0
- package/assets/ly.img.cesdk/shaders/linocut.sksl +30 -0
- package/assets/ly.img.cesdk/shaders/liquid.sksl +19 -0
- package/assets/ly.img.cesdk/shaders/lut_filter.sksl +70 -0
- package/assets/ly.img.cesdk/shaders/mask_color.sksl +16 -0
- package/assets/ly.img.cesdk/shaders/mirror.sksl +21 -0
- package/assets/ly.img.cesdk/shaders/outliner.sksl +40 -0
- package/assets/ly.img.cesdk/shaders/pixelize.sksl +10 -0
- package/assets/ly.img.cesdk/shaders/placeholder_overlay_lines.sksl +18 -0
- package/assets/ly.img.cesdk/shaders/posterize.sksl +8 -0
- package/assets/ly.img.cesdk/shaders/radial_pixel.sksl +22 -0
- package/assets/ly.img.cesdk/shaders/recolor.sksl +57 -0
- package/assets/ly.img.cesdk/shaders/sharpie.sksl +74 -0
- package/assets/ly.img.cesdk/shaders/shifter.sksl +22 -0
- package/assets/ly.img.cesdk/shaders/tiltshift.sksl +21 -0
- package/assets/ly.img.cesdk/shaders/tv_glitch.sksl +25 -0
- package/assets/ly.img.cesdk/shaders/vignette.sksl +12 -0
- package/example.js +31 -0
- package/lib/index.d.ts +4072 -0
- package/lib/index.js +4922 -0
- package/lib/index.js.map +7 -0
- package/package.json +59 -0
package/lib/index.js
ADDED
|
@@ -0,0 +1,4922 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// ts/src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
ANIMATION_TYPES: () => ANIMATION_TYPES,
|
|
34
|
+
BLUR_TYPES: () => BLUR_TYPES,
|
|
35
|
+
CompressionFormat: () => CompressionFormat,
|
|
36
|
+
CompressionLevel: () => CompressionLevel,
|
|
37
|
+
DESIGN_BLOCK_TYPES: () => DESIGN_BLOCK_TYPES,
|
|
38
|
+
EFFECT_TYPES: () => EFFECT_TYPES,
|
|
39
|
+
FILL_TYPES: () => FILL_TYPES,
|
|
40
|
+
LogLevel: () => LogLevel,
|
|
41
|
+
MimeType: () => MimeType,
|
|
42
|
+
SHAPE_TYPES: () => SHAPE_TYPES,
|
|
43
|
+
default: () => index_default,
|
|
44
|
+
defaultLogger: () => defaultLogger,
|
|
45
|
+
isCMYKColor: () => isCMYKColor,
|
|
46
|
+
isRGBAColor: () => isRGBAColor,
|
|
47
|
+
isSpotColor: () => isSpotColor
|
|
48
|
+
});
|
|
49
|
+
module.exports = __toCommonJS(index_exports);
|
|
50
|
+
|
|
51
|
+
// ts/src/CreativeEngine.ts
|
|
52
|
+
var path = __toESM(require("node:path"));
|
|
53
|
+
var fs2 = __toESM(require("node:fs"));
|
|
54
|
+
var crypto = __toESM(require("node:crypto"));
|
|
55
|
+
var import_node_url2 = require("node:url");
|
|
56
|
+
|
|
57
|
+
// ../shared/ts/src/types.ts
|
|
58
|
+
var MimeType = {
|
|
59
|
+
Png: "image/png",
|
|
60
|
+
Jpeg: "image/jpeg",
|
|
61
|
+
WebP: "image/webp",
|
|
62
|
+
Tga: "image/x-tga",
|
|
63
|
+
Svg: "image/svg+xml",
|
|
64
|
+
Wav: "audio/wav",
|
|
65
|
+
Mp4Audio: "audio/mp4",
|
|
66
|
+
Mp4: "video/mp4",
|
|
67
|
+
QuickTime: "video/quicktime",
|
|
68
|
+
Binary: "application/octet-stream",
|
|
69
|
+
Pdf: "application/pdf",
|
|
70
|
+
Zip: "application/zip"
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
// ../shared/ts/src/blockTypes.ts
|
|
74
|
+
var DESIGN_BLOCK_TYPES = [
|
|
75
|
+
"scene",
|
|
76
|
+
"stack",
|
|
77
|
+
"camera",
|
|
78
|
+
"page",
|
|
79
|
+
"graphic",
|
|
80
|
+
"audio",
|
|
81
|
+
"text",
|
|
82
|
+
"group",
|
|
83
|
+
"cutout",
|
|
84
|
+
"track",
|
|
85
|
+
"caption",
|
|
86
|
+
"captionTrack"
|
|
87
|
+
];
|
|
88
|
+
var SHAPE_TYPES = [
|
|
89
|
+
"rect",
|
|
90
|
+
"line",
|
|
91
|
+
"ellipse",
|
|
92
|
+
"polygon",
|
|
93
|
+
"star",
|
|
94
|
+
"vector_path"
|
|
95
|
+
];
|
|
96
|
+
var FILL_TYPES = [
|
|
97
|
+
"color",
|
|
98
|
+
"gradient/linear",
|
|
99
|
+
"gradient/radial",
|
|
100
|
+
"gradient/conical",
|
|
101
|
+
"image",
|
|
102
|
+
"video",
|
|
103
|
+
"pixelStream"
|
|
104
|
+
];
|
|
105
|
+
var EFFECT_TYPES = [
|
|
106
|
+
"adjustments",
|
|
107
|
+
"cross_cut",
|
|
108
|
+
"dot_pattern",
|
|
109
|
+
"duotone_filter",
|
|
110
|
+
"extrude_blur",
|
|
111
|
+
"glow",
|
|
112
|
+
"green_screen",
|
|
113
|
+
"half_tone",
|
|
114
|
+
"linocut",
|
|
115
|
+
"liquid",
|
|
116
|
+
"lut_filter",
|
|
117
|
+
"mirror",
|
|
118
|
+
"outliner",
|
|
119
|
+
"pixelize",
|
|
120
|
+
"posterize",
|
|
121
|
+
"radial_pixel",
|
|
122
|
+
"recolor",
|
|
123
|
+
"sharpie",
|
|
124
|
+
"shifter",
|
|
125
|
+
"tilt_shift",
|
|
126
|
+
"tv_glitch",
|
|
127
|
+
"vignette"
|
|
128
|
+
];
|
|
129
|
+
var BLUR_TYPES = ["uniform", "linear", "mirrored", "radial"];
|
|
130
|
+
var ANIMATION_TYPES = [
|
|
131
|
+
"slide",
|
|
132
|
+
"pan",
|
|
133
|
+
"fade",
|
|
134
|
+
"blur",
|
|
135
|
+
"grow",
|
|
136
|
+
"zoom",
|
|
137
|
+
"pop",
|
|
138
|
+
"wipe",
|
|
139
|
+
"baseline",
|
|
140
|
+
"crop_zoom",
|
|
141
|
+
"spin",
|
|
142
|
+
"spin_loop",
|
|
143
|
+
"fade_loop",
|
|
144
|
+
"blur_loop",
|
|
145
|
+
"pulsating_loop",
|
|
146
|
+
"breathing_loop",
|
|
147
|
+
"jump_loop",
|
|
148
|
+
"squeeze_loop",
|
|
149
|
+
"sway_loop",
|
|
150
|
+
"scale_loop",
|
|
151
|
+
"typewriter_text",
|
|
152
|
+
"block_swipe_text",
|
|
153
|
+
"spread_text",
|
|
154
|
+
"merge_text",
|
|
155
|
+
"ken_burns"
|
|
156
|
+
];
|
|
157
|
+
|
|
158
|
+
// ../shared/ts/src/color-guards.ts
|
|
159
|
+
function isRGBAColor(color) {
|
|
160
|
+
return "r" in color && "a" in color && color.r !== void 0 && color.a !== void 0;
|
|
161
|
+
}
|
|
162
|
+
function isSpotColor(color) {
|
|
163
|
+
return "name" in color && color.name !== void 0;
|
|
164
|
+
}
|
|
165
|
+
function isCMYKColor(color) {
|
|
166
|
+
return "c" in color && "m" in color && "y" in color && "k" in color && color.c !== void 0 && color.m !== void 0 && color.y !== void 0 && color.k !== void 0;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// ../shared/ts/src/Logger.ts
|
|
170
|
+
var LogLevel = {
|
|
171
|
+
Info: "Info",
|
|
172
|
+
Warning: "Warning",
|
|
173
|
+
Error: "Error"
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
// ../shared/ts/src/defaultLogger.ts
|
|
177
|
+
function defaultLogger(message, level) {
|
|
178
|
+
const prefixedMessage = `[UBQ] ${message}`;
|
|
179
|
+
switch (level) {
|
|
180
|
+
case "Warning": {
|
|
181
|
+
console.warn(prefixedMessage);
|
|
182
|
+
break;
|
|
183
|
+
}
|
|
184
|
+
case "Error": {
|
|
185
|
+
console.error(prefixedMessage);
|
|
186
|
+
break;
|
|
187
|
+
}
|
|
188
|
+
case "Info": {
|
|
189
|
+
console.info(prefixedMessage);
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
192
|
+
default: {
|
|
193
|
+
console.log(prefixedMessage);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// ../shared/ts/src/api/VariableAPI.ts
|
|
199
|
+
var VariableAPI = class {
|
|
200
|
+
#engine;
|
|
201
|
+
constructor(engine) {
|
|
202
|
+
this.#engine = engine;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Get all text variable names currently stored in the engine.
|
|
206
|
+
* @returns List of variable names.
|
|
207
|
+
*/
|
|
208
|
+
findAll() {
|
|
209
|
+
return this.#engine.findAllVariables();
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Set a text variable's value. Creates the variable if it doesn't exist.
|
|
213
|
+
* @param key - The variable's key.
|
|
214
|
+
* @param value - The text value to assign.
|
|
215
|
+
*/
|
|
216
|
+
setString(key, value) {
|
|
217
|
+
this.#engine.setVariableString(key, value);
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Get a text variable's value.
|
|
221
|
+
* @param key - The variable's key.
|
|
222
|
+
* @returns The text value of the variable.
|
|
223
|
+
*/
|
|
224
|
+
getString(key) {
|
|
225
|
+
return this.#engine.getVariableString(key);
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Remove a text variable from the engine.
|
|
229
|
+
* @param key - The variable's key to remove.
|
|
230
|
+
*/
|
|
231
|
+
remove(key) {
|
|
232
|
+
this.#engine.removeVariable(key);
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
// ts/src/platform-packages.ts
|
|
237
|
+
var PLATFORM_PACKAGES = Object.freeze({
|
|
238
|
+
"darwin-arm64": "@cesdk/node-native-darwin-arm64",
|
|
239
|
+
"darwin-x64": "@cesdk/node-native-darwin-x64",
|
|
240
|
+
"linux-x64": "@cesdk/node-native-linux-x64"
|
|
241
|
+
});
|
|
242
|
+
function platformPackageFor(platform, arch) {
|
|
243
|
+
return PLATFORM_PACKAGES[`${platform}-${arch}`];
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// ts/src/builtin-typeface.ts
|
|
247
|
+
var BUILTIN_TYPEFACE_SOURCE_ID = "ly.img.typeface.builtin";
|
|
248
|
+
var BUILTIN_TYPEFACE_JSON = JSON.stringify({
|
|
249
|
+
version: "6.0.0",
|
|
250
|
+
id: BUILTIN_TYPEFACE_SOURCE_ID,
|
|
251
|
+
assets: [
|
|
252
|
+
{
|
|
253
|
+
id: "ly.img.typeface.builtin.inter",
|
|
254
|
+
label: { en: "Inter" },
|
|
255
|
+
payload: {
|
|
256
|
+
typeface: {
|
|
257
|
+
name: "Inter",
|
|
258
|
+
fonts: [
|
|
259
|
+
{
|
|
260
|
+
uri: "bundle://ly.img.cesdk/fonts/imgly_font_inter_semibold.otf",
|
|
261
|
+
subFamily: "Semi Bold",
|
|
262
|
+
weight: "semiBold",
|
|
263
|
+
style: "normal"
|
|
264
|
+
}
|
|
265
|
+
]
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
]
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
// ts/src/addDefaultAssetSources.ts
|
|
273
|
+
var fs = __toESM(require("node:fs/promises"));
|
|
274
|
+
var import_node_url = require("node:url");
|
|
275
|
+
var DEFAULT_SOURCE_IDS = [
|
|
276
|
+
"ly.img.sticker",
|
|
277
|
+
"ly.img.vectorpath",
|
|
278
|
+
"ly.img.colors.defaultPalette",
|
|
279
|
+
"ly.img.filter.lut",
|
|
280
|
+
"ly.img.filter.duotone",
|
|
281
|
+
"ly.img.effect",
|
|
282
|
+
"ly.img.blur",
|
|
283
|
+
"ly.img.typeface",
|
|
284
|
+
"ly.img.page.presets",
|
|
285
|
+
"ly.img.page.presets.video",
|
|
286
|
+
"ly.img.crop.presets",
|
|
287
|
+
"ly.img.text"
|
|
288
|
+
];
|
|
289
|
+
var DEMO_CONTENT_JSON_IDS = [
|
|
290
|
+
"ly.img.image",
|
|
291
|
+
"ly.img.video",
|
|
292
|
+
"ly.img.audio"
|
|
293
|
+
];
|
|
294
|
+
async function readContentJSON(url) {
|
|
295
|
+
if (url.startsWith("file://")) {
|
|
296
|
+
return fs.readFile((0, import_node_url.fileURLToPath)(url), "utf8");
|
|
297
|
+
}
|
|
298
|
+
if (url.startsWith("http://") || url.startsWith("https://")) {
|
|
299
|
+
const res = await fetch(url);
|
|
300
|
+
if (!res.ok) {
|
|
301
|
+
throw new Error(`Failed to fetch ${url}: ${res.status} ${res.statusText}`);
|
|
302
|
+
}
|
|
303
|
+
return res.text();
|
|
304
|
+
}
|
|
305
|
+
return fs.readFile(url, "utf8");
|
|
306
|
+
}
|
|
307
|
+
async function loadOne(asset, sourceId, baseURL) {
|
|
308
|
+
const normalizedBase = baseURL.replace(/\/+$/, "");
|
|
309
|
+
const contentURL = `${normalizedBase}/${sourceId}/content.json`;
|
|
310
|
+
try {
|
|
311
|
+
const json = await readContentJSON(contentURL);
|
|
312
|
+
await asset.addLocalAssetSourceFromJSONString(json, normalizedBase);
|
|
313
|
+
} catch (err) {
|
|
314
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
315
|
+
console.warn(
|
|
316
|
+
`[@cesdk/node-native] Failed to load asset source '${sourceId}' from ${contentURL}: ${msg}. Skipping.`
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
async function loadDefaultAssetSources(asset, baseURL, exclude) {
|
|
321
|
+
const tasks = DEFAULT_SOURCE_IDS.filter((id) => !exclude.has(id)).map(
|
|
322
|
+
(id) => loadOne(asset, id, baseURL)
|
|
323
|
+
);
|
|
324
|
+
if (!exclude.has("ly.img.captionPresets")) {
|
|
325
|
+
tasks.push(loadOne(asset, "ly.img.captionPresets", baseURL));
|
|
326
|
+
}
|
|
327
|
+
await Promise.all(tasks);
|
|
328
|
+
}
|
|
329
|
+
var UPLOAD_MIMES = {
|
|
330
|
+
image: {
|
|
331
|
+
Design: ["image/jpeg", "image/png", "image/webp", "image/svg+xml", "image/bmp", "image/gif", "image/apng"],
|
|
332
|
+
Video: ["image/jpeg", "image/png", "image/webp", "image/svg+xml", "image/bmp"]
|
|
333
|
+
},
|
|
334
|
+
video: ["application/json", "video/mp4", "video/quicktime", "video/webm", "video/matroska", "image/gif", "image/apng"],
|
|
335
|
+
audio: ["audio/mpeg", "audio/mp3", "audio/x-m4a", "audio/wav"]
|
|
336
|
+
};
|
|
337
|
+
async function loadDemoAssetSources(asset, baseURL, exclude, options = {}) {
|
|
338
|
+
const {
|
|
339
|
+
withUploadAssetSources = false,
|
|
340
|
+
sceneMode = "Design",
|
|
341
|
+
sceneAPI
|
|
342
|
+
} = options;
|
|
343
|
+
const manager = asset;
|
|
344
|
+
const existing = new Set(manager.findAllSources?.() ?? []);
|
|
345
|
+
if (withUploadAssetSources) {
|
|
346
|
+
if (!exclude.has("ly.img.image.upload") && !existing.has("ly.img.image.upload")) {
|
|
347
|
+
manager.addLocalSource("ly.img.image.upload", [...UPLOAD_MIMES.image[sceneMode]]);
|
|
348
|
+
}
|
|
349
|
+
if (sceneMode === "Video" && !exclude.has("ly.img.video.upload") && !existing.has("ly.img.video.upload")) {
|
|
350
|
+
manager.addLocalSource("ly.img.video.upload", [...UPLOAD_MIMES.video]);
|
|
351
|
+
}
|
|
352
|
+
if (sceneMode === "Video" && !exclude.has("ly.img.audio.upload") && !existing.has("ly.img.audio.upload")) {
|
|
353
|
+
manager.addLocalSource("ly.img.audio.upload", [...UPLOAD_MIMES.audio]);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
const contentJsonIds = DEMO_CONTENT_JSON_IDS.filter((id) => {
|
|
357
|
+
if (exclude.has(id)) return false;
|
|
358
|
+
if (sceneMode === "Design" && (id === "ly.img.video" || id === "ly.img.audio")) {
|
|
359
|
+
}
|
|
360
|
+
return true;
|
|
361
|
+
});
|
|
362
|
+
const registerTemplateSource = (id) => {
|
|
363
|
+
if (exclude.has(id) || existing.has(id)) return;
|
|
364
|
+
if (!sceneAPI) {
|
|
365
|
+
console.warn(
|
|
366
|
+
`[@cesdk/node-native] Cannot register ${id} without a sceneAPI handle. Templates will be visible but applying them will be a no-op. Pass \`{ sceneAPI: engine.scene }\` to engine.addDemoAssetSources().`
|
|
367
|
+
);
|
|
368
|
+
manager.addLocalSource(id);
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
manager.addLocalSource(id, void 0, async (assetForApply) => {
|
|
372
|
+
const meta = assetForApply.meta;
|
|
373
|
+
const sceneUri = meta?.uri;
|
|
374
|
+
if (!sceneUri) return void 0;
|
|
375
|
+
if (sceneUri.startsWith("UBQ1")) {
|
|
376
|
+
await sceneAPI.applyTemplateFromString(sceneUri);
|
|
377
|
+
} else {
|
|
378
|
+
await sceneAPI.applyTemplateFromURL(sceneUri);
|
|
379
|
+
}
|
|
380
|
+
return void 0;
|
|
381
|
+
});
|
|
382
|
+
};
|
|
383
|
+
registerTemplateSource("ly.img.template");
|
|
384
|
+
if (sceneMode === "Video") {
|
|
385
|
+
registerTemplateSource("ly.img.video.template");
|
|
386
|
+
}
|
|
387
|
+
if (!exclude.has("ly.img.textComponents") && !existing.has("ly.img.textComponents")) {
|
|
388
|
+
contentJsonIds.push("ly.img.textComponents");
|
|
389
|
+
}
|
|
390
|
+
await Promise.all(contentJsonIds.map((id) => loadOne(asset, id, baseURL)));
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// ts/src/configureEngine.ts
|
|
394
|
+
var KNOWN_FEATURE_FLAGS = /* @__PURE__ */ new Set([
|
|
395
|
+
"preventScrolling",
|
|
396
|
+
"singlePageMode",
|
|
397
|
+
"fileSystemUsageEnabled"
|
|
398
|
+
]);
|
|
399
|
+
var REMOVED_KEYS = [
|
|
400
|
+
{ key: "scene" },
|
|
401
|
+
{ key: "page" },
|
|
402
|
+
{ key: "initialSceneURL" },
|
|
403
|
+
{ key: "initialSceneString" },
|
|
404
|
+
{ key: "initialSceneFile" },
|
|
405
|
+
{ key: "initialSceneBlob" },
|
|
406
|
+
{ key: "initialImageURL" }
|
|
407
|
+
];
|
|
408
|
+
function configureEngine(engine, config, _options) {
|
|
409
|
+
const rawLogger = config?.logger ?? defaultLog;
|
|
410
|
+
const logger = (message, level) => {
|
|
411
|
+
try {
|
|
412
|
+
rawLogger(message, level);
|
|
413
|
+
} catch {
|
|
414
|
+
}
|
|
415
|
+
};
|
|
416
|
+
const role = config?.role ?? "Creator";
|
|
417
|
+
try {
|
|
418
|
+
engine.editor.setRole(role);
|
|
419
|
+
} catch (err) {
|
|
420
|
+
logger(`setRole failed: ${describeError(err)}`, "Warning");
|
|
421
|
+
}
|
|
422
|
+
if (config?.featureFlags) {
|
|
423
|
+
const flags = config.featureFlags;
|
|
424
|
+
for (const flag of Object.keys(flags)) {
|
|
425
|
+
if (!KNOWN_FEATURE_FLAGS.has(flag)) {
|
|
426
|
+
logger(
|
|
427
|
+
`Unknown featureFlag '${flag}' will be ignored. Known flags: ${[
|
|
428
|
+
...KNOWN_FEATURE_FLAGS
|
|
429
|
+
].join(", ")}.`,
|
|
430
|
+
"Warning"
|
|
431
|
+
);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
if (flags.preventScrolling) {
|
|
435
|
+
tryWarnOnFail(
|
|
436
|
+
() => engine.editor.setSettingBool("touch/singlePointPanning", false),
|
|
437
|
+
logger
|
|
438
|
+
);
|
|
439
|
+
tryWarnOnFail(
|
|
440
|
+
() => engine.editor.setSettingBool("touch/dragStartCanSelect", false),
|
|
441
|
+
logger
|
|
442
|
+
);
|
|
443
|
+
}
|
|
444
|
+
const singlePageMode = !!flags.singlePageMode;
|
|
445
|
+
tryWarnOnFail(
|
|
446
|
+
() => engine.editor.setSettingBool(
|
|
447
|
+
"features/singlePageModeEnabled",
|
|
448
|
+
singlePageMode
|
|
449
|
+
),
|
|
450
|
+
logger
|
|
451
|
+
);
|
|
452
|
+
const fileSystemUsageEnabled = flags.fileSystemUsageEnabled !== false;
|
|
453
|
+
tryWarnOnFail(
|
|
454
|
+
() => engine.editor.setSettingBool(
|
|
455
|
+
"features/fileSystemUsageEnabled",
|
|
456
|
+
fileSystemUsageEnabled
|
|
457
|
+
),
|
|
458
|
+
logger
|
|
459
|
+
);
|
|
460
|
+
}
|
|
461
|
+
try {
|
|
462
|
+
engine.editor.startTracking(
|
|
463
|
+
config?.license ?? "",
|
|
464
|
+
config?.userId ?? "",
|
|
465
|
+
""
|
|
466
|
+
);
|
|
467
|
+
} catch (err) {
|
|
468
|
+
logger(`startTracking failed: ${describeError(err)}`, "Warning");
|
|
469
|
+
}
|
|
470
|
+
if (config) {
|
|
471
|
+
const seen = config;
|
|
472
|
+
for (const entry of REMOVED_KEYS) {
|
|
473
|
+
if (entry.key in seen) {
|
|
474
|
+
logger(
|
|
475
|
+
`Configuration.${entry.key} is no longer supported and will be ignored.`,
|
|
476
|
+
"Warning"
|
|
477
|
+
);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
if (config?.presets?.typefaces && Object.keys(config.presets.typefaces).length > 0) {
|
|
482
|
+
logger(
|
|
483
|
+
"Configuration.presets.typefaces is deprecated. Register typefaces via engine.asset.addLocalSource / addLocalAssetSourceFromJSONString instead.",
|
|
484
|
+
"Warning"
|
|
485
|
+
);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
function tryWarnOnFail(fn, _logger) {
|
|
489
|
+
try {
|
|
490
|
+
fn();
|
|
491
|
+
} catch {
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
function describeError(err) {
|
|
495
|
+
if (err instanceof Error) return err.message;
|
|
496
|
+
return String(err);
|
|
497
|
+
}
|
|
498
|
+
function defaultLog(message, level) {
|
|
499
|
+
const prefixed = `[UBQ] ${message}`;
|
|
500
|
+
switch (level) {
|
|
501
|
+
case "Warning":
|
|
502
|
+
console.warn(prefixed);
|
|
503
|
+
break;
|
|
504
|
+
case "Error":
|
|
505
|
+
console.error(prefixed);
|
|
506
|
+
break;
|
|
507
|
+
case "Info":
|
|
508
|
+
console.info(prefixed);
|
|
509
|
+
break;
|
|
510
|
+
default:
|
|
511
|
+
console.log(prefixed);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// ts/src/license.ts
|
|
516
|
+
var LICENSE_ENDPOINT_PRODUCTION = "https://api.img.ly/activate";
|
|
517
|
+
var LICENSE_ENDPOINT_STAGING = "https://api.staging.img.ly/activate";
|
|
518
|
+
var LICENSE_ACTIVATION_TIMEOUT_MS = 1e4;
|
|
519
|
+
function pickEndpoint() {
|
|
520
|
+
if (process.env.CESDK_LICENSE_ENDPOINT) return process.env.CESDK_LICENSE_ENDPOINT;
|
|
521
|
+
if (process.env.NODE_ENV === "development" || process.env.CESDK_STAGING === "1") {
|
|
522
|
+
return LICENSE_ENDPOINT_STAGING;
|
|
523
|
+
}
|
|
524
|
+
return LICENSE_ENDPOINT_PRODUCTION;
|
|
525
|
+
}
|
|
526
|
+
async function downloadAndCheckLicense(config, fetchImpl = globalThis.fetch) {
|
|
527
|
+
if (!config.license || config.license.length === 0 || config.license === "evaluation-license") {
|
|
528
|
+
return "";
|
|
529
|
+
}
|
|
530
|
+
if (config.license.length >= 128) {
|
|
531
|
+
return config.license;
|
|
532
|
+
}
|
|
533
|
+
if (!fetchImpl) {
|
|
534
|
+
throw new Error(
|
|
535
|
+
"No global `fetch` available. Pass a `fetch` polyfill or use Node 18+."
|
|
536
|
+
);
|
|
537
|
+
}
|
|
538
|
+
const endpoint = pickEndpoint();
|
|
539
|
+
const controller = new AbortController();
|
|
540
|
+
const timer = setTimeout(
|
|
541
|
+
() => controller.abort(),
|
|
542
|
+
LICENSE_ACTIVATION_TIMEOUT_MS
|
|
543
|
+
);
|
|
544
|
+
let response;
|
|
545
|
+
try {
|
|
546
|
+
response = await fetchImpl(endpoint, {
|
|
547
|
+
method: "POST",
|
|
548
|
+
headers: { "Content-Type": "application/json" },
|
|
549
|
+
body: JSON.stringify({
|
|
550
|
+
apiKey: config.license,
|
|
551
|
+
userId: config.userId
|
|
552
|
+
}),
|
|
553
|
+
signal: controller.signal
|
|
554
|
+
});
|
|
555
|
+
} catch (e) {
|
|
556
|
+
if (controller.signal.aborted) {
|
|
557
|
+
throw new Error(
|
|
558
|
+
`License activation timed out after ${LICENSE_ACTIVATION_TIMEOUT_MS}ms (${endpoint}). Check network connectivity or set CESDK_LICENSE_ENDPOINT.`
|
|
559
|
+
);
|
|
560
|
+
}
|
|
561
|
+
throw e;
|
|
562
|
+
} finally {
|
|
563
|
+
clearTimeout(timer);
|
|
564
|
+
}
|
|
565
|
+
if (!response.ok) {
|
|
566
|
+
throw new Error(
|
|
567
|
+
"Unfortunately we are experiencing a server down time and your License key cannot be validated. We're already working on a fix and will restore service soon. Should services not restore within the hour, kindly get in touch with our support team."
|
|
568
|
+
);
|
|
569
|
+
}
|
|
570
|
+
const data = await response.json();
|
|
571
|
+
if (data.status === "valid") return data.license;
|
|
572
|
+
if (data.status === "expired") {
|
|
573
|
+
throw new Error(
|
|
574
|
+
"Thanks for using IMG.LY for creative editing. Please note that your license file or commercial use is expired. Please get in touch with our sales team to discuss extension of your commercial license."
|
|
575
|
+
);
|
|
576
|
+
}
|
|
577
|
+
throw new Error(
|
|
578
|
+
"The License Key (API Key) you are using to access the IMG.LY SDK is invalid. Please ensure that you are using the license key tied to your subscription and get in touch with our support team."
|
|
579
|
+
);
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
// ts/src/CreativeEngine.ts
|
|
583
|
+
function isRGBAColor2(color) {
|
|
584
|
+
return "r" in color && "a" in color && color.r !== void 0 && color.a !== void 0;
|
|
585
|
+
}
|
|
586
|
+
function isSpotColor2(color) {
|
|
587
|
+
return "name" in color && color.name !== void 0;
|
|
588
|
+
}
|
|
589
|
+
function isCMYKColor2(color) {
|
|
590
|
+
return "c" in color && "m" in color && "y" in color && "k" in color && color.c !== void 0 && color.m !== void 0 && color.y !== void 0 && color.k !== void 0;
|
|
591
|
+
}
|
|
592
|
+
var NativeColorInternal;
|
|
593
|
+
((NativeColorInternal2) => {
|
|
594
|
+
let ColorSpace;
|
|
595
|
+
((ColorSpace2) => {
|
|
596
|
+
ColorSpace2[ColorSpace2["sRGB"] = 0] = "sRGB";
|
|
597
|
+
ColorSpace2[ColorSpace2["CMYK"] = 1] = "CMYK";
|
|
598
|
+
ColorSpace2[ColorSpace2["SpotColor"] = 2] = "SpotColor";
|
|
599
|
+
})(ColorSpace = NativeColorInternal2.ColorSpace || (NativeColorInternal2.ColorSpace = {}));
|
|
600
|
+
function toColor(color) {
|
|
601
|
+
switch (color.colorSpace) {
|
|
602
|
+
case 0 /* sRGB */:
|
|
603
|
+
return {
|
|
604
|
+
r: color.components.x,
|
|
605
|
+
g: color.components.y,
|
|
606
|
+
b: color.components.z,
|
|
607
|
+
a: color.components.w
|
|
608
|
+
};
|
|
609
|
+
case 2 /* SpotColor */: {
|
|
610
|
+
return {
|
|
611
|
+
name: color.spotColorName,
|
|
612
|
+
tint: color.tint,
|
|
613
|
+
externalReference: color.externalReference
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
case 1 /* CMYK */:
|
|
617
|
+
return {
|
|
618
|
+
c: color.components.x,
|
|
619
|
+
m: color.components.y,
|
|
620
|
+
y: color.components.z,
|
|
621
|
+
k: color.components.w,
|
|
622
|
+
tint: color.tint
|
|
623
|
+
};
|
|
624
|
+
default:
|
|
625
|
+
throw new Error("Unknown color space!");
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
NativeColorInternal2.toColor = toColor;
|
|
629
|
+
function fromColor(color) {
|
|
630
|
+
if (isRGBAColor2(color)) {
|
|
631
|
+
return {
|
|
632
|
+
colorSpace: 0 /* sRGB */,
|
|
633
|
+
components: { x: color.r, y: color.g, z: color.b, w: color.a },
|
|
634
|
+
spotColorName: "",
|
|
635
|
+
tint: 1,
|
|
636
|
+
externalReference: ""
|
|
637
|
+
};
|
|
638
|
+
} else if (isCMYKColor2(color)) {
|
|
639
|
+
return {
|
|
640
|
+
colorSpace: 1 /* CMYK */,
|
|
641
|
+
components: { x: color.c, y: color.m, z: color.y, w: color.k },
|
|
642
|
+
spotColorName: "",
|
|
643
|
+
tint: color.tint ?? 1,
|
|
644
|
+
externalReference: ""
|
|
645
|
+
};
|
|
646
|
+
} else if (isSpotColor2(color)) {
|
|
647
|
+
return {
|
|
648
|
+
colorSpace: 2 /* SpotColor */,
|
|
649
|
+
components: { x: 0, y: 0, z: 0, w: 0 },
|
|
650
|
+
spotColorName: color.name,
|
|
651
|
+
tint: color.tint,
|
|
652
|
+
externalReference: color.externalReference
|
|
653
|
+
};
|
|
654
|
+
}
|
|
655
|
+
throw new Error("Unknown color space!");
|
|
656
|
+
}
|
|
657
|
+
NativeColorInternal2.fromColor = fromColor;
|
|
658
|
+
})(NativeColorInternal || (NativeColorInternal = {}));
|
|
659
|
+
function convertUTF16ToGraphemeRange(text, from, to) {
|
|
660
|
+
if (from < 0 && to < 0) {
|
|
661
|
+
return { from, to };
|
|
662
|
+
}
|
|
663
|
+
const segmenter = new Intl.Segmenter("en");
|
|
664
|
+
const codeUnitToGrapheme = new Array(text.length + 1);
|
|
665
|
+
let codeUnit = 0;
|
|
666
|
+
let graphemeIdx = 0;
|
|
667
|
+
for (const seg of segmenter.segment(text)) {
|
|
668
|
+
for (let i = codeUnit; i <= seg.index; i++) {
|
|
669
|
+
codeUnitToGrapheme[i] = graphemeIdx;
|
|
670
|
+
}
|
|
671
|
+
codeUnit = seg.index + 1;
|
|
672
|
+
graphemeIdx++;
|
|
673
|
+
}
|
|
674
|
+
for (let i = codeUnit; i <= text.length; i++) {
|
|
675
|
+
codeUnitToGrapheme[i] = graphemeIdx;
|
|
676
|
+
}
|
|
677
|
+
const fromGrapheme = from < 0 ? from : codeUnitToGrapheme[Math.min(from, text.length)];
|
|
678
|
+
const toGrapheme = to < 0 ? to : codeUnitToGrapheme[Math.min(to, text.length)];
|
|
679
|
+
return { from: fromGrapheme, to: toGrapheme };
|
|
680
|
+
}
|
|
681
|
+
function convertGraphemeToUTF16Range(text, from, to) {
|
|
682
|
+
if (from < 0 && to < 0) {
|
|
683
|
+
return { from, to };
|
|
684
|
+
}
|
|
685
|
+
const segmenter = new Intl.Segmenter("en");
|
|
686
|
+
const graphemeStarts = [];
|
|
687
|
+
for (const seg of segmenter.segment(text)) {
|
|
688
|
+
graphemeStarts.push(seg.index);
|
|
689
|
+
}
|
|
690
|
+
graphemeStarts.push(text.length);
|
|
691
|
+
const fromUtf16 = from < 0 ? from : from >= graphemeStarts.length ? text.length : graphemeStarts[from];
|
|
692
|
+
const toUtf16 = to < 0 ? to : to >= graphemeStarts.length ? text.length : graphemeStarts[to];
|
|
693
|
+
return { from: fromUtf16, to: toUtf16 };
|
|
694
|
+
}
|
|
695
|
+
var NATIVE_DEBUG_ENABLED = process.env.CESDK_DEBUG === "1" || /(^|,)cesdk(:native)?(,|$)/.test(process.env.DEBUG ?? "");
|
|
696
|
+
function nativeDebug(message) {
|
|
697
|
+
if (NATIVE_DEBUG_ENABLED) {
|
|
698
|
+
console.error(`[cesdk:native] ${message}`);
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
async function verifyAddonSha256(addonPath) {
|
|
702
|
+
if (process.env.CESDK_SKIP_BINARY_VERIFY === "1") {
|
|
703
|
+
nativeDebug("SHA-256 verification disabled via CESDK_SKIP_BINARY_VERIFY=1");
|
|
704
|
+
return;
|
|
705
|
+
}
|
|
706
|
+
const shaPath = `${addonPath}.sha256`;
|
|
707
|
+
if (!fs2.existsSync(shaPath)) {
|
|
708
|
+
return;
|
|
709
|
+
}
|
|
710
|
+
const shaContents = (await fs2.promises.readFile(shaPath, "utf8")).trim();
|
|
711
|
+
const expected = shaContents.split(/\s+/)[0];
|
|
712
|
+
if (!/^[0-9a-f]{64}$/i.test(expected)) {
|
|
713
|
+
const err = new Error(
|
|
714
|
+
`@cesdk/node-native: malformed SHA-256 sidecar at ${shaPath} \u2014 expected a 64-char hex digest. Likely a corrupted or incomplete install. Re-install @cesdk/node-native (verify the package signature with \`npm audit signatures\`), or set CESDK_SKIP_BINARY_VERIFY=1 to bypass (not recommended in production).`
|
|
715
|
+
);
|
|
716
|
+
err.code = "ERR_CESDK_BINARY_TAMPERED";
|
|
717
|
+
throw err;
|
|
718
|
+
}
|
|
719
|
+
const hasher = crypto.createHash("sha256");
|
|
720
|
+
await new Promise((resolve, reject) => {
|
|
721
|
+
const stream = fs2.createReadStream(addonPath, { highWaterMark: 64 * 1024 });
|
|
722
|
+
stream.on("data", (chunk) => hasher.update(chunk));
|
|
723
|
+
stream.on("error", reject);
|
|
724
|
+
stream.on("end", () => resolve());
|
|
725
|
+
});
|
|
726
|
+
const actual = hasher.digest("hex");
|
|
727
|
+
if (actual !== expected.toLowerCase()) {
|
|
728
|
+
const err = new Error(
|
|
729
|
+
`@cesdk/node-native: SHA-256 mismatch for native binary at ${addonPath}.
|
|
730
|
+
expected ${expected}
|
|
731
|
+
actual ${actual}
|
|
732
|
+
The binary does not match its checksum sidecar \u2014 likely a corrupted or incomplete install. Re-install @cesdk/node-native (and verify the package signature with \`npm audit signatures\`), or set CESDK_SKIP_BINARY_VERIFY=1 to bypass (not recommended in production).`
|
|
733
|
+
);
|
|
734
|
+
err.code = "ERR_CESDK_BINARY_TAMPERED";
|
|
735
|
+
throw err;
|
|
736
|
+
}
|
|
737
|
+
nativeDebug(`SHA-256 verified for ${addonPath}`);
|
|
738
|
+
}
|
|
739
|
+
function recordLoadError(bucket, source, e) {
|
|
740
|
+
if (e instanceof Error) {
|
|
741
|
+
const maybeCoded = e;
|
|
742
|
+
bucket.push({
|
|
743
|
+
source,
|
|
744
|
+
message: e.message,
|
|
745
|
+
code: typeof maybeCoded.code === "string" ? maybeCoded.code : void 0
|
|
746
|
+
});
|
|
747
|
+
} else {
|
|
748
|
+
bucket.push({ source, message: String(e) });
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
function rethrowIfTampered(e) {
|
|
752
|
+
if (e?.code === "ERR_CESDK_BINARY_TAMPERED") {
|
|
753
|
+
throw e;
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
function assertSupportedRuntime() {
|
|
757
|
+
const g = globalThis;
|
|
758
|
+
if (typeof g.Bun !== "undefined") {
|
|
759
|
+
throw new Error(
|
|
760
|
+
"@cesdk/node-native is not supported on Bun. Use @cesdk/node (WASM) instead."
|
|
761
|
+
);
|
|
762
|
+
}
|
|
763
|
+
if (typeof g.Deno !== "undefined") {
|
|
764
|
+
throw new Error(
|
|
765
|
+
"@cesdk/node-native is not supported on Deno. Use @cesdk/node (WASM) instead."
|
|
766
|
+
);
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
async function resolveFromEnvOverride() {
|
|
770
|
+
const envOverride = process.env.CESDK_NATIVE_BINARY_PATH;
|
|
771
|
+
if (envOverride === void 0 || envOverride === "") {
|
|
772
|
+
return void 0;
|
|
773
|
+
}
|
|
774
|
+
nativeDebug(`CESDK_NATIVE_BINARY_PATH override -> ${envOverride}`);
|
|
775
|
+
if (!path.isAbsolute(envOverride)) {
|
|
776
|
+
throw new Error(
|
|
777
|
+
`CESDK_NATIVE_BINARY_PATH must be an absolute path (got '${envOverride}').`
|
|
778
|
+
);
|
|
779
|
+
}
|
|
780
|
+
if (!envOverride.endsWith(".node")) {
|
|
781
|
+
throw new Error(
|
|
782
|
+
`CESDK_NATIVE_BINARY_PATH must point to a .node file (got '${envOverride}').`
|
|
783
|
+
);
|
|
784
|
+
}
|
|
785
|
+
let resolvedPath;
|
|
786
|
+
try {
|
|
787
|
+
resolvedPath = fs2.realpathSync(envOverride);
|
|
788
|
+
} catch (e) {
|
|
789
|
+
throw new Error(
|
|
790
|
+
`CESDK_NATIVE_BINARY_PATH at '${envOverride}' cannot be resolved: ${e instanceof Error ? e.message : String(e)}`
|
|
791
|
+
);
|
|
792
|
+
}
|
|
793
|
+
if (!resolvedPath.endsWith(".node")) {
|
|
794
|
+
throw new Error(
|
|
795
|
+
`CESDK_NATIVE_BINARY_PATH symlink target '${resolvedPath}' is not a .node file (override path: '${envOverride}').`
|
|
796
|
+
);
|
|
797
|
+
}
|
|
798
|
+
await verifyAddonSha256(resolvedPath);
|
|
799
|
+
try {
|
|
800
|
+
const addon = require(resolvedPath);
|
|
801
|
+
return { addon, addonPath: resolvedPath };
|
|
802
|
+
} catch (e) {
|
|
803
|
+
throw new Error(
|
|
804
|
+
`Failed to load CESDK_NATIVE_BINARY_PATH override at '${resolvedPath}': ${e instanceof Error ? e.message : String(e)}`
|
|
805
|
+
);
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
async function resolveFromSiblingPackage(siblingPkg, errors) {
|
|
809
|
+
try {
|
|
810
|
+
const pkgJsonPath = require.resolve(`${siblingPkg}/package.json`);
|
|
811
|
+
const loadPath = path.join(path.dirname(pkgJsonPath), "cesdk_native.node");
|
|
812
|
+
nativeDebug(`trying sibling package -> ${loadPath}`);
|
|
813
|
+
await verifyAddonSha256(loadPath);
|
|
814
|
+
const addon = require(loadPath);
|
|
815
|
+
return { addon, addonPath: loadPath };
|
|
816
|
+
} catch (e) {
|
|
817
|
+
rethrowIfTampered(e);
|
|
818
|
+
recordLoadError(errors, `${siblingPkg}/cesdk_native.node`, e);
|
|
819
|
+
return void 0;
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
async function resolveFromInPackage(errors) {
|
|
823
|
+
const inPkgPath = path.join(__dirname, "cesdk_native.node");
|
|
824
|
+
nativeDebug(`trying in-package -> ${inPkgPath}`);
|
|
825
|
+
try {
|
|
826
|
+
await verifyAddonSha256(inPkgPath);
|
|
827
|
+
const addon = require(inPkgPath);
|
|
828
|
+
return { addon, addonPath: inPkgPath };
|
|
829
|
+
} catch (e) {
|
|
830
|
+
rethrowIfTampered(e);
|
|
831
|
+
recordLoadError(errors, inPkgPath, e);
|
|
832
|
+
return void 0;
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
function buildLoadFailureError(key, siblingPkg, isProductionInstall, productionErrors, devErrors) {
|
|
836
|
+
const recovery = siblingPkg !== void 0 ? [
|
|
837
|
+
`Recovery:`,
|
|
838
|
+
` npm install --include=optional ${siblingPkg}`,
|
|
839
|
+
` (or re-run the install with optional dependencies enabled)`,
|
|
840
|
+
` Or use @cesdk/node (WASM) for broader install coverage.`
|
|
841
|
+
].join("\n") : [
|
|
842
|
+
`Your platform/arch '${key}' is not supported by @cesdk/node-native.`,
|
|
843
|
+
`Use @cesdk/node (WASM) for broader platform coverage.`
|
|
844
|
+
].join("\n");
|
|
845
|
+
const visibleErrors = isProductionInstall ? productionErrors : [...productionErrors, ...devErrors];
|
|
846
|
+
const message = [
|
|
847
|
+
`Failed to load the @cesdk/node-native addon for ${key}.`,
|
|
848
|
+
``,
|
|
849
|
+
recovery,
|
|
850
|
+
``,
|
|
851
|
+
`Tried:`,
|
|
852
|
+
...visibleErrors.map(
|
|
853
|
+
(e) => ` - ${e.source}: ${e.message}${e.code ? ` [${e.code}]` : ""}`
|
|
854
|
+
)
|
|
855
|
+
].join("\n");
|
|
856
|
+
const err = new Error(message);
|
|
857
|
+
const codedError = visibleErrors.find((e) => e.code !== void 0);
|
|
858
|
+
if (codedError?.code) {
|
|
859
|
+
err.code = codedError.code;
|
|
860
|
+
}
|
|
861
|
+
return err;
|
|
862
|
+
}
|
|
863
|
+
async function loadNativeAddon() {
|
|
864
|
+
assertSupportedRuntime();
|
|
865
|
+
const platform = process.platform;
|
|
866
|
+
const arch = process.arch;
|
|
867
|
+
const key = `${platform}-${arch}`;
|
|
868
|
+
nativeDebug(`platform=${platform} arch=${arch} key=${key}`);
|
|
869
|
+
const fromEnv = await resolveFromEnvOverride();
|
|
870
|
+
if (fromEnv !== void 0) {
|
|
871
|
+
return fromEnv;
|
|
872
|
+
}
|
|
873
|
+
const isProductionInstall = __dirname.includes(
|
|
874
|
+
`${path.sep}node_modules${path.sep}`
|
|
875
|
+
);
|
|
876
|
+
const productionErrors = [];
|
|
877
|
+
const devErrors = [];
|
|
878
|
+
const siblingPkg = platformPackageFor(platform, arch);
|
|
879
|
+
if (siblingPkg !== void 0) {
|
|
880
|
+
const fromSibling = await resolveFromSiblingPackage(
|
|
881
|
+
siblingPkg,
|
|
882
|
+
productionErrors
|
|
883
|
+
);
|
|
884
|
+
if (fromSibling !== void 0) {
|
|
885
|
+
return fromSibling;
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
const fromInPackage = await resolveFromInPackage(devErrors);
|
|
889
|
+
if (fromInPackage !== void 0) {
|
|
890
|
+
return fromInPackage;
|
|
891
|
+
}
|
|
892
|
+
throw buildLoadFailureError(
|
|
893
|
+
key,
|
|
894
|
+
siblingPkg,
|
|
895
|
+
isProductionInstall,
|
|
896
|
+
productionErrors,
|
|
897
|
+
devErrors
|
|
898
|
+
);
|
|
899
|
+
}
|
|
900
|
+
var _loadedAddon;
|
|
901
|
+
function getNativeAddon() {
|
|
902
|
+
if (_loadedAddon === void 0) {
|
|
903
|
+
_loadedAddon = loadNativeAddon().catch((e) => {
|
|
904
|
+
_loadedAddon = void 0;
|
|
905
|
+
throw e;
|
|
906
|
+
});
|
|
907
|
+
}
|
|
908
|
+
return _loadedAddon;
|
|
909
|
+
}
|
|
910
|
+
function resolveDefaultAssetsDir(addonPath) {
|
|
911
|
+
const candidates = [
|
|
912
|
+
path.join(__dirname, "..", "assets"),
|
|
913
|
+
path.join(__dirname, "..", "..", "assets"),
|
|
914
|
+
path.join(path.dirname(addonPath), "assets")
|
|
915
|
+
];
|
|
916
|
+
for (const dir of candidates) {
|
|
917
|
+
try {
|
|
918
|
+
if (fs2.statSync(dir).isDirectory()) {
|
|
919
|
+
nativeDebug(`resolveDefaultAssetsDir -> ${dir}`);
|
|
920
|
+
return dir;
|
|
921
|
+
}
|
|
922
|
+
} catch {
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
return void 0;
|
|
926
|
+
}
|
|
927
|
+
function convertFontSizeToPoints(value, unit, dpi) {
|
|
928
|
+
switch (unit) {
|
|
929
|
+
case "Point":
|
|
930
|
+
return value;
|
|
931
|
+
case "Pixel":
|
|
932
|
+
return 72 * value / dpi;
|
|
933
|
+
case "Millimeter":
|
|
934
|
+
return value * 72 / 25.4;
|
|
935
|
+
case "Inch":
|
|
936
|
+
return value * 72;
|
|
937
|
+
default:
|
|
938
|
+
return value;
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
function convertFontSizeFromPoints(valueInPoints, unit, dpi) {
|
|
942
|
+
switch (unit) {
|
|
943
|
+
case "Point":
|
|
944
|
+
return valueInPoints;
|
|
945
|
+
case "Pixel":
|
|
946
|
+
return valueInPoints * dpi / 72;
|
|
947
|
+
case "Millimeter":
|
|
948
|
+
return valueInPoints * 25.4 / 72;
|
|
949
|
+
case "Inch":
|
|
950
|
+
return valueInPoints / 72;
|
|
951
|
+
default:
|
|
952
|
+
return valueInPoints;
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
function normalizeBaseURL(raw) {
|
|
956
|
+
if (!raw) return raw;
|
|
957
|
+
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(raw)) {
|
|
958
|
+
return raw.endsWith("/") ? raw : `${raw}/`;
|
|
959
|
+
}
|
|
960
|
+
try {
|
|
961
|
+
const asUrl = (0, import_node_url2.pathToFileURL)(raw).href;
|
|
962
|
+
return asUrl.endsWith("/") ? asUrl : `${asUrl}/`;
|
|
963
|
+
} catch {
|
|
964
|
+
return raw.endsWith("/") ? raw : `${raw}/`;
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
function resolveEngineDevice(config) {
|
|
968
|
+
return config?.device ?? (process.env.CESDK_FORCE_CPU === "1" ? "cpu" : "auto");
|
|
969
|
+
}
|
|
970
|
+
function resolveEngineBaseURL(config, nativeAddonPath) {
|
|
971
|
+
let baseURL;
|
|
972
|
+
if (config?.baseURL !== void 0) {
|
|
973
|
+
baseURL = normalizeBaseURL(config.baseURL);
|
|
974
|
+
} else {
|
|
975
|
+
const assetsDir = resolveDefaultAssetsDir(nativeAddonPath);
|
|
976
|
+
baseURL = assetsDir ? `${(0, import_node_url2.pathToFileURL)(assetsDir).href}/` : "";
|
|
977
|
+
}
|
|
978
|
+
let enginePath = baseURL;
|
|
979
|
+
if (enginePath.startsWith("file://")) {
|
|
980
|
+
try {
|
|
981
|
+
enginePath = (0, import_node_url2.fileURLToPath)(enginePath);
|
|
982
|
+
} catch {
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
return { baseURL, enginePath };
|
|
986
|
+
}
|
|
987
|
+
async function registerBuiltinTypeface(engine) {
|
|
988
|
+
if (process.env.CESDK_SUPPRESS_BUILTIN_TYPEFACE === "1") {
|
|
989
|
+
return;
|
|
990
|
+
}
|
|
991
|
+
try {
|
|
992
|
+
await engine.asset.addLocalAssetSourceFromJSONString(BUILTIN_TYPEFACE_JSON);
|
|
993
|
+
} catch {
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
var BlockAPI = class {
|
|
997
|
+
#engine;
|
|
998
|
+
constructor(engine) {
|
|
999
|
+
this.#engine = engine;
|
|
1000
|
+
}
|
|
1001
|
+
// ==========================================================================
|
|
1002
|
+
// Block Lifecycle
|
|
1003
|
+
// ==========================================================================
|
|
1004
|
+
/**
|
|
1005
|
+
* Create a new block of the specified type.
|
|
1006
|
+
* @param type - The block type (e.g., 'graphic', 'text', 'page', 'audio').
|
|
1007
|
+
* @returns The ID of the newly created block.
|
|
1008
|
+
*/
|
|
1009
|
+
create(type) {
|
|
1010
|
+
return this.#engine.create(type);
|
|
1011
|
+
}
|
|
1012
|
+
/**
|
|
1013
|
+
* Create a new fill block of the specified type.
|
|
1014
|
+
* @param type - The fill type (e.g., 'color', 'gradient/linear', 'gradient/radial', 'image', 'video').
|
|
1015
|
+
* @returns The ID of the newly created fill block.
|
|
1016
|
+
*/
|
|
1017
|
+
createFill(type) {
|
|
1018
|
+
return this.#engine.createFill(type);
|
|
1019
|
+
}
|
|
1020
|
+
/**
|
|
1021
|
+
* Create a new shape block of the specified type.
|
|
1022
|
+
* @param type - The shape type (e.g., 'rect', 'ellipse', 'polygon', 'star', 'line').
|
|
1023
|
+
* @returns The ID of the newly created shape block.
|
|
1024
|
+
*/
|
|
1025
|
+
createShape(type) {
|
|
1026
|
+
return this.#engine.createShape(type);
|
|
1027
|
+
}
|
|
1028
|
+
/**
|
|
1029
|
+
* Create a new effect block of the specified type.
|
|
1030
|
+
* @param type - The effect type (e.g., 'adjustments', 'pixelize', 'glow', 'half_tone').
|
|
1031
|
+
* @returns The ID of the newly created effect block.
|
|
1032
|
+
*/
|
|
1033
|
+
createEffect(type) {
|
|
1034
|
+
return this.#engine.createEffect(type);
|
|
1035
|
+
}
|
|
1036
|
+
/**
|
|
1037
|
+
* Create a new blur block of the specified type.
|
|
1038
|
+
* @param type - The blur type (e.g., 'uniform', 'linear', 'mirrored', 'radial').
|
|
1039
|
+
* @returns The ID of the newly created blur block.
|
|
1040
|
+
*/
|
|
1041
|
+
createBlur(type) {
|
|
1042
|
+
return this.#engine.createBlur(type);
|
|
1043
|
+
}
|
|
1044
|
+
/**
|
|
1045
|
+
* Create a new animation block of the specified type.
|
|
1046
|
+
* @param type - The animation type.
|
|
1047
|
+
* @returns The ID of the newly created animation block.
|
|
1048
|
+
*/
|
|
1049
|
+
createAnimation(type) {
|
|
1050
|
+
return this.#engine.createAnimation(type);
|
|
1051
|
+
}
|
|
1052
|
+
/**
|
|
1053
|
+
* Duplicate an existing block.
|
|
1054
|
+
* @param block - The ID of the block to duplicate.
|
|
1055
|
+
* @param attachToParent - Whether to attach the duplicate to the same parent (default: true).
|
|
1056
|
+
* @returns The ID of the duplicated block.
|
|
1057
|
+
*/
|
|
1058
|
+
duplicate(block, attachToParent = true) {
|
|
1059
|
+
return this.#engine.duplicate(block, attachToParent);
|
|
1060
|
+
}
|
|
1061
|
+
/**
|
|
1062
|
+
* Destroy a block and release its resources.
|
|
1063
|
+
* @param block - The ID of the block to destroy.
|
|
1064
|
+
*/
|
|
1065
|
+
destroy(block) {
|
|
1066
|
+
this.#engine.destroy(block);
|
|
1067
|
+
}
|
|
1068
|
+
/**
|
|
1069
|
+
* Check if a block ID refers to a valid, existing block.
|
|
1070
|
+
* @param block - The ID to check.
|
|
1071
|
+
* @returns True if the block exists and is valid, false otherwise.
|
|
1072
|
+
*/
|
|
1073
|
+
isValid(block) {
|
|
1074
|
+
return this.#engine.isValid(block);
|
|
1075
|
+
}
|
|
1076
|
+
// ==========================================================================
|
|
1077
|
+
// Find Methods
|
|
1078
|
+
// ==========================================================================
|
|
1079
|
+
/**
|
|
1080
|
+
* Find all blocks in the scene.
|
|
1081
|
+
* @returns Array of all block IDs.
|
|
1082
|
+
*/
|
|
1083
|
+
findAll() {
|
|
1084
|
+
return this.#engine.findAll();
|
|
1085
|
+
}
|
|
1086
|
+
/**
|
|
1087
|
+
* Find all placeholder blocks in the scene.
|
|
1088
|
+
* @returns Array of placeholder block IDs.
|
|
1089
|
+
*/
|
|
1090
|
+
findAllPlaceholders() {
|
|
1091
|
+
return this.#engine.findAllPlaceholders();
|
|
1092
|
+
}
|
|
1093
|
+
/**
|
|
1094
|
+
* Find all blocks that are not part of the active scene tree (orphans).
|
|
1095
|
+
* Useful for diagnosing leaks where blocks are created with `create(...)`
|
|
1096
|
+
* but never appended to a parent.
|
|
1097
|
+
* @returns Array of unreferenced block IDs.
|
|
1098
|
+
*/
|
|
1099
|
+
findAllUnused() {
|
|
1100
|
+
return this.#engine.findAllUnused();
|
|
1101
|
+
}
|
|
1102
|
+
/**
|
|
1103
|
+
* Find blocks by their name.
|
|
1104
|
+
* @param name - The name to search for.
|
|
1105
|
+
* @returns Array of matching block IDs.
|
|
1106
|
+
*/
|
|
1107
|
+
findByName(name) {
|
|
1108
|
+
return this.#engine.findByName(name);
|
|
1109
|
+
}
|
|
1110
|
+
/**
|
|
1111
|
+
* Find blocks by their type.
|
|
1112
|
+
* @param type - The type to search for (e.g., '//ly.img.ubq/graphic').
|
|
1113
|
+
* @returns Array of matching block IDs.
|
|
1114
|
+
*/
|
|
1115
|
+
findByType(type) {
|
|
1116
|
+
return this.#engine.findByType(type);
|
|
1117
|
+
}
|
|
1118
|
+
/**
|
|
1119
|
+
* Find blocks by their kind.
|
|
1120
|
+
* @param kind - The kind to search for (e.g., 'image', 'text', 'sticker').
|
|
1121
|
+
* @returns Array of matching block IDs.
|
|
1122
|
+
*/
|
|
1123
|
+
findByKind(kind) {
|
|
1124
|
+
return this.#engine.findByKind(kind);
|
|
1125
|
+
}
|
|
1126
|
+
/**
|
|
1127
|
+
* Find all currently selected blocks.
|
|
1128
|
+
* @returns Array of selected block IDs.
|
|
1129
|
+
*/
|
|
1130
|
+
findAllSelected() {
|
|
1131
|
+
return this.#engine.findAllSelected();
|
|
1132
|
+
}
|
|
1133
|
+
// ==========================================================================
|
|
1134
|
+
// Hierarchy
|
|
1135
|
+
// ==========================================================================
|
|
1136
|
+
/**
|
|
1137
|
+
* Get the parent of a block.
|
|
1138
|
+
* @param block - The ID of the block.
|
|
1139
|
+
* @returns The ID of the parent block, or null if no parent.
|
|
1140
|
+
*/
|
|
1141
|
+
getParent(block) {
|
|
1142
|
+
if (!this.#engine.hasParent(block)) {
|
|
1143
|
+
return null;
|
|
1144
|
+
}
|
|
1145
|
+
return this.#engine.getParent(block);
|
|
1146
|
+
}
|
|
1147
|
+
/**
|
|
1148
|
+
* Check if a block has a parent.
|
|
1149
|
+
* @param block - The ID of the block.
|
|
1150
|
+
* @returns True if the block has a parent.
|
|
1151
|
+
*/
|
|
1152
|
+
hasParent(block) {
|
|
1153
|
+
return this.#engine.hasParent(block);
|
|
1154
|
+
}
|
|
1155
|
+
/**
|
|
1156
|
+
* Get all children of a block.
|
|
1157
|
+
* @param block - The ID of the parent block.
|
|
1158
|
+
* @returns Array of child block IDs.
|
|
1159
|
+
*/
|
|
1160
|
+
getChildren(block) {
|
|
1161
|
+
return this.#engine.getChildren(block);
|
|
1162
|
+
}
|
|
1163
|
+
/**
|
|
1164
|
+
* Insert a child block at a specific index.
|
|
1165
|
+
* @param parent - The ID of the parent block.
|
|
1166
|
+
* @param child - The ID of the child block to insert.
|
|
1167
|
+
* @param index - The index at which to insert the child.
|
|
1168
|
+
*/
|
|
1169
|
+
insertChild(parent, child, index) {
|
|
1170
|
+
this.#engine.insertChild(parent, child, index);
|
|
1171
|
+
}
|
|
1172
|
+
/**
|
|
1173
|
+
* Append a child block to the end of the parent's children.
|
|
1174
|
+
* @param parent - The ID of the parent block.
|
|
1175
|
+
* @param child - The ID of the child block to append.
|
|
1176
|
+
*/
|
|
1177
|
+
appendChild(parent, child) {
|
|
1178
|
+
this.#engine.appendChild(parent, child);
|
|
1179
|
+
}
|
|
1180
|
+
// ==========================================================================
|
|
1181
|
+
// Properties - Generic
|
|
1182
|
+
// ==========================================================================
|
|
1183
|
+
/**
|
|
1184
|
+
* Get the type of a block.
|
|
1185
|
+
* @param block - The ID of the block.
|
|
1186
|
+
* @returns The block type string (e.g., '//ly.img.ubq/graphic').
|
|
1187
|
+
*/
|
|
1188
|
+
getType(block) {
|
|
1189
|
+
return this.#engine.getType(block);
|
|
1190
|
+
}
|
|
1191
|
+
/**
|
|
1192
|
+
* Get the kind of a block.
|
|
1193
|
+
* @param block - The ID of the block.
|
|
1194
|
+
* @returns The block kind string (e.g., 'image', 'text', 'sticker').
|
|
1195
|
+
*/
|
|
1196
|
+
getKind(block) {
|
|
1197
|
+
return this.#engine.getKind(block);
|
|
1198
|
+
}
|
|
1199
|
+
/**
|
|
1200
|
+
* Set the kind of a block.
|
|
1201
|
+
* @param block - The ID of the block.
|
|
1202
|
+
* @param kind - The new kind value.
|
|
1203
|
+
*/
|
|
1204
|
+
setKind(block, kind) {
|
|
1205
|
+
this.#engine.setKind(block, kind);
|
|
1206
|
+
}
|
|
1207
|
+
/**
|
|
1208
|
+
* Get the name of a block.
|
|
1209
|
+
* @param block - The ID of the block.
|
|
1210
|
+
* @returns The block name.
|
|
1211
|
+
*/
|
|
1212
|
+
getName(block) {
|
|
1213
|
+
return this.#engine.getName(block);
|
|
1214
|
+
}
|
|
1215
|
+
/**
|
|
1216
|
+
* Set the name of a block.
|
|
1217
|
+
* @param block - The ID of the block.
|
|
1218
|
+
* @param name - The new name.
|
|
1219
|
+
*/
|
|
1220
|
+
setName(block, name) {
|
|
1221
|
+
this.#engine.setName(block, name);
|
|
1222
|
+
}
|
|
1223
|
+
/**
|
|
1224
|
+
* Get the UUID of a block.
|
|
1225
|
+
* @param block - The ID of the block.
|
|
1226
|
+
* @returns The block's UUID string.
|
|
1227
|
+
*/
|
|
1228
|
+
getUUID(block) {
|
|
1229
|
+
return this.#engine.getUUID(block);
|
|
1230
|
+
}
|
|
1231
|
+
// Properties - typed
|
|
1232
|
+
getBool(block, property) {
|
|
1233
|
+
return this.#engine.getBool(block, property);
|
|
1234
|
+
}
|
|
1235
|
+
setBool(block, property, value) {
|
|
1236
|
+
this.#engine.setBool(block, property, value);
|
|
1237
|
+
}
|
|
1238
|
+
getInt(block, property) {
|
|
1239
|
+
return this.#engine.getInt(block, property);
|
|
1240
|
+
}
|
|
1241
|
+
setInt(block, property, value) {
|
|
1242
|
+
this.#engine.setInt(block, property, value);
|
|
1243
|
+
}
|
|
1244
|
+
getFloat(block, property) {
|
|
1245
|
+
return this.#engine.getFloat(block, property);
|
|
1246
|
+
}
|
|
1247
|
+
setFloat(block, property, value) {
|
|
1248
|
+
this.#engine.setFloat(block, property, value);
|
|
1249
|
+
}
|
|
1250
|
+
getDouble(block, property) {
|
|
1251
|
+
return this.#engine.getDouble(block, property);
|
|
1252
|
+
}
|
|
1253
|
+
setDouble(block, property, value) {
|
|
1254
|
+
this.#engine.setDouble(block, property, value);
|
|
1255
|
+
}
|
|
1256
|
+
getString(block, property) {
|
|
1257
|
+
return this.#engine.getString(block, property);
|
|
1258
|
+
}
|
|
1259
|
+
setString(block, property, value) {
|
|
1260
|
+
this.#engine.setString(block, property, value);
|
|
1261
|
+
}
|
|
1262
|
+
getColor(block, property) {
|
|
1263
|
+
const internalColor = this.#engine.getColor(
|
|
1264
|
+
block,
|
|
1265
|
+
property
|
|
1266
|
+
);
|
|
1267
|
+
return NativeColorInternal.toColor(internalColor);
|
|
1268
|
+
}
|
|
1269
|
+
setColor(block, property, value) {
|
|
1270
|
+
const internalColor = NativeColorInternal.fromColor(value);
|
|
1271
|
+
this.#engine.setColor(block, property, internalColor);
|
|
1272
|
+
}
|
|
1273
|
+
getColorRGBA(block, property) {
|
|
1274
|
+
const color = this.getColor(block, property);
|
|
1275
|
+
if (!isRGBAColor2(color)) {
|
|
1276
|
+
throw new Error(
|
|
1277
|
+
"Color is not in sRGB color space. Use getColor() for non-RGBA colors."
|
|
1278
|
+
);
|
|
1279
|
+
}
|
|
1280
|
+
return { r: color.r, g: color.g, b: color.b, a: color.a };
|
|
1281
|
+
}
|
|
1282
|
+
setColorRGBA(block, property, r, g, b, a) {
|
|
1283
|
+
this.setColor(block, property, { r, g, b, a });
|
|
1284
|
+
}
|
|
1285
|
+
getEnum(block, property) {
|
|
1286
|
+
return this.#engine.getEnum(block, property);
|
|
1287
|
+
}
|
|
1288
|
+
setEnum(block, property, value) {
|
|
1289
|
+
this.#engine.setEnum(block, property, value);
|
|
1290
|
+
}
|
|
1291
|
+
// Transform
|
|
1292
|
+
getPositionX(block) {
|
|
1293
|
+
return this.#engine.getPositionX(block);
|
|
1294
|
+
}
|
|
1295
|
+
setPositionX(block, value) {
|
|
1296
|
+
this.#engine.setPositionX(block, value);
|
|
1297
|
+
}
|
|
1298
|
+
getPositionY(block) {
|
|
1299
|
+
return this.#engine.getPositionY(block);
|
|
1300
|
+
}
|
|
1301
|
+
setPositionY(block, value) {
|
|
1302
|
+
this.#engine.setPositionY(block, value);
|
|
1303
|
+
}
|
|
1304
|
+
getPositionXMode(block) {
|
|
1305
|
+
return this.#engine.getPositionXMode(block);
|
|
1306
|
+
}
|
|
1307
|
+
setPositionXMode(block, mode) {
|
|
1308
|
+
this.#engine.setPositionXMode(block, mode);
|
|
1309
|
+
}
|
|
1310
|
+
getPositionYMode(block) {
|
|
1311
|
+
return this.#engine.getPositionYMode(block);
|
|
1312
|
+
}
|
|
1313
|
+
setPositionYMode(block, mode) {
|
|
1314
|
+
this.#engine.setPositionYMode(block, mode);
|
|
1315
|
+
}
|
|
1316
|
+
getWidth(block) {
|
|
1317
|
+
return this.#engine.getWidth(block);
|
|
1318
|
+
}
|
|
1319
|
+
setWidth(block, value) {
|
|
1320
|
+
this.#engine.setWidth(block, value);
|
|
1321
|
+
}
|
|
1322
|
+
getWidthMode(block) {
|
|
1323
|
+
return this.#engine.getWidthMode(block);
|
|
1324
|
+
}
|
|
1325
|
+
setWidthMode(block, mode) {
|
|
1326
|
+
this.#engine.setWidthMode(block, mode);
|
|
1327
|
+
}
|
|
1328
|
+
getHeight(block) {
|
|
1329
|
+
return this.#engine.getHeight(block);
|
|
1330
|
+
}
|
|
1331
|
+
setHeight(block, value) {
|
|
1332
|
+
this.#engine.setHeight(block, value);
|
|
1333
|
+
}
|
|
1334
|
+
getHeightMode(block) {
|
|
1335
|
+
return this.#engine.getHeightMode(block);
|
|
1336
|
+
}
|
|
1337
|
+
setHeightMode(block, mode) {
|
|
1338
|
+
this.#engine.setHeightMode(block, mode);
|
|
1339
|
+
}
|
|
1340
|
+
getRotation(block) {
|
|
1341
|
+
return this.#engine.getRotation(block);
|
|
1342
|
+
}
|
|
1343
|
+
setRotation(block, value) {
|
|
1344
|
+
this.#engine.setRotation(block, value);
|
|
1345
|
+
}
|
|
1346
|
+
// Flip - WASM API has separate getters (no combined getFlip)
|
|
1347
|
+
getFlipHorizontal(block) {
|
|
1348
|
+
return this.#engine.getFlip(block).horizontal;
|
|
1349
|
+
}
|
|
1350
|
+
getFlipVertical(block) {
|
|
1351
|
+
return this.#engine.getFlip(block).vertical;
|
|
1352
|
+
}
|
|
1353
|
+
setFlipHorizontal(block, flip) {
|
|
1354
|
+
this.#engine.setFlipHorizontal(block, flip);
|
|
1355
|
+
}
|
|
1356
|
+
setFlipVertical(block, flip) {
|
|
1357
|
+
this.#engine.setFlipVertical(block, flip);
|
|
1358
|
+
}
|
|
1359
|
+
// WASM API convenience method for position
|
|
1360
|
+
setPosition(block, x, y, options) {
|
|
1361
|
+
if (options?.positionMode) {
|
|
1362
|
+
this.#engine.setPositionXMode(block, options.positionMode);
|
|
1363
|
+
this.#engine.setPositionYMode(block, options.positionMode);
|
|
1364
|
+
}
|
|
1365
|
+
this.#engine.setPositionX(block, x);
|
|
1366
|
+
this.#engine.setPositionY(block, y);
|
|
1367
|
+
}
|
|
1368
|
+
// WASM API convenience method for size
|
|
1369
|
+
setSize(block, width, height, options) {
|
|
1370
|
+
if (options?.sizeMode) {
|
|
1371
|
+
this.#engine.setWidthMode(block, options.sizeMode);
|
|
1372
|
+
this.#engine.setHeightMode(block, options.sizeMode);
|
|
1373
|
+
}
|
|
1374
|
+
this.#engine.setWidth(block, width);
|
|
1375
|
+
this.#engine.setHeight(block, height);
|
|
1376
|
+
}
|
|
1377
|
+
scale(block, scale, anchorX, anchorY) {
|
|
1378
|
+
this.#engine.scale(block, scale, anchorX, anchorY);
|
|
1379
|
+
}
|
|
1380
|
+
fillParent(block) {
|
|
1381
|
+
this.#engine.fillParent(block);
|
|
1382
|
+
}
|
|
1383
|
+
resizeContentAware(blocks, width, height) {
|
|
1384
|
+
return this.#engine.resizeContentAware(blocks, width, height);
|
|
1385
|
+
}
|
|
1386
|
+
// Global bounding box
|
|
1387
|
+
getGlobalBoundingBoxX(block) {
|
|
1388
|
+
return this.#engine.getGlobalBoundingBoxX(block);
|
|
1389
|
+
}
|
|
1390
|
+
getGlobalBoundingBoxY(block) {
|
|
1391
|
+
return this.#engine.getGlobalBoundingBoxY(block);
|
|
1392
|
+
}
|
|
1393
|
+
getGlobalBoundingBoxWidth(block) {
|
|
1394
|
+
return this.#engine.getGlobalBoundingBoxWidth(block);
|
|
1395
|
+
}
|
|
1396
|
+
getGlobalBoundingBoxHeight(block) {
|
|
1397
|
+
return this.#engine.getGlobalBoundingBoxHeight(block);
|
|
1398
|
+
}
|
|
1399
|
+
getScreenSpaceBoundingBoxXYWH(blocks) {
|
|
1400
|
+
return this.#engine.getScreenSpaceBoundingBoxXYWH(blocks);
|
|
1401
|
+
}
|
|
1402
|
+
// Fill - WASM also has hasFillColor and isFillColorEnabled
|
|
1403
|
+
supportsFill(block) {
|
|
1404
|
+
return this.#engine.supportsFill(block);
|
|
1405
|
+
}
|
|
1406
|
+
hasFill(block) {
|
|
1407
|
+
return this.#engine.hasFill(block);
|
|
1408
|
+
}
|
|
1409
|
+
hasFillColor(block) {
|
|
1410
|
+
return this.hasFill(block);
|
|
1411
|
+
}
|
|
1412
|
+
isFillColorEnabled(block) {
|
|
1413
|
+
return this.#engine.getFillEnabled(block);
|
|
1414
|
+
}
|
|
1415
|
+
setFillColorEnabled(block, enabled) {
|
|
1416
|
+
this.#engine.setFillEnabled(block, enabled);
|
|
1417
|
+
}
|
|
1418
|
+
getFillColorRGBA(block) {
|
|
1419
|
+
const color = this.getFillSolidColor(block);
|
|
1420
|
+
if (!isRGBAColor2(color)) {
|
|
1421
|
+
throw new Error(
|
|
1422
|
+
"Fill color is not in sRGB color space. Use getFillSolidColor() for non-RGBA colors."
|
|
1423
|
+
);
|
|
1424
|
+
}
|
|
1425
|
+
return { r: color.r, g: color.g, b: color.b, a: color.a };
|
|
1426
|
+
}
|
|
1427
|
+
setFillColorRGBA(block, r, g, b, a) {
|
|
1428
|
+
this.setFillSolidColor(block, r, g, b, a);
|
|
1429
|
+
}
|
|
1430
|
+
getFill(block) {
|
|
1431
|
+
return this.#engine.getFill(block);
|
|
1432
|
+
}
|
|
1433
|
+
setFill(block, fill) {
|
|
1434
|
+
this.#engine.setFill(block, fill);
|
|
1435
|
+
}
|
|
1436
|
+
getFillEnabled(block) {
|
|
1437
|
+
return this.#engine.getFillEnabled(block);
|
|
1438
|
+
}
|
|
1439
|
+
isFillEnabled(block) {
|
|
1440
|
+
return this.#engine.getFillEnabled(block);
|
|
1441
|
+
}
|
|
1442
|
+
setFillEnabled(block, enabled) {
|
|
1443
|
+
this.#engine.setFillEnabled(block, enabled);
|
|
1444
|
+
}
|
|
1445
|
+
getFillSolidColor(block) {
|
|
1446
|
+
return this.#engine.getFillSolidColor(block);
|
|
1447
|
+
}
|
|
1448
|
+
setFillSolidColor(block, r, g, b, a = 1) {
|
|
1449
|
+
this.#engine.setFillSolidColor(block, { r, g, b, a });
|
|
1450
|
+
}
|
|
1451
|
+
getGradientColorStops(block, property) {
|
|
1452
|
+
const raw = this.#engine.getGradientColorStops(block, property);
|
|
1453
|
+
return raw.map((s) => ({
|
|
1454
|
+
color: NativeColorInternal.toColor(s.color),
|
|
1455
|
+
stop: s.stop
|
|
1456
|
+
}));
|
|
1457
|
+
}
|
|
1458
|
+
setGradientColorStops(block, property, stops) {
|
|
1459
|
+
const engineStops = stops.map((s) => ({
|
|
1460
|
+
color: NativeColorInternal.fromColor(s.color),
|
|
1461
|
+
stop: s.stop
|
|
1462
|
+
}));
|
|
1463
|
+
this.#engine.setGradientColorStops(block, property, engineStops);
|
|
1464
|
+
}
|
|
1465
|
+
// Stroke
|
|
1466
|
+
supportsStroke(block) {
|
|
1467
|
+
return this.#engine.supportsStroke(block);
|
|
1468
|
+
}
|
|
1469
|
+
hasStroke(block) {
|
|
1470
|
+
return this.#engine.hasStroke(block);
|
|
1471
|
+
}
|
|
1472
|
+
getStroke(block) {
|
|
1473
|
+
return this.#engine.getStroke(block);
|
|
1474
|
+
}
|
|
1475
|
+
setStroke(block, stroke) {
|
|
1476
|
+
this.#engine.setStroke(block, stroke);
|
|
1477
|
+
}
|
|
1478
|
+
getStrokeEnabled(block) {
|
|
1479
|
+
return this.#engine.getStrokeEnabled(block);
|
|
1480
|
+
}
|
|
1481
|
+
isStrokeEnabled(block) {
|
|
1482
|
+
return this.#engine.getStrokeEnabled(block);
|
|
1483
|
+
}
|
|
1484
|
+
setStrokeEnabled(block, enabled) {
|
|
1485
|
+
this.#engine.setStrokeEnabled(block, enabled);
|
|
1486
|
+
}
|
|
1487
|
+
getStrokeColor(block) {
|
|
1488
|
+
const internalColor = this.#engine.getStrokeColor(
|
|
1489
|
+
block
|
|
1490
|
+
);
|
|
1491
|
+
return NativeColorInternal.toColor(internalColor);
|
|
1492
|
+
}
|
|
1493
|
+
setStrokeColor(block, color) {
|
|
1494
|
+
const internalColor = NativeColorInternal.fromColor(color);
|
|
1495
|
+
this.#engine.setStrokeColor(block, internalColor);
|
|
1496
|
+
}
|
|
1497
|
+
getStrokeWidth(block) {
|
|
1498
|
+
return this.#engine.getStrokeWidth(block);
|
|
1499
|
+
}
|
|
1500
|
+
setStrokeWidth(block, width) {
|
|
1501
|
+
this.#engine.setStrokeWidth(block, width);
|
|
1502
|
+
}
|
|
1503
|
+
getStrokeStyle(block) {
|
|
1504
|
+
return this.#engine.getStrokeStyle(block);
|
|
1505
|
+
}
|
|
1506
|
+
setStrokeStyle(block, style) {
|
|
1507
|
+
this.#engine.setStrokeStyle(block, style);
|
|
1508
|
+
}
|
|
1509
|
+
getStrokePosition(block) {
|
|
1510
|
+
return this.#engine.getStrokePosition(block);
|
|
1511
|
+
}
|
|
1512
|
+
setStrokePosition(block, position) {
|
|
1513
|
+
this.#engine.setStrokePosition(block, position);
|
|
1514
|
+
}
|
|
1515
|
+
getStrokeCornerGeometry(block) {
|
|
1516
|
+
return this.#engine.getStrokeCornerGeometry(block);
|
|
1517
|
+
}
|
|
1518
|
+
setStrokeCornerGeometry(block, geometry) {
|
|
1519
|
+
this.#engine.setStrokeCornerGeometry(block, geometry);
|
|
1520
|
+
}
|
|
1521
|
+
// ─── Stroke caps + dash pattern (line shapes / dashed strokes) ──────────────
|
|
1522
|
+
getStrokeCap(block) {
|
|
1523
|
+
return this.#engine.getStrokeCap(block);
|
|
1524
|
+
}
|
|
1525
|
+
setStrokeCap(block, cap) {
|
|
1526
|
+
this.#engine.setStrokeCap(block, cap);
|
|
1527
|
+
}
|
|
1528
|
+
getStrokeStartCap(block) {
|
|
1529
|
+
return this.#engine.getStrokeStartCap(block);
|
|
1530
|
+
}
|
|
1531
|
+
setStrokeStartCap(block, cap) {
|
|
1532
|
+
this.#engine.setStrokeStartCap(block, cap);
|
|
1533
|
+
}
|
|
1534
|
+
getStrokeEndCap(block) {
|
|
1535
|
+
return this.#engine.getStrokeEndCap(block);
|
|
1536
|
+
}
|
|
1537
|
+
setStrokeEndCap(block, cap) {
|
|
1538
|
+
this.#engine.setStrokeEndCap(block, cap);
|
|
1539
|
+
}
|
|
1540
|
+
getStrokeDashStartCap(block) {
|
|
1541
|
+
return this.#engine.getStrokeDashStartCap(block);
|
|
1542
|
+
}
|
|
1543
|
+
setStrokeDashStartCap(block, cap) {
|
|
1544
|
+
this.#engine.setStrokeDashStartCap(block, cap);
|
|
1545
|
+
}
|
|
1546
|
+
getStrokeDashEndCap(block) {
|
|
1547
|
+
return this.#engine.getStrokeDashEndCap(block);
|
|
1548
|
+
}
|
|
1549
|
+
setStrokeDashEndCap(block, cap) {
|
|
1550
|
+
this.#engine.setStrokeDashEndCap(block, cap);
|
|
1551
|
+
}
|
|
1552
|
+
getStrokeDashArray(block) {
|
|
1553
|
+
return this.#engine.getStrokeDashArray(block);
|
|
1554
|
+
}
|
|
1555
|
+
setStrokeDashArray(block, dashArray) {
|
|
1556
|
+
this.#engine.setStrokeDashArray(block, dashArray);
|
|
1557
|
+
}
|
|
1558
|
+
getStrokeDashOffset(block) {
|
|
1559
|
+
return this.#engine.getStrokeDashOffset(block);
|
|
1560
|
+
}
|
|
1561
|
+
setStrokeDashOffset(block, dashOffset) {
|
|
1562
|
+
this.#engine.setStrokeDashOffset(block, dashOffset);
|
|
1563
|
+
}
|
|
1564
|
+
isLineOrigin(block) {
|
|
1565
|
+
return this.#engine.isLineOrigin(block);
|
|
1566
|
+
}
|
|
1567
|
+
getStrokeColorRGBA(block) {
|
|
1568
|
+
return this.#engine.getStrokeColorRGBA(block);
|
|
1569
|
+
}
|
|
1570
|
+
setStrokeColorRGBA(block, r, g, b, a) {
|
|
1571
|
+
this.#engine.setStrokeColorRGBA(block, r, g, b, a);
|
|
1572
|
+
}
|
|
1573
|
+
// Effects
|
|
1574
|
+
supportsEffects(block) {
|
|
1575
|
+
return this.#engine.supportsEffects(block);
|
|
1576
|
+
}
|
|
1577
|
+
hasEffects(block) {
|
|
1578
|
+
return this.#engine.hasEffects(block);
|
|
1579
|
+
}
|
|
1580
|
+
getEffects(block) {
|
|
1581
|
+
return this.#engine.getEffects(block);
|
|
1582
|
+
}
|
|
1583
|
+
appendEffect(block, effect) {
|
|
1584
|
+
this.#engine.appendEffect(block, effect);
|
|
1585
|
+
}
|
|
1586
|
+
insertEffect(block, effect, index) {
|
|
1587
|
+
this.#engine.insertEffect(block, effect, index);
|
|
1588
|
+
}
|
|
1589
|
+
removeEffect(block, index) {
|
|
1590
|
+
this.#engine.removeEffect(block, index);
|
|
1591
|
+
}
|
|
1592
|
+
isEffectEnabled(effect) {
|
|
1593
|
+
return this.#engine.isEffectEnabled(effect);
|
|
1594
|
+
}
|
|
1595
|
+
hasEffectEnabled(effect) {
|
|
1596
|
+
return this.isEffectEnabled(effect);
|
|
1597
|
+
}
|
|
1598
|
+
setEffectEnabled(effect, enabled) {
|
|
1599
|
+
this.#engine.setEffectEnabled(effect, enabled);
|
|
1600
|
+
}
|
|
1601
|
+
// Blur - WASM API uses isBlurEnabled
|
|
1602
|
+
supportsBlur(block) {
|
|
1603
|
+
return this.#engine.supportsBlur(block);
|
|
1604
|
+
}
|
|
1605
|
+
hasBlur(block) {
|
|
1606
|
+
return this.#engine.hasBlur(block);
|
|
1607
|
+
}
|
|
1608
|
+
getBlur(block) {
|
|
1609
|
+
return this.#engine.getBlur(block);
|
|
1610
|
+
}
|
|
1611
|
+
setBlur(block, blur) {
|
|
1612
|
+
this.#engine.setBlur(block, blur);
|
|
1613
|
+
}
|
|
1614
|
+
getBlurEnabled(block) {
|
|
1615
|
+
return this.#engine.getBlurEnabled(block);
|
|
1616
|
+
}
|
|
1617
|
+
isBlurEnabled(block) {
|
|
1618
|
+
return this.#engine.getBlurEnabled(block);
|
|
1619
|
+
}
|
|
1620
|
+
setBlurEnabled(block, enabled) {
|
|
1621
|
+
this.#engine.setBlurEnabled(block, enabled);
|
|
1622
|
+
}
|
|
1623
|
+
// Shape
|
|
1624
|
+
supportsShape(block) {
|
|
1625
|
+
return this.#engine.supportsShape(block);
|
|
1626
|
+
}
|
|
1627
|
+
getShape(block) {
|
|
1628
|
+
return this.#engine.getShape(block);
|
|
1629
|
+
}
|
|
1630
|
+
setShape(block, shape) {
|
|
1631
|
+
this.#engine.setShape(block, shape);
|
|
1632
|
+
}
|
|
1633
|
+
hasShape(block) {
|
|
1634
|
+
return this.supportsShape(block);
|
|
1635
|
+
}
|
|
1636
|
+
// Animation
|
|
1637
|
+
supportsAnimation(block) {
|
|
1638
|
+
return this.#engine.supportsAnimation(block);
|
|
1639
|
+
}
|
|
1640
|
+
getInAnimation(block) {
|
|
1641
|
+
return this.#engine.getInAnimation(block);
|
|
1642
|
+
}
|
|
1643
|
+
setInAnimation(block, animation) {
|
|
1644
|
+
this.#engine.setInAnimation(block, animation);
|
|
1645
|
+
}
|
|
1646
|
+
getOutAnimation(block) {
|
|
1647
|
+
return this.#engine.getOutAnimation(block);
|
|
1648
|
+
}
|
|
1649
|
+
setOutAnimation(block, animation) {
|
|
1650
|
+
this.#engine.setOutAnimation(block, animation);
|
|
1651
|
+
}
|
|
1652
|
+
getLoopAnimation(block) {
|
|
1653
|
+
return this.#engine.getLoopAnimation(block);
|
|
1654
|
+
}
|
|
1655
|
+
setLoopAnimation(block, animation) {
|
|
1656
|
+
this.#engine.setLoopAnimation(block, animation);
|
|
1657
|
+
}
|
|
1658
|
+
// Content fill mode - WASM also has hasContentFillMode
|
|
1659
|
+
supportsContentFillMode(block) {
|
|
1660
|
+
return this.#engine.supportsContentFillMode(block);
|
|
1661
|
+
}
|
|
1662
|
+
hasContentFillMode(block) {
|
|
1663
|
+
return this.supportsContentFillMode(block);
|
|
1664
|
+
}
|
|
1665
|
+
getContentFillMode(block) {
|
|
1666
|
+
return this.#engine.getContentFillMode(block);
|
|
1667
|
+
}
|
|
1668
|
+
setContentFillMode(block, mode) {
|
|
1669
|
+
this.#engine.setContentFillMode(block, mode);
|
|
1670
|
+
}
|
|
1671
|
+
// Content-fill alignment — applies to `Contain` / `Cover` fill modes.
|
|
1672
|
+
// Has no visible effect in `Crop`.
|
|
1673
|
+
setContentFillHorizontalAlignment(block, alignment) {
|
|
1674
|
+
this.#engine.setContentFillHorizontalAlignment(block, alignment);
|
|
1675
|
+
}
|
|
1676
|
+
getContentFillHorizontalAlignment(block) {
|
|
1677
|
+
return this.#engine.getContentFillHorizontalAlignment(
|
|
1678
|
+
block
|
|
1679
|
+
);
|
|
1680
|
+
}
|
|
1681
|
+
setContentFillVerticalAlignment(block, alignment) {
|
|
1682
|
+
this.#engine.setContentFillVerticalAlignment(block, alignment);
|
|
1683
|
+
}
|
|
1684
|
+
getContentFillVerticalAlignment(block) {
|
|
1685
|
+
return this.#engine.getContentFillVerticalAlignment(
|
|
1686
|
+
block
|
|
1687
|
+
);
|
|
1688
|
+
}
|
|
1689
|
+
// Crop - WASM also has hasCrop
|
|
1690
|
+
supportsCrop(block) {
|
|
1691
|
+
return this.#engine.supportsCrop(block);
|
|
1692
|
+
}
|
|
1693
|
+
hasCrop(block) {
|
|
1694
|
+
return this.supportsCrop(block);
|
|
1695
|
+
}
|
|
1696
|
+
resetCrop(block) {
|
|
1697
|
+
this.#engine.resetCrop(block);
|
|
1698
|
+
}
|
|
1699
|
+
// Match @cesdk/node — accept the `minScaleRatio` argument. The C++ binding
|
|
1700
|
+
// already forwards it (defaults to 1.0 when omitted, see
|
|
1701
|
+
// engine_binding_impl/appearance.cpp). The engine returns void; the WASM
|
|
1702
|
+
// wrapper's `: number` declaration is a typing artefact (it forwards an
|
|
1703
|
+
// `unpackResult` of a `Result<void>`, which is `undefined` at runtime), so
|
|
1704
|
+
// native stays honest with `: void`.
|
|
1705
|
+
adjustCropToFillFrame(block, minScaleRatio) {
|
|
1706
|
+
this.#engine.adjustCropToFillFrame(block, minScaleRatio);
|
|
1707
|
+
}
|
|
1708
|
+
getCropRotation(block) {
|
|
1709
|
+
return this.#engine.getCropRotation(block);
|
|
1710
|
+
}
|
|
1711
|
+
setCropRotation(block, rotation) {
|
|
1712
|
+
this.#engine.setCropRotation(block, rotation);
|
|
1713
|
+
}
|
|
1714
|
+
getCropScaleX(block) {
|
|
1715
|
+
return this.#engine.getCropScaleX(block);
|
|
1716
|
+
}
|
|
1717
|
+
setCropScaleX(block, scale) {
|
|
1718
|
+
this.#engine.setCropScaleX(block, scale);
|
|
1719
|
+
}
|
|
1720
|
+
getCropScaleY(block) {
|
|
1721
|
+
return this.#engine.getCropScaleY(block);
|
|
1722
|
+
}
|
|
1723
|
+
setCropScaleY(block, scale) {
|
|
1724
|
+
this.#engine.setCropScaleY(block, scale);
|
|
1725
|
+
}
|
|
1726
|
+
getCropScaleRatio(block) {
|
|
1727
|
+
return this.#engine.getCropScaleRatio(block);
|
|
1728
|
+
}
|
|
1729
|
+
setCropScaleRatio(block, ratio) {
|
|
1730
|
+
this.#engine.setCropScaleRatio(block, ratio);
|
|
1731
|
+
}
|
|
1732
|
+
getCropTranslationX(block) {
|
|
1733
|
+
return this.#engine.getCropTranslationX(block);
|
|
1734
|
+
}
|
|
1735
|
+
setCropTranslationX(block, translation) {
|
|
1736
|
+
this.#engine.setCropTranslationX(block, translation);
|
|
1737
|
+
}
|
|
1738
|
+
getCropTranslationY(block) {
|
|
1739
|
+
return this.#engine.getCropTranslationY(block);
|
|
1740
|
+
}
|
|
1741
|
+
setCropTranslationY(block, translation) {
|
|
1742
|
+
this.#engine.setCropTranslationY(block, translation);
|
|
1743
|
+
}
|
|
1744
|
+
isCropAspectRatioLocked(block) {
|
|
1745
|
+
return this.#engine.isCropAspectRatioLocked(block);
|
|
1746
|
+
}
|
|
1747
|
+
setCropAspectRatioLocked(block, locked) {
|
|
1748
|
+
this.#engine.setCropAspectRatioLocked(block, locked);
|
|
1749
|
+
}
|
|
1750
|
+
flipCropHorizontal(block) {
|
|
1751
|
+
this.#engine.flipCropHorizontal(block);
|
|
1752
|
+
}
|
|
1753
|
+
flipCropVertical(block) {
|
|
1754
|
+
this.#engine.flipCropVertical(block);
|
|
1755
|
+
}
|
|
1756
|
+
// Drop shadow
|
|
1757
|
+
supportsDropShadow(block) {
|
|
1758
|
+
return this.#engine.supportsDropShadow(block);
|
|
1759
|
+
}
|
|
1760
|
+
hasDropShadow(block) {
|
|
1761
|
+
return this.supportsDropShadow(block);
|
|
1762
|
+
}
|
|
1763
|
+
isDropShadowEnabled(block) {
|
|
1764
|
+
return this.#engine.isDropShadowEnabled(block);
|
|
1765
|
+
}
|
|
1766
|
+
setDropShadowEnabled(block, enabled) {
|
|
1767
|
+
this.#engine.setDropShadowEnabled(block, enabled);
|
|
1768
|
+
}
|
|
1769
|
+
getDropShadowColor(block) {
|
|
1770
|
+
const internalColor = this.#engine.getDropShadowColor(
|
|
1771
|
+
block
|
|
1772
|
+
);
|
|
1773
|
+
return NativeColorInternal.toColor(internalColor);
|
|
1774
|
+
}
|
|
1775
|
+
setDropShadowColor(block, color) {
|
|
1776
|
+
const internalColor = NativeColorInternal.fromColor(color);
|
|
1777
|
+
this.#engine.setDropShadowColor(block, internalColor);
|
|
1778
|
+
}
|
|
1779
|
+
getDropShadowColorRGBA(block) {
|
|
1780
|
+
return this.#engine.getDropShadowColorRGBA(block);
|
|
1781
|
+
}
|
|
1782
|
+
setDropShadowColorRGBA(block, r, g, b, a) {
|
|
1783
|
+
this.#engine.setDropShadowColorRGBA(block, r, g, b, a);
|
|
1784
|
+
}
|
|
1785
|
+
getDropShadowOffsetX(block) {
|
|
1786
|
+
return this.#engine.getDropShadowOffsetX(block);
|
|
1787
|
+
}
|
|
1788
|
+
setDropShadowOffsetX(block, offset) {
|
|
1789
|
+
this.#engine.setDropShadowOffsetX(block, offset);
|
|
1790
|
+
}
|
|
1791
|
+
getDropShadowOffsetY(block) {
|
|
1792
|
+
return this.#engine.getDropShadowOffsetY(block);
|
|
1793
|
+
}
|
|
1794
|
+
setDropShadowOffsetY(block, offset) {
|
|
1795
|
+
this.#engine.setDropShadowOffsetY(block, offset);
|
|
1796
|
+
}
|
|
1797
|
+
getDropShadowBlurRadiusX(block) {
|
|
1798
|
+
return this.#engine.getDropShadowBlurRadiusX(block);
|
|
1799
|
+
}
|
|
1800
|
+
setDropShadowBlurRadiusX(block, radius) {
|
|
1801
|
+
this.#engine.setDropShadowBlurRadiusX(block, radius);
|
|
1802
|
+
}
|
|
1803
|
+
getDropShadowBlurRadiusY(block) {
|
|
1804
|
+
return this.#engine.getDropShadowBlurRadiusY(block);
|
|
1805
|
+
}
|
|
1806
|
+
setDropShadowBlurRadiusY(block, radius) {
|
|
1807
|
+
this.#engine.setDropShadowBlurRadiusY(block, radius);
|
|
1808
|
+
}
|
|
1809
|
+
getDropShadowClip(block) {
|
|
1810
|
+
return this.#engine.getDropShadowClip(block);
|
|
1811
|
+
}
|
|
1812
|
+
setDropShadowClip(block, clip) {
|
|
1813
|
+
this.#engine.setDropShadowClip(block, clip);
|
|
1814
|
+
}
|
|
1815
|
+
// Blend mode
|
|
1816
|
+
supportsBlendMode(block) {
|
|
1817
|
+
return this.#engine.supportsBlendMode(block);
|
|
1818
|
+
}
|
|
1819
|
+
getBlendMode(block) {
|
|
1820
|
+
return this.#engine.getBlendMode(block);
|
|
1821
|
+
}
|
|
1822
|
+
setBlendMode(block, mode) {
|
|
1823
|
+
this.#engine.setBlendMode(block, mode);
|
|
1824
|
+
}
|
|
1825
|
+
hasBlendMode(block) {
|
|
1826
|
+
return this.supportsBlendMode(block);
|
|
1827
|
+
}
|
|
1828
|
+
// Opacity
|
|
1829
|
+
supportsOpacity(block) {
|
|
1830
|
+
return this.#engine.supportsOpacity(block);
|
|
1831
|
+
}
|
|
1832
|
+
hasOpacity(block) {
|
|
1833
|
+
return this.supportsOpacity(block);
|
|
1834
|
+
}
|
|
1835
|
+
getOpacity(block) {
|
|
1836
|
+
return this.#engine.getOpacity(block);
|
|
1837
|
+
}
|
|
1838
|
+
setOpacity(block, opacity) {
|
|
1839
|
+
this.#engine.setOpacity(block, opacity);
|
|
1840
|
+
}
|
|
1841
|
+
// Visibility
|
|
1842
|
+
getVisible(block) {
|
|
1843
|
+
return this.#engine.getVisible(block);
|
|
1844
|
+
}
|
|
1845
|
+
isVisible(block) {
|
|
1846
|
+
return this.#engine.getVisible(block);
|
|
1847
|
+
}
|
|
1848
|
+
setVisible(block, visible) {
|
|
1849
|
+
this.#engine.setVisible(block, visible);
|
|
1850
|
+
}
|
|
1851
|
+
getClipped(block) {
|
|
1852
|
+
return this.#engine.getClipped(block);
|
|
1853
|
+
}
|
|
1854
|
+
isClipped(block) {
|
|
1855
|
+
return this.#engine.getClipped(block);
|
|
1856
|
+
}
|
|
1857
|
+
setClipped(block, clipped) {
|
|
1858
|
+
this.#engine.setClipped(block, clipped);
|
|
1859
|
+
}
|
|
1860
|
+
// Selection
|
|
1861
|
+
setSelected(block, selected) {
|
|
1862
|
+
this.#engine.setSelected(block, selected);
|
|
1863
|
+
}
|
|
1864
|
+
isSelected(block) {
|
|
1865
|
+
return this.#engine.isSelected(block);
|
|
1866
|
+
}
|
|
1867
|
+
select(block) {
|
|
1868
|
+
this.#engine.select(block);
|
|
1869
|
+
}
|
|
1870
|
+
// Ordering
|
|
1871
|
+
bringToFront(block) {
|
|
1872
|
+
this.#engine.bringToFront(block);
|
|
1873
|
+
}
|
|
1874
|
+
sendToBack(block) {
|
|
1875
|
+
this.#engine.sendToBack(block);
|
|
1876
|
+
}
|
|
1877
|
+
bringForward(block) {
|
|
1878
|
+
this.#engine.bringForward(block);
|
|
1879
|
+
}
|
|
1880
|
+
sendBackward(block) {
|
|
1881
|
+
this.#engine.sendBackward(block);
|
|
1882
|
+
}
|
|
1883
|
+
setAlwaysOnTop(block, enabled) {
|
|
1884
|
+
this.#engine.setAlwaysOnTop(block, enabled);
|
|
1885
|
+
}
|
|
1886
|
+
setAlwaysOnBottom(block, enabled) {
|
|
1887
|
+
this.#engine.setAlwaysOnBottom(block, enabled);
|
|
1888
|
+
}
|
|
1889
|
+
isAlwaysOnTop(block) {
|
|
1890
|
+
return this.#engine.isAlwaysOnTop(block);
|
|
1891
|
+
}
|
|
1892
|
+
isAlwaysOnBottom(block) {
|
|
1893
|
+
return this.#engine.isAlwaysOnBottom(block);
|
|
1894
|
+
}
|
|
1895
|
+
// Alignment and distribution
|
|
1896
|
+
alignHorizontally(blocks, alignment) {
|
|
1897
|
+
this.#engine.alignHorizontally(blocks, alignment);
|
|
1898
|
+
}
|
|
1899
|
+
alignVertically(blocks, alignment) {
|
|
1900
|
+
this.#engine.alignVertically(blocks, alignment);
|
|
1901
|
+
}
|
|
1902
|
+
isAlignable(blocks) {
|
|
1903
|
+
return this.#engine.isAlignable(blocks);
|
|
1904
|
+
}
|
|
1905
|
+
distributeHorizontally(blocks) {
|
|
1906
|
+
this.#engine.distributeHorizontally(blocks);
|
|
1907
|
+
}
|
|
1908
|
+
distributeVertically(blocks) {
|
|
1909
|
+
this.#engine.distributeVertically(blocks);
|
|
1910
|
+
}
|
|
1911
|
+
isDistributable(blocks) {
|
|
1912
|
+
return this.#engine.isDistributable(blocks);
|
|
1913
|
+
}
|
|
1914
|
+
// Grouping
|
|
1915
|
+
group(blocks) {
|
|
1916
|
+
return this.#engine.group(blocks);
|
|
1917
|
+
}
|
|
1918
|
+
ungroup(group) {
|
|
1919
|
+
this.#engine.ungroup(group);
|
|
1920
|
+
}
|
|
1921
|
+
isGroupable(blocks) {
|
|
1922
|
+
return this.#engine.isGroupable(blocks);
|
|
1923
|
+
}
|
|
1924
|
+
enterGroup(group) {
|
|
1925
|
+
this.#engine.enterGroup(group);
|
|
1926
|
+
}
|
|
1927
|
+
exitGroup(block) {
|
|
1928
|
+
this.#engine.exitGroup(block);
|
|
1929
|
+
}
|
|
1930
|
+
// Combine
|
|
1931
|
+
combine(blocks, operation) {
|
|
1932
|
+
const validOps = ["Union", "Difference", "Intersection", "XOR"];
|
|
1933
|
+
if (!validOps.includes(operation)) {
|
|
1934
|
+
throw new Error(`Unknown boolean operation: ${operation}`);
|
|
1935
|
+
}
|
|
1936
|
+
return this.#engine.combine(blocks, operation);
|
|
1937
|
+
}
|
|
1938
|
+
isCombinable(blocks) {
|
|
1939
|
+
return this.#engine.isCombinable(blocks);
|
|
1940
|
+
}
|
|
1941
|
+
// Duration/Timeline
|
|
1942
|
+
supportsDuration(block) {
|
|
1943
|
+
return this.#engine.supportsDuration(block);
|
|
1944
|
+
}
|
|
1945
|
+
hasDuration(block) {
|
|
1946
|
+
return this.supportsDuration(block);
|
|
1947
|
+
}
|
|
1948
|
+
getDuration(block) {
|
|
1949
|
+
return this.#engine.getDuration(block);
|
|
1950
|
+
}
|
|
1951
|
+
setDuration(block, duration) {
|
|
1952
|
+
this.#engine.setDuration(block, duration);
|
|
1953
|
+
}
|
|
1954
|
+
supportsTimeOffset(block) {
|
|
1955
|
+
return this.#engine.supportsTimeOffset(block);
|
|
1956
|
+
}
|
|
1957
|
+
hasTimeOffset(block) {
|
|
1958
|
+
return this.supportsTimeOffset(block);
|
|
1959
|
+
}
|
|
1960
|
+
getTimeOffset(block) {
|
|
1961
|
+
return this.#engine.getTimeOffset(block);
|
|
1962
|
+
}
|
|
1963
|
+
setTimeOffset(block, offset) {
|
|
1964
|
+
this.#engine.setTimeOffset(block, offset);
|
|
1965
|
+
}
|
|
1966
|
+
supportsTrim(block) {
|
|
1967
|
+
return this.#engine.supportsTrim(block);
|
|
1968
|
+
}
|
|
1969
|
+
hasTrim(block) {
|
|
1970
|
+
return this.supportsTrim(block);
|
|
1971
|
+
}
|
|
1972
|
+
getTrimOffset(block) {
|
|
1973
|
+
return this.#engine.getTrimOffset(block);
|
|
1974
|
+
}
|
|
1975
|
+
setTrimOffset(block, offset) {
|
|
1976
|
+
this.#engine.setTrimOffset(block, offset);
|
|
1977
|
+
}
|
|
1978
|
+
getTrimLength(block) {
|
|
1979
|
+
return this.#engine.getTrimLength(block);
|
|
1980
|
+
}
|
|
1981
|
+
setTrimLength(block, length) {
|
|
1982
|
+
this.#engine.setTrimLength(block, length);
|
|
1983
|
+
}
|
|
1984
|
+
// Playback
|
|
1985
|
+
supportsPlaybackControl(block) {
|
|
1986
|
+
return this.#engine.supportsPlaybackControl(block);
|
|
1987
|
+
}
|
|
1988
|
+
hasPlaybackControl(block) {
|
|
1989
|
+
return this.supportsPlaybackControl(block);
|
|
1990
|
+
}
|
|
1991
|
+
supportsPlaybackTime(block) {
|
|
1992
|
+
return this.#engine.supportsPlaybackTime(block);
|
|
1993
|
+
}
|
|
1994
|
+
hasPlaybackTime(block) {
|
|
1995
|
+
return this.supportsPlaybackTime(block);
|
|
1996
|
+
}
|
|
1997
|
+
getPlaybackTime(block) {
|
|
1998
|
+
return this.#engine.getPlaybackTime(block);
|
|
1999
|
+
}
|
|
2000
|
+
setPlaybackTime(block, time) {
|
|
2001
|
+
this.#engine.setPlaybackTime(block, time);
|
|
2002
|
+
}
|
|
2003
|
+
isPlaying(block) {
|
|
2004
|
+
return this.#engine.isPlaying(block);
|
|
2005
|
+
}
|
|
2006
|
+
setPlaying(block, playing) {
|
|
2007
|
+
this.#engine.setPlaying(block, playing);
|
|
2008
|
+
}
|
|
2009
|
+
isLooping(block) {
|
|
2010
|
+
return this.#engine.isLooping(block);
|
|
2011
|
+
}
|
|
2012
|
+
setLooping(block, looping) {
|
|
2013
|
+
this.#engine.setLooping(block, looping);
|
|
2014
|
+
}
|
|
2015
|
+
getPlaybackSpeed(block) {
|
|
2016
|
+
return this.#engine.getPlaybackSpeed(block);
|
|
2017
|
+
}
|
|
2018
|
+
setPlaybackSpeed(block, speed) {
|
|
2019
|
+
this.#engine.setPlaybackSpeed(block, speed);
|
|
2020
|
+
}
|
|
2021
|
+
isMuted(block) {
|
|
2022
|
+
return this.#engine.isMuted(block);
|
|
2023
|
+
}
|
|
2024
|
+
setMuted(block, muted) {
|
|
2025
|
+
this.#engine.setMuted(block, muted);
|
|
2026
|
+
}
|
|
2027
|
+
getVolume(block) {
|
|
2028
|
+
return this.#engine.getVolume(block);
|
|
2029
|
+
}
|
|
2030
|
+
setVolume(block, volume) {
|
|
2031
|
+
this.#engine.setVolume(block, volume);
|
|
2032
|
+
}
|
|
2033
|
+
isSoloPlaybackEnabled(block) {
|
|
2034
|
+
return this.#engine.isSoloPlaybackEnabled(block);
|
|
2035
|
+
}
|
|
2036
|
+
setSoloPlaybackEnabled(block, enabled) {
|
|
2037
|
+
this.#engine.setSoloPlaybackEnabled(block, enabled);
|
|
2038
|
+
}
|
|
2039
|
+
isForceMuted(block) {
|
|
2040
|
+
return this.#engine.isForceMuted(block);
|
|
2041
|
+
}
|
|
2042
|
+
getTotalSceneDuration(scene) {
|
|
2043
|
+
return this.#engine.getTotalSceneDuration(scene);
|
|
2044
|
+
}
|
|
2045
|
+
isVisibleAtCurrentPlaybackTime(block) {
|
|
2046
|
+
return this.#engine.isVisibleAtCurrentPlaybackTime(block);
|
|
2047
|
+
}
|
|
2048
|
+
// Locking
|
|
2049
|
+
isTransformLocked(block) {
|
|
2050
|
+
return this.#engine.isTransformLocked(block);
|
|
2051
|
+
}
|
|
2052
|
+
setTransformLocked(block, locked) {
|
|
2053
|
+
this.#engine.setTransformLocked(block, locked);
|
|
2054
|
+
}
|
|
2055
|
+
// Include in export
|
|
2056
|
+
isIncludedInExport(block) {
|
|
2057
|
+
return this.#engine.isIncludedInExport(block);
|
|
2058
|
+
}
|
|
2059
|
+
setIncludedInExport(block, included) {
|
|
2060
|
+
this.#engine.setIncludedInExport(block, included);
|
|
2061
|
+
}
|
|
2062
|
+
// Placeholder
|
|
2063
|
+
isPlaceholderEnabled(block) {
|
|
2064
|
+
return this.#engine.isPlaceholderEnabled(block);
|
|
2065
|
+
}
|
|
2066
|
+
setPlaceholderEnabled(block, enabled) {
|
|
2067
|
+
this.#engine.setPlaceholderEnabled(block, enabled);
|
|
2068
|
+
}
|
|
2069
|
+
supportsPlaceholderBehavior(block) {
|
|
2070
|
+
return this.#engine.supportsPlaceholderBehavior(block);
|
|
2071
|
+
}
|
|
2072
|
+
hasPlaceholderBehavior(block) {
|
|
2073
|
+
return this.supportsPlaceholderBehavior(block);
|
|
2074
|
+
}
|
|
2075
|
+
isPlaceholderBehaviorEnabled(block) {
|
|
2076
|
+
return this.#engine.isPlaceholderBehaviorEnabled(block);
|
|
2077
|
+
}
|
|
2078
|
+
setPlaceholderBehaviorEnabled(block, enabled) {
|
|
2079
|
+
this.#engine.setPlaceholderBehaviorEnabled(block, enabled);
|
|
2080
|
+
}
|
|
2081
|
+
supportsPlaceholderControls(block) {
|
|
2082
|
+
return this.#engine.supportsPlaceholderControls(block);
|
|
2083
|
+
}
|
|
2084
|
+
hasPlaceholderControls(block) {
|
|
2085
|
+
return this.supportsPlaceholderControls(block);
|
|
2086
|
+
}
|
|
2087
|
+
isPlaceholderControlsOverlayEnabled(block) {
|
|
2088
|
+
return this.#engine.isPlaceholderControlsOverlayEnabled(block);
|
|
2089
|
+
}
|
|
2090
|
+
setPlaceholderControlsOverlayEnabled(block, enabled) {
|
|
2091
|
+
this.#engine.setPlaceholderControlsOverlayEnabled(block, enabled);
|
|
2092
|
+
}
|
|
2093
|
+
isPlaceholderControlsButtonEnabled(block) {
|
|
2094
|
+
return this.#engine.isPlaceholderControlsButtonEnabled(block);
|
|
2095
|
+
}
|
|
2096
|
+
setPlaceholderControlsButtonEnabled(block, enabled) {
|
|
2097
|
+
this.#engine.setPlaceholderControlsButtonEnabled(block, enabled);
|
|
2098
|
+
}
|
|
2099
|
+
// Background color - WASM also has hasBackgroundColor and RGBA methods
|
|
2100
|
+
supportsBackgroundColor(block) {
|
|
2101
|
+
return this.#engine.supportsBackgroundColor(block);
|
|
2102
|
+
}
|
|
2103
|
+
hasBackgroundColor(block) {
|
|
2104
|
+
return this.supportsBackgroundColor(block);
|
|
2105
|
+
}
|
|
2106
|
+
isBackgroundColorEnabled(block) {
|
|
2107
|
+
return this.#engine.isBackgroundColorEnabled(block);
|
|
2108
|
+
}
|
|
2109
|
+
setBackgroundColorEnabled(block, enabled) {
|
|
2110
|
+
this.#engine.setBackgroundColorEnabled(block, enabled);
|
|
2111
|
+
}
|
|
2112
|
+
getBackgroundColorRGBA(block) {
|
|
2113
|
+
const internalColor = this.#engine.getColor(
|
|
2114
|
+
block,
|
|
2115
|
+
"backgroundColor"
|
|
2116
|
+
);
|
|
2117
|
+
const color = NativeColorInternal.toColor(internalColor);
|
|
2118
|
+
if (!isRGBAColor2(color)) {
|
|
2119
|
+
throw new Error("Expected RGBA color for background color");
|
|
2120
|
+
}
|
|
2121
|
+
return { r: color.r, g: color.g, b: color.b, a: color.a };
|
|
2122
|
+
}
|
|
2123
|
+
setBackgroundColorRGBA(block, r, g, b, a) {
|
|
2124
|
+
this.setColor(block, "backgroundColor", { r, g, b, a });
|
|
2125
|
+
}
|
|
2126
|
+
// Metadata
|
|
2127
|
+
hasMetadata(block, key) {
|
|
2128
|
+
return this.#engine.hasMetadata(block, key);
|
|
2129
|
+
}
|
|
2130
|
+
getMetadata(block, key) {
|
|
2131
|
+
return this.#engine.getMetadata(block, key);
|
|
2132
|
+
}
|
|
2133
|
+
setMetadata(block, key, value) {
|
|
2134
|
+
this.#engine.setMetadata(block, key, value);
|
|
2135
|
+
}
|
|
2136
|
+
removeMetadata(block, key) {
|
|
2137
|
+
this.#engine.removeMetadata(block, key);
|
|
2138
|
+
}
|
|
2139
|
+
findAllMetadata(block) {
|
|
2140
|
+
return this.#engine.findAllMetadata(block);
|
|
2141
|
+
}
|
|
2142
|
+
// ==========================================================================
|
|
2143
|
+
// Text — range-aware methods accept UTF-16 indices (`from`/`to`) like WASM.
|
|
2144
|
+
// The wrapper looks up the current text and converts to grapheme indices via
|
|
2145
|
+
// `convertUTF16ToGraphemeRange` before forwarding to the engine.
|
|
2146
|
+
// ==========================================================================
|
|
2147
|
+
/**
|
|
2148
|
+
* Resolve UTF-16 `from`/`to` to engine grapheme range. Returns the original
|
|
2149
|
+
* range when both ends are negative ("fall back to current selection / full
|
|
2150
|
+
* text"), so we avoid the engine round-trip when the caller didn't ask for
|
|
2151
|
+
* a sub-range.
|
|
2152
|
+
*/
|
|
2153
|
+
#toGraphemeRange(block, from, to) {
|
|
2154
|
+
if (from < 0 && to < 0) return { from, to };
|
|
2155
|
+
let text = "";
|
|
2156
|
+
try {
|
|
2157
|
+
text = this.#engine.getString(block, "text/text");
|
|
2158
|
+
} catch {
|
|
2159
|
+
return { from, to };
|
|
2160
|
+
}
|
|
2161
|
+
return convertUTF16ToGraphemeRange(text, from, to);
|
|
2162
|
+
}
|
|
2163
|
+
replaceText(block, text, from = -1, to = -1) {
|
|
2164
|
+
const range = this.#toGraphemeRange(block, from, to);
|
|
2165
|
+
this.#engine.replaceText(block, text, range.from, range.to);
|
|
2166
|
+
}
|
|
2167
|
+
removeText(block, from = -1, to = -1) {
|
|
2168
|
+
const range = this.#toGraphemeRange(block, from, to);
|
|
2169
|
+
this.#engine.removeText(block, range.from, range.to);
|
|
2170
|
+
}
|
|
2171
|
+
getTextFontSizes(block, fromOrOptions, to = -1) {
|
|
2172
|
+
let from = -1;
|
|
2173
|
+
let optTo = to;
|
|
2174
|
+
let unit = "Point";
|
|
2175
|
+
if (typeof fromOrOptions === "object" && fromOrOptions !== null) {
|
|
2176
|
+
from = fromOrOptions.from ?? -1;
|
|
2177
|
+
optTo = fromOrOptions.to ?? -1;
|
|
2178
|
+
unit = fromOrOptions.unit ?? "Point";
|
|
2179
|
+
} else if (typeof fromOrOptions === "number") {
|
|
2180
|
+
from = fromOrOptions;
|
|
2181
|
+
}
|
|
2182
|
+
const range = this.#toGraphemeRange(block, from, optTo);
|
|
2183
|
+
const sizesInPoints = this.#engine.getTextFontSizes(
|
|
2184
|
+
block,
|
|
2185
|
+
range.from,
|
|
2186
|
+
range.to
|
|
2187
|
+
);
|
|
2188
|
+
if (unit === "Point") return sizesInPoints;
|
|
2189
|
+
const scenes = this.findByType("//ly.img.ubq/scene");
|
|
2190
|
+
if (scenes.length === 0) {
|
|
2191
|
+
throw new Error("No scene found for unit conversion");
|
|
2192
|
+
}
|
|
2193
|
+
const dpi = this.getFloat(scenes[0], "scene/dpi");
|
|
2194
|
+
return sizesInPoints.map((s) => convertFontSizeFromPoints(s, unit, dpi));
|
|
2195
|
+
}
|
|
2196
|
+
setTextFontSize(block, size, fromOrOptions, to = -1) {
|
|
2197
|
+
let fontSizeInPoints = size;
|
|
2198
|
+
let from = -1;
|
|
2199
|
+
let optTo = to;
|
|
2200
|
+
if (typeof fromOrOptions === "object" && fromOrOptions !== null) {
|
|
2201
|
+
const {
|
|
2202
|
+
unit = "Point",
|
|
2203
|
+
from: optFrom = -1,
|
|
2204
|
+
to: optionsTo = -1
|
|
2205
|
+
} = fromOrOptions;
|
|
2206
|
+
from = optFrom;
|
|
2207
|
+
optTo = optionsTo;
|
|
2208
|
+
if (unit !== "Point") {
|
|
2209
|
+
const scenes = this.findByType("//ly.img.ubq/scene");
|
|
2210
|
+
if (scenes.length === 0) {
|
|
2211
|
+
throw new Error("No scene found for unit conversion");
|
|
2212
|
+
}
|
|
2213
|
+
const dpi = this.getFloat(scenes[0], "scene/dpi");
|
|
2214
|
+
fontSizeInPoints = convertFontSizeToPoints(size, unit, dpi);
|
|
2215
|
+
}
|
|
2216
|
+
} else if (typeof fromOrOptions === "number") {
|
|
2217
|
+
from = fromOrOptions;
|
|
2218
|
+
}
|
|
2219
|
+
const range = this.#toGraphemeRange(block, from, optTo);
|
|
2220
|
+
this.#engine.setTextFontSize(block, fontSizeInPoints, range.from, range.to);
|
|
2221
|
+
}
|
|
2222
|
+
getTextFontStyles(block, from = -1, to = -1) {
|
|
2223
|
+
const range = this.#toGraphemeRange(block, from, to);
|
|
2224
|
+
return this.#engine.getTextFontStyles(block, range.from, range.to);
|
|
2225
|
+
}
|
|
2226
|
+
setTextFontStyle(block, style, from = -1, to = -1) {
|
|
2227
|
+
const range = this.#toGraphemeRange(block, from, to);
|
|
2228
|
+
this.#engine.setTextFontStyle(block, style, range.from, range.to);
|
|
2229
|
+
}
|
|
2230
|
+
getTextFontWeights(block, from = -1, to = -1) {
|
|
2231
|
+
const range = this.#toGraphemeRange(block, from, to);
|
|
2232
|
+
return this.#engine.getTextFontWeights(block, range.from, range.to);
|
|
2233
|
+
}
|
|
2234
|
+
setTextFontWeight(block, weight, from = -1, to = -1) {
|
|
2235
|
+
const range = this.#toGraphemeRange(block, from, to);
|
|
2236
|
+
this.#engine.setTextFontWeight(block, weight, range.from, range.to);
|
|
2237
|
+
}
|
|
2238
|
+
getTextColors(block, from = -1, to = -1) {
|
|
2239
|
+
const range = this.#toGraphemeRange(block, from, to);
|
|
2240
|
+
const internalColors = this.#engine.getTextColors(
|
|
2241
|
+
block,
|
|
2242
|
+
range.from,
|
|
2243
|
+
range.to
|
|
2244
|
+
);
|
|
2245
|
+
return internalColors.map((c) => NativeColorInternal.toColor(c));
|
|
2246
|
+
}
|
|
2247
|
+
setTextColor(block, color, from = -1, to = -1) {
|
|
2248
|
+
const internalColor = NativeColorInternal.fromColor(color);
|
|
2249
|
+
const range = this.#toGraphemeRange(block, from, to);
|
|
2250
|
+
this.#engine.setTextColor(block, internalColor, range.from, range.to);
|
|
2251
|
+
}
|
|
2252
|
+
getTextCases(block, from = -1, to = -1) {
|
|
2253
|
+
const range = this.#toGraphemeRange(block, from, to);
|
|
2254
|
+
return this.#engine.getTextCases(block, range.from, range.to);
|
|
2255
|
+
}
|
|
2256
|
+
setTextCase(block, textCase, from = -1, to = -1) {
|
|
2257
|
+
const range = this.#toGraphemeRange(block, from, to);
|
|
2258
|
+
this.#engine.setTextCase(block, textCase, range.from, range.to);
|
|
2259
|
+
}
|
|
2260
|
+
getTypefaces(block, from, to) {
|
|
2261
|
+
const range = this.#toGraphemeRange(block, from ?? -1, to ?? -1);
|
|
2262
|
+
return this.#engine.getTypefaces(block, range.from, range.to);
|
|
2263
|
+
}
|
|
2264
|
+
setTypeface(block, typeface, from = -1, to = -1) {
|
|
2265
|
+
const range = this.#toGraphemeRange(block, from, to);
|
|
2266
|
+
this.#engine.setTypeface(block, typeface, range.from, range.to);
|
|
2267
|
+
}
|
|
2268
|
+
getTypeface(block) {
|
|
2269
|
+
return this.#engine.getTypeface(block);
|
|
2270
|
+
}
|
|
2271
|
+
/**
|
|
2272
|
+
* Set extra character-level kerning offset for a grapheme range. The
|
|
2273
|
+
* value is in em units (1.0 = one full em); 0.0 resets to no extra
|
|
2274
|
+
* offset. Matches the node wasm binding's `BlockAPI.setTextKerning`.
|
|
2275
|
+
*/
|
|
2276
|
+
setTextKerning(block, kerning, from = -1, to = -1) {
|
|
2277
|
+
const range = this.#toGraphemeRange(block, from, to);
|
|
2278
|
+
this.#engine.setTextKerning(block, kerning, range.from, range.to);
|
|
2279
|
+
}
|
|
2280
|
+
/**
|
|
2281
|
+
* Return the unique kerning values seen across the grapheme range.
|
|
2282
|
+
* Mirrors `getTextFontSizes` / `getTextFontStyles` — `[0]` for a clean
|
|
2283
|
+
* block, `[v1, v2, …]` when the range spans multiple distinct values.
|
|
2284
|
+
*/
|
|
2285
|
+
getTextKernings(block, from, to) {
|
|
2286
|
+
const range = this.#toGraphemeRange(block, from ?? -1, to ?? -1);
|
|
2287
|
+
return this.#engine.getTextKernings(block, range.from, range.to);
|
|
2288
|
+
}
|
|
2289
|
+
setFont(block, fontUri, typeface) {
|
|
2290
|
+
this.#engine.setFont(block, fontUri, typeface);
|
|
2291
|
+
}
|
|
2292
|
+
canToggleBoldFont(block) {
|
|
2293
|
+
return this.#engine.canToggleBoldFont(block);
|
|
2294
|
+
}
|
|
2295
|
+
toggleBoldFont(block) {
|
|
2296
|
+
this.#engine.toggleBoldFont(block);
|
|
2297
|
+
}
|
|
2298
|
+
canToggleItalicFont(block) {
|
|
2299
|
+
return this.#engine.canToggleItalicFont(block);
|
|
2300
|
+
}
|
|
2301
|
+
toggleItalicFont(block) {
|
|
2302
|
+
this.#engine.toggleItalicFont(block);
|
|
2303
|
+
}
|
|
2304
|
+
/**
|
|
2305
|
+
* The text block currently being edited, or `undefined` when not in Text
|
|
2306
|
+
* edit mode. Used to convert between UTF-16 and grapheme indices when
|
|
2307
|
+
* exposing cursor ranges.
|
|
2308
|
+
*/
|
|
2309
|
+
#findActiveTextBlock() {
|
|
2310
|
+
try {
|
|
2311
|
+
const editMode = this.#engine.getEditMode();
|
|
2312
|
+
if (editMode !== "Text") return void 0;
|
|
2313
|
+
} catch {
|
|
2314
|
+
return void 0;
|
|
2315
|
+
}
|
|
2316
|
+
const selected = this.#engine.findAllSelected();
|
|
2317
|
+
for (const block of selected) {
|
|
2318
|
+
try {
|
|
2319
|
+
if (this.#engine.getType(block) === "//ly.img.ubq/text") {
|
|
2320
|
+
return block;
|
|
2321
|
+
}
|
|
2322
|
+
} catch {
|
|
2323
|
+
continue;
|
|
2324
|
+
}
|
|
2325
|
+
}
|
|
2326
|
+
return void 0;
|
|
2327
|
+
}
|
|
2328
|
+
/**
|
|
2329
|
+
* Returns the current text cursor range as UTF-16 indices. When no block
|
|
2330
|
+
* is currently being edited, returns `{ from: -1, to: -1 }`.
|
|
2331
|
+
*/
|
|
2332
|
+
getTextCursorRange() {
|
|
2333
|
+
const grapheme = this.#engine.getTextCursorRange();
|
|
2334
|
+
if (grapheme.from < 0 && grapheme.to < 0) return grapheme;
|
|
2335
|
+
const block = this.#findActiveTextBlock();
|
|
2336
|
+
if (block == null) return grapheme;
|
|
2337
|
+
let text = "";
|
|
2338
|
+
try {
|
|
2339
|
+
text = this.#engine.getString(block, "text/text");
|
|
2340
|
+
} catch {
|
|
2341
|
+
return grapheme;
|
|
2342
|
+
}
|
|
2343
|
+
return convertGraphemeToUTF16Range(text, grapheme.from, grapheme.to);
|
|
2344
|
+
}
|
|
2345
|
+
/**
|
|
2346
|
+
* Sets the text cursor range. `from`/`to` are UTF-16 indices. Negative
|
|
2347
|
+
* values mean "from start" / "to end" (so `{ from: -1, to: -1 }` selects
|
|
2348
|
+
* the entire text).
|
|
2349
|
+
*/
|
|
2350
|
+
setTextCursorRange(range) {
|
|
2351
|
+
const block = this.#findActiveTextBlock();
|
|
2352
|
+
if (block == null) {
|
|
2353
|
+
throw new Error("No text block is currently being edited.");
|
|
2354
|
+
}
|
|
2355
|
+
let { from, to } = range;
|
|
2356
|
+
if (from >= 0 || to >= 0) {
|
|
2357
|
+
const text = this.#engine.getString(block, "text/text");
|
|
2358
|
+
({ from, to } = convertUTF16ToGraphemeRange(text, from, to));
|
|
2359
|
+
}
|
|
2360
|
+
this.#engine.setTextCursorRange(from, to);
|
|
2361
|
+
}
|
|
2362
|
+
getTextCursorPositionInScreenSpaceX(block) {
|
|
2363
|
+
return this.#engine.getTextCursorPositionInScreenSpaceX(block);
|
|
2364
|
+
}
|
|
2365
|
+
getTextCursorPositionInScreenSpaceY(block) {
|
|
2366
|
+
return this.#engine.getTextCursorPositionInScreenSpaceY(block);
|
|
2367
|
+
}
|
|
2368
|
+
getTextVisibleLineCount(block) {
|
|
2369
|
+
return this.#engine.getTextVisibleLineCount(block);
|
|
2370
|
+
}
|
|
2371
|
+
getTextVisibleLineContent(block, lineIndex) {
|
|
2372
|
+
return this.#engine.getTextVisibleLineContent(block, lineIndex);
|
|
2373
|
+
}
|
|
2374
|
+
getTextVisibleLineGlobalBoundingBoxXYWH(block, lineIndex) {
|
|
2375
|
+
return this.#engine.getTextVisibleLineGlobalBoundingBoxXYWH(
|
|
2376
|
+
block,
|
|
2377
|
+
lineIndex
|
|
2378
|
+
);
|
|
2379
|
+
}
|
|
2380
|
+
/**
|
|
2381
|
+
* Returns the tight ink-paint bounding box for each grapheme in the
|
|
2382
|
+
* range. One entry per grapheme in [from, to). Non-printable graphemes
|
|
2383
|
+
* (e.g. newline) get a zero-rect entry. Coordinates are in global
|
|
2384
|
+
* scene space.
|
|
2385
|
+
*
|
|
2386
|
+
* @param block - The text block to query.
|
|
2387
|
+
* @param from - Start UTF-16 index (-1 = start of cursor selection or 0).
|
|
2388
|
+
* @param to - End UTF-16 index (-1 = end of cursor selection or text length).
|
|
2389
|
+
*/
|
|
2390
|
+
getTextCharacterInkBoxes(block, from = -1, to = -1) {
|
|
2391
|
+
const range = this.#toGraphemeRange(block, from, to);
|
|
2392
|
+
return this.#engine.getTextCharacterInkBoxes(block, range.from, range.to);
|
|
2393
|
+
}
|
|
2394
|
+
getTextEffectiveHorizontalAlignment(block) {
|
|
2395
|
+
return this.#engine.getTextEffectiveHorizontalAlignment(block);
|
|
2396
|
+
}
|
|
2397
|
+
/**
|
|
2398
|
+
* Returns the horizontal alignment override for a specific paragraph, or
|
|
2399
|
+
* the block-level alignment for negative paragraph indices. Returns
|
|
2400
|
+
* `undefined` when no override is set for the given paragraph.
|
|
2401
|
+
* @param block - The text block to query.
|
|
2402
|
+
* @param paragraphIndex - 0-based paragraph index. Negative values return
|
|
2403
|
+
* the block-level `text/horizontalAlignment` setting.
|
|
2404
|
+
*/
|
|
2405
|
+
getTextHorizontalAlignment(block, paragraphIndex = -1) {
|
|
2406
|
+
return this.#engine.getTextHorizontalAlignment(block, paragraphIndex);
|
|
2407
|
+
}
|
|
2408
|
+
/**
|
|
2409
|
+
* Sets the horizontal alignment override for a specific paragraph of a text
|
|
2410
|
+
* block. Pass `undefined` for `alignment` to clear the paragraph-level
|
|
2411
|
+
* override. Negative `paragraphIndex` clears all paragraph overrides and
|
|
2412
|
+
* applies the alignment block-wide.
|
|
2413
|
+
*/
|
|
2414
|
+
setTextHorizontalAlignment(block, alignment, paragraphIndex = -1) {
|
|
2415
|
+
this.#engine.setTextHorizontalAlignment(block, alignment, paragraphIndex);
|
|
2416
|
+
}
|
|
2417
|
+
/**
|
|
2418
|
+
* Returns the ordered list of unique text-decoration configurations within
|
|
2419
|
+
* the given grapheme range. `from` / `to` are UTF-16 indices and are
|
|
2420
|
+
* converted to grapheme indices to match WASM semantics.
|
|
2421
|
+
*/
|
|
2422
|
+
getTextDecorations(block, from = -1, to = -1) {
|
|
2423
|
+
const range = this.#toGraphemeRange(block, from, to);
|
|
2424
|
+
const raw = this.#engine.getTextDecorations(
|
|
2425
|
+
block,
|
|
2426
|
+
range.from,
|
|
2427
|
+
range.to
|
|
2428
|
+
);
|
|
2429
|
+
return raw.map((c) => {
|
|
2430
|
+
const result = { lines: c.lines ?? [] };
|
|
2431
|
+
if (c.style != null) result.style = c.style;
|
|
2432
|
+
if (c.underlineColor != null)
|
|
2433
|
+
result.underlineColor = NativeColorInternal.toColor(c.underlineColor);
|
|
2434
|
+
if (c.underlineThickness != null)
|
|
2435
|
+
result.underlineThickness = c.underlineThickness;
|
|
2436
|
+
if (c.underlineOffset != null) result.underlineOffset = c.underlineOffset;
|
|
2437
|
+
if (c.skipInk != null) result.skipInk = c.skipInk;
|
|
2438
|
+
return result;
|
|
2439
|
+
});
|
|
2440
|
+
}
|
|
2441
|
+
/**
|
|
2442
|
+
* Sets the given text-decoration config for the given grapheme range. Set
|
|
2443
|
+
* `lines: ['None']` to clear all decorations.
|
|
2444
|
+
*/
|
|
2445
|
+
setTextDecoration(block, config, from = -1, to = -1) {
|
|
2446
|
+
const range = this.#toGraphemeRange(block, from, to);
|
|
2447
|
+
const internal = {
|
|
2448
|
+
lines: config.lines,
|
|
2449
|
+
style: config.style,
|
|
2450
|
+
underlineColor: config.underlineColor != null ? NativeColorInternal.fromColor(config.underlineColor) : void 0,
|
|
2451
|
+
underlineThickness: config.underlineThickness,
|
|
2452
|
+
underlineOffset: config.underlineOffset,
|
|
2453
|
+
skipInk: config.skipInk
|
|
2454
|
+
};
|
|
2455
|
+
this.#engine.setTextDecoration(block, internal, range.from, range.to);
|
|
2456
|
+
}
|
|
2457
|
+
toggleTextDecorationUnderline(block, from = -1, to = -1) {
|
|
2458
|
+
const range = this.#toGraphemeRange(block, from, to);
|
|
2459
|
+
this.#engine.toggleTextDecorationUnderline(block, range.from, range.to);
|
|
2460
|
+
}
|
|
2461
|
+
toggleTextDecorationStrikethrough(block, from = -1, to = -1) {
|
|
2462
|
+
const range = this.#toGraphemeRange(block, from, to);
|
|
2463
|
+
this.#engine.toggleTextDecorationStrikethrough(block, range.from, range.to);
|
|
2464
|
+
}
|
|
2465
|
+
toggleTextDecorationOverline(block, from = -1, to = -1) {
|
|
2466
|
+
const range = this.#toGraphemeRange(block, from, to);
|
|
2467
|
+
this.#engine.toggleTextDecorationOverline(block, range.from, range.to);
|
|
2468
|
+
}
|
|
2469
|
+
// Text lists
|
|
2470
|
+
getTextListStyle(block, paragraphIndex) {
|
|
2471
|
+
return this.#engine.getTextListStyle(block, paragraphIndex);
|
|
2472
|
+
}
|
|
2473
|
+
setTextListStyle(block, listStyle, paragraphIndex = -1, listLevel) {
|
|
2474
|
+
this.#engine.setTextListStyle(block, listStyle, paragraphIndex, listLevel);
|
|
2475
|
+
}
|
|
2476
|
+
getTextListLevel(block, paragraphIndex) {
|
|
2477
|
+
return this.#engine.getTextListLevel(block, paragraphIndex);
|
|
2478
|
+
}
|
|
2479
|
+
setTextListLevel(block, listLevel, paragraphIndex = -1) {
|
|
2480
|
+
this.#engine.setTextListLevel(block, listLevel, paragraphIndex);
|
|
2481
|
+
}
|
|
2482
|
+
/**
|
|
2483
|
+
* Returns the 0-based paragraph indices that overlap the given UTF-16 range.
|
|
2484
|
+
* Range is half-open: `from` inclusive, `to` exclusive. Negative values mean
|
|
2485
|
+
* "all paragraphs". When `from === to`, returns the paragraph containing the
|
|
2486
|
+
* cursor at `from`.
|
|
2487
|
+
*/
|
|
2488
|
+
getTextParagraphIndices(block, from = -1, to = -1) {
|
|
2489
|
+
const range = this.#toGraphemeRange(block, from, to);
|
|
2490
|
+
return this.#engine.getTextParagraphIndices(block, range.from, range.to);
|
|
2491
|
+
}
|
|
2492
|
+
getTextLineHeight(block, paragraphIndex) {
|
|
2493
|
+
return this.#engine.getTextLineHeight(block, paragraphIndex);
|
|
2494
|
+
}
|
|
2495
|
+
setTextLineHeight(block, lineHeight, paragraphIndex = -1) {
|
|
2496
|
+
this.#engine.setTextLineHeight(
|
|
2497
|
+
block,
|
|
2498
|
+
lineHeight ?? void 0,
|
|
2499
|
+
paragraphIndex
|
|
2500
|
+
);
|
|
2501
|
+
}
|
|
2502
|
+
getFontMetrics(fontFileUri) {
|
|
2503
|
+
return this.#engine.getFontMetrics(fontFileUri);
|
|
2504
|
+
}
|
|
2505
|
+
// Source sets
|
|
2506
|
+
getSourceSet(block, property) {
|
|
2507
|
+
return this.#engine.getSourceSet(block, property);
|
|
2508
|
+
}
|
|
2509
|
+
setSourceSet(block, property, sources) {
|
|
2510
|
+
this.#engine.setSourceSet(block, property, sources);
|
|
2511
|
+
}
|
|
2512
|
+
addImageFileURIToSourceSet(block, property, uri) {
|
|
2513
|
+
return this.#engine.addImageFileURIToSourceSet(block, property, uri);
|
|
2514
|
+
}
|
|
2515
|
+
addVideoFileURIToSourceSet(block, property, uri) {
|
|
2516
|
+
return this.#engine.addVideoFileURIToSourceSet(block, property, uri);
|
|
2517
|
+
}
|
|
2518
|
+
// Video/Audio info
|
|
2519
|
+
getVideoWidth(block) {
|
|
2520
|
+
return this.#engine.getVideoWidth(block);
|
|
2521
|
+
}
|
|
2522
|
+
getVideoHeight(block) {
|
|
2523
|
+
return this.#engine.getVideoHeight(block);
|
|
2524
|
+
}
|
|
2525
|
+
getAudioTrackCountFromVideo(block) {
|
|
2526
|
+
return this.#engine.getAudioTrackCountFromVideo(block);
|
|
2527
|
+
}
|
|
2528
|
+
getAVResourceTotalDuration(block) {
|
|
2529
|
+
return this.#engine.getAVResourceTotalDuration(block);
|
|
2530
|
+
}
|
|
2531
|
+
/**
|
|
2532
|
+
* Splits the block at the given time. The original block keeps the
|
|
2533
|
+
* leading portion; the trailing portion is returned as a newly
|
|
2534
|
+
* created block id (matches `@cesdk/node`'s return contract).
|
|
2535
|
+
*
|
|
2536
|
+
* @remarks Matches `@cesdk/node`'s `SplitOptions` shape:
|
|
2537
|
+
* `attachToParent` and `selectNewBlock` default to `true`,
|
|
2538
|
+
* `createParentTrackIfNeeded` defaults to `false`. Non-default values
|
|
2539
|
+
* are accepted for shape parity but not yet plumbed to the C++ binding
|
|
2540
|
+
* — when set, a warning is emitted so callers can detect the gap.
|
|
2541
|
+
*
|
|
2542
|
+
* @param block - The block to split.
|
|
2543
|
+
* @param atTime - The time (seconds) at which to split.
|
|
2544
|
+
* @param options - Split-behavior overrides.
|
|
2545
|
+
* @returns The id of the newly created trailing block.
|
|
2546
|
+
* @public
|
|
2547
|
+
*/
|
|
2548
|
+
split(block, atTime, options = {}) {
|
|
2549
|
+
const {
|
|
2550
|
+
attachToParent = true,
|
|
2551
|
+
createParentTrackIfNeeded = false,
|
|
2552
|
+
selectNewBlock = true
|
|
2553
|
+
} = options;
|
|
2554
|
+
if (attachToParent !== true || createParentTrackIfNeeded !== false || selectNewBlock !== true) {
|
|
2555
|
+
console.warn(
|
|
2556
|
+
"[@cesdk/node-native] block.split() options are accepted for shape parity but not yet plumbed through the C++ binding. The engine will use defaults (attachToParent: true, createParentTrackIfNeeded: false, selectNewBlock: true)."
|
|
2557
|
+
);
|
|
2558
|
+
}
|
|
2559
|
+
return this.#engine.split(block, atTime);
|
|
2560
|
+
}
|
|
2561
|
+
// Frame position/size - WASM API uses getFrameX/Y/Width/Height
|
|
2562
|
+
getFrameX(block) {
|
|
2563
|
+
return this.#engine.getLastFrameX(block);
|
|
2564
|
+
}
|
|
2565
|
+
getFrameY(block) {
|
|
2566
|
+
return this.#engine.getLastFrameY(block);
|
|
2567
|
+
}
|
|
2568
|
+
getFrameWidth(block) {
|
|
2569
|
+
return this.#engine.getLastFrameWidth(block);
|
|
2570
|
+
}
|
|
2571
|
+
getFrameHeight(block) {
|
|
2572
|
+
return this.#engine.getLastFrameHeight(block);
|
|
2573
|
+
}
|
|
2574
|
+
// Page duration source
|
|
2575
|
+
supportsPageDurationSource(page, block) {
|
|
2576
|
+
return this.#engine.supportsPageDurationSource(page, block);
|
|
2577
|
+
}
|
|
2578
|
+
setPageDurationSource(page, block) {
|
|
2579
|
+
this.#engine.setPageDurationSource(page, block);
|
|
2580
|
+
}
|
|
2581
|
+
removePageDurationSource(page) {
|
|
2582
|
+
this.#engine.removePageDurationSource(page);
|
|
2583
|
+
}
|
|
2584
|
+
isPageDurationSource(block) {
|
|
2585
|
+
return this.#engine.isPageDurationSource(block);
|
|
2586
|
+
}
|
|
2587
|
+
// Scope - block-level methods only (findAllScopes, getGlobalScope, setGlobalScope are on EditorAPI)
|
|
2588
|
+
isScopeEnabled(block, scope) {
|
|
2589
|
+
return this.#engine.isScopeEnabled(block, scope);
|
|
2590
|
+
}
|
|
2591
|
+
setScopeEnabled(block, scope, enabled) {
|
|
2592
|
+
this.#engine.setScopeEnabled(block, scope, enabled);
|
|
2593
|
+
}
|
|
2594
|
+
isAllowedByScope(block, scope) {
|
|
2595
|
+
return this.#engine.isAllowedByScope(block, scope);
|
|
2596
|
+
}
|
|
2597
|
+
// Properties
|
|
2598
|
+
findAllProperties(block) {
|
|
2599
|
+
return this.#engine.findAllProperties(block);
|
|
2600
|
+
}
|
|
2601
|
+
getPropertyType(blockOrProperty, property) {
|
|
2602
|
+
const propName = typeof blockOrProperty === "string" ? blockOrProperty : property;
|
|
2603
|
+
return this.#engine.getPropertyType(propName);
|
|
2604
|
+
}
|
|
2605
|
+
isPropertyReadable(blockOrProperty, property) {
|
|
2606
|
+
const propName = typeof blockOrProperty === "string" ? blockOrProperty : property;
|
|
2607
|
+
return this.#engine.isPropertyReadable(propName);
|
|
2608
|
+
}
|
|
2609
|
+
isPropertyWritable(blockOrProperty, property) {
|
|
2610
|
+
const propName = typeof blockOrProperty === "string" ? blockOrProperty : property;
|
|
2611
|
+
return this.#engine.isPropertyWritable(propName);
|
|
2612
|
+
}
|
|
2613
|
+
getEnumValues(blockOrProperty, property) {
|
|
2614
|
+
const propName = typeof blockOrProperty === "string" ? blockOrProperty : property;
|
|
2615
|
+
return this.#engine.getEnumValues(propName);
|
|
2616
|
+
}
|
|
2617
|
+
// State
|
|
2618
|
+
getState(block) {
|
|
2619
|
+
return this.#engine.getState(block);
|
|
2620
|
+
}
|
|
2621
|
+
async export(block, mimeTypeOrOptions, optionsOrUndefined) {
|
|
2622
|
+
let mimeType;
|
|
2623
|
+
let options;
|
|
2624
|
+
if (typeof mimeTypeOrOptions === "string") {
|
|
2625
|
+
mimeType = mimeTypeOrOptions;
|
|
2626
|
+
options = optionsOrUndefined;
|
|
2627
|
+
} else {
|
|
2628
|
+
options = mimeTypeOrOptions;
|
|
2629
|
+
mimeType = options?.mimeType ?? "image/png";
|
|
2630
|
+
}
|
|
2631
|
+
const buffer = await this.exportToBuffer(block, mimeType, options);
|
|
2632
|
+
return new Blob([buffer], { type: mimeType });
|
|
2633
|
+
}
|
|
2634
|
+
exportToBuffer(block, mimeType, options) {
|
|
2635
|
+
const exportOptions = {
|
|
2636
|
+
targetWidth: options?.targetWidth ?? 0,
|
|
2637
|
+
targetHeight: options?.targetHeight ?? 0,
|
|
2638
|
+
useTargetSize: options?.targetWidth != null && options?.targetHeight != null,
|
|
2639
|
+
jpegQuality: options?.jpegQuality ?? 0.9,
|
|
2640
|
+
webpQuality: options?.webpQuality ?? 1,
|
|
2641
|
+
pngCompressionLevel: options?.pngCompressionLevel ?? 5,
|
|
2642
|
+
exportPdfWithHighCompatibility: options?.exportPdfWithHighCompatibility ?? true,
|
|
2643
|
+
exportPdfWithDeviceCMYK: options?.exportPdfWithDeviceCMYK ?? false,
|
|
2644
|
+
exportPdfWithUnderlayer: options?.exportPdfWithUnderlayer ?? false,
|
|
2645
|
+
underlayerSpotColorName: options?.underlayerSpotColorName ?? "",
|
|
2646
|
+
underlayerOffset: options?.underlayerOffset ?? 0,
|
|
2647
|
+
underlayerRenderRatio: options?.underlayerRenderRatio ?? 1,
|
|
2648
|
+
underlayerMaxError: options?.underlayerMaxError ?? 2,
|
|
2649
|
+
allowTextOverhang: options?.allowTextOverhang ?? false
|
|
2650
|
+
};
|
|
2651
|
+
return this.#engine.exportToBuffer(block, mimeType, exportOptions);
|
|
2652
|
+
}
|
|
2653
|
+
async exportWithColorMask(block, arg2, arg3, arg4, arg5, arg6) {
|
|
2654
|
+
let mimeType;
|
|
2655
|
+
let maskColorR;
|
|
2656
|
+
let maskColorG;
|
|
2657
|
+
let maskColorB;
|
|
2658
|
+
let options;
|
|
2659
|
+
if (typeof arg2 === "number") {
|
|
2660
|
+
maskColorR = arg2;
|
|
2661
|
+
maskColorG = arg3;
|
|
2662
|
+
maskColorB = arg4;
|
|
2663
|
+
options = typeof arg5 === "number" ? void 0 : arg5;
|
|
2664
|
+
mimeType = options?.mimeType ?? "image/png";
|
|
2665
|
+
} else {
|
|
2666
|
+
mimeType = arg2 ?? "image/png";
|
|
2667
|
+
maskColorR = arg3;
|
|
2668
|
+
maskColorG = arg4;
|
|
2669
|
+
maskColorB = arg5 ?? 0;
|
|
2670
|
+
options = arg6;
|
|
2671
|
+
}
|
|
2672
|
+
const exportOptions = {
|
|
2673
|
+
targetWidth: options?.targetWidth ?? 0,
|
|
2674
|
+
targetHeight: options?.targetHeight ?? 0,
|
|
2675
|
+
useTargetSize: options?.targetWidth != null && options?.targetHeight != null,
|
|
2676
|
+
jpegQuality: options?.jpegQuality ?? 0.9,
|
|
2677
|
+
webpQuality: options?.webpQuality ?? 1,
|
|
2678
|
+
pngCompressionLevel: options?.pngCompressionLevel ?? 5,
|
|
2679
|
+
exportPdfWithHighCompatibility: options?.exportPdfWithHighCompatibility ?? true,
|
|
2680
|
+
exportPdfWithDeviceCMYK: options?.exportPdfWithDeviceCMYK ?? false,
|
|
2681
|
+
exportPdfWithUnderlayer: options?.exportPdfWithUnderlayer ?? false,
|
|
2682
|
+
underlayerSpotColorName: options?.underlayerSpotColorName ?? "",
|
|
2683
|
+
underlayerOffset: options?.underlayerOffset ?? 0,
|
|
2684
|
+
underlayerRenderRatio: options?.underlayerRenderRatio ?? 1,
|
|
2685
|
+
underlayerMaxError: options?.underlayerMaxError ?? 2,
|
|
2686
|
+
allowTextOverhang: options?.allowTextOverhang ?? false
|
|
2687
|
+
};
|
|
2688
|
+
const buffers = await this.#engine.exportWithColorMaskToBuffer(
|
|
2689
|
+
block,
|
|
2690
|
+
mimeType,
|
|
2691
|
+
maskColorR,
|
|
2692
|
+
maskColorG,
|
|
2693
|
+
maskColorB,
|
|
2694
|
+
exportOptions
|
|
2695
|
+
);
|
|
2696
|
+
return buffers.map((buf) => new Blob([buf], { type: mimeType }));
|
|
2697
|
+
}
|
|
2698
|
+
async exportVideo(block, mimeTypeOrOptions, progressCallbackOrUndefined, optionsOrUndefined) {
|
|
2699
|
+
let mimeType;
|
|
2700
|
+
let progressCallback;
|
|
2701
|
+
let options;
|
|
2702
|
+
if (typeof mimeTypeOrOptions === "string") {
|
|
2703
|
+
mimeType = mimeTypeOrOptions;
|
|
2704
|
+
progressCallback = progressCallbackOrUndefined;
|
|
2705
|
+
options = optionsOrUndefined;
|
|
2706
|
+
} else {
|
|
2707
|
+
const bag = mimeTypeOrOptions;
|
|
2708
|
+
mimeType = bag?.mimeType ?? "video/mp4";
|
|
2709
|
+
progressCallback = bag?.onProgress;
|
|
2710
|
+
options = bag;
|
|
2711
|
+
}
|
|
2712
|
+
const buffer = await this.exportVideoToBuffer(
|
|
2713
|
+
block,
|
|
2714
|
+
mimeType,
|
|
2715
|
+
options,
|
|
2716
|
+
progressCallback
|
|
2717
|
+
);
|
|
2718
|
+
return new Blob([buffer], { type: mimeType });
|
|
2719
|
+
}
|
|
2720
|
+
exportVideoToBuffer(block, mimeType, options, progressCallback) {
|
|
2721
|
+
return new Promise((resolve, reject) => {
|
|
2722
|
+
const defaultOptions = {
|
|
2723
|
+
h264Profile: 77,
|
|
2724
|
+
// Main (H264VideoProfile::Main = 77)
|
|
2725
|
+
h264Level: 52,
|
|
2726
|
+
videoBitrate: 0,
|
|
2727
|
+
audioBitrate: 0,
|
|
2728
|
+
framerate: 30,
|
|
2729
|
+
useTargetSize: false,
|
|
2730
|
+
targetWidth: 0,
|
|
2731
|
+
targetHeight: 0,
|
|
2732
|
+
allowTextOverhang: false,
|
|
2733
|
+
...options
|
|
2734
|
+
};
|
|
2735
|
+
this.#engine.exportVideoToBuffer(
|
|
2736
|
+
block,
|
|
2737
|
+
options?.timeOffset ?? 0,
|
|
2738
|
+
options?.duration ?? this.getDuration(block),
|
|
2739
|
+
mimeType,
|
|
2740
|
+
progressCallback ?? (() => {
|
|
2741
|
+
}),
|
|
2742
|
+
(errorOrNull, data) => {
|
|
2743
|
+
if (errorOrNull) {
|
|
2744
|
+
reject(
|
|
2745
|
+
errorOrNull instanceof Error ? errorOrNull : new Error(String(errorOrNull))
|
|
2746
|
+
);
|
|
2747
|
+
} else if (data) {
|
|
2748
|
+
resolve(data);
|
|
2749
|
+
} else {
|
|
2750
|
+
reject(new Error("Video export returned no data"));
|
|
2751
|
+
}
|
|
2752
|
+
},
|
|
2753
|
+
defaultOptions
|
|
2754
|
+
);
|
|
2755
|
+
});
|
|
2756
|
+
}
|
|
2757
|
+
async exportAudio(block, mimeTypeOrOptions, optionsOrUndefined) {
|
|
2758
|
+
let mimeType;
|
|
2759
|
+
let options;
|
|
2760
|
+
if (typeof mimeTypeOrOptions === "string") {
|
|
2761
|
+
mimeType = mimeTypeOrOptions;
|
|
2762
|
+
options = optionsOrUndefined;
|
|
2763
|
+
} else {
|
|
2764
|
+
options = mimeTypeOrOptions;
|
|
2765
|
+
mimeType = options?.mimeType ?? "audio/wav";
|
|
2766
|
+
}
|
|
2767
|
+
const buffer = await this.exportAudioToBuffer(block, mimeType, options);
|
|
2768
|
+
return new Blob([buffer], { type: mimeType });
|
|
2769
|
+
}
|
|
2770
|
+
exportAudioToBuffer(block, mimeType, options) {
|
|
2771
|
+
return new Promise((resolve, reject) => {
|
|
2772
|
+
const defaultOptions = {
|
|
2773
|
+
sampleRate: 48e3,
|
|
2774
|
+
numberOfChannels: 2,
|
|
2775
|
+
skipEncoding: false,
|
|
2776
|
+
...options
|
|
2777
|
+
};
|
|
2778
|
+
this.#engine.exportAudioToBuffer(
|
|
2779
|
+
block,
|
|
2780
|
+
options?.timeOffset ?? 0,
|
|
2781
|
+
options?.duration ?? this.getDuration(block),
|
|
2782
|
+
mimeType,
|
|
2783
|
+
options?.onProgress ?? (() => {
|
|
2784
|
+
}),
|
|
2785
|
+
(errorOrNull, data) => {
|
|
2786
|
+
if (errorOrNull) {
|
|
2787
|
+
reject(
|
|
2788
|
+
errorOrNull instanceof Error ? errorOrNull : new Error(String(errorOrNull))
|
|
2789
|
+
);
|
|
2790
|
+
} else if (data) {
|
|
2791
|
+
resolve(data);
|
|
2792
|
+
} else {
|
|
2793
|
+
reject(new Error("Audio export returned no data"));
|
|
2794
|
+
}
|
|
2795
|
+
},
|
|
2796
|
+
defaultOptions
|
|
2797
|
+
);
|
|
2798
|
+
});
|
|
2799
|
+
}
|
|
2800
|
+
// Loading/Saving blocks
|
|
2801
|
+
loadFromString(content) {
|
|
2802
|
+
if (content.length === 0) {
|
|
2803
|
+
return Promise.reject(new Error("Cannot load from empty string"));
|
|
2804
|
+
}
|
|
2805
|
+
return this.#engine.loadBlocksFromString(content);
|
|
2806
|
+
}
|
|
2807
|
+
loadFromURL(url) {
|
|
2808
|
+
return this.#engine.loadBlocksFromURL(url);
|
|
2809
|
+
}
|
|
2810
|
+
/**
|
|
2811
|
+
* Load blocks from an archive URL.
|
|
2812
|
+
* Also supports data URIs (data:application/zip;base64,...) which are converted to buffer:// protocol internally.
|
|
2813
|
+
* @param url - The URL of the archive file, or a data URI containing base64-encoded archive data.
|
|
2814
|
+
* @returns A promise that resolves with an array of block IDs.
|
|
2815
|
+
*/
|
|
2816
|
+
async loadFromArchiveURL(url) {
|
|
2817
|
+
if (url.startsWith("data:")) {
|
|
2818
|
+
const matches = url.match(/^data:([^;,]+)?(?:;base64)?,(.*)$/);
|
|
2819
|
+
if (!matches) {
|
|
2820
|
+
throw new Error("Invalid data URI format");
|
|
2821
|
+
}
|
|
2822
|
+
const base64Data = matches[2];
|
|
2823
|
+
const buffer = Buffer.from(base64Data, "base64");
|
|
2824
|
+
const bufferUri = this.#engine.createBuffer();
|
|
2825
|
+
this.#engine.setBufferData(bufferUri, 0, new Uint8Array(buffer));
|
|
2826
|
+
try {
|
|
2827
|
+
return await this.#engine.loadBlocksFromArchiveURL(bufferUri);
|
|
2828
|
+
} finally {
|
|
2829
|
+
this.#engine.destroyBuffer(bufferUri);
|
|
2830
|
+
}
|
|
2831
|
+
}
|
|
2832
|
+
return this.#engine.loadBlocksFromArchiveURL(url);
|
|
2833
|
+
}
|
|
2834
|
+
saveToString(blocks) {
|
|
2835
|
+
return this.#engine.saveBlocksToString(blocks);
|
|
2836
|
+
}
|
|
2837
|
+
// BlockAPI.saveToArchive matches @cesdk/node and returns Promise<Blob>. The
|
|
2838
|
+
// raw Uint8Array form remains accessible via the engine binding for
|
|
2839
|
+
// power-users that want to skip the wrapper.
|
|
2840
|
+
async saveToArchive(blocks) {
|
|
2841
|
+
const buffer = await this.#engine.saveBlocksToArchive(blocks);
|
|
2842
|
+
return new Blob([buffer]);
|
|
2843
|
+
}
|
|
2844
|
+
/**
|
|
2845
|
+
* Force-load the audio/video resource for an audio block or video-fill block.
|
|
2846
|
+
* Resolves once the asset is fully fetched and demuxed (so subsequent
|
|
2847
|
+
* `exportVideo` calls have data immediately available on frame 0). Without
|
|
2848
|
+
* this prime, the encoder can race ahead of the HTTP fetch and produce
|
|
2849
|
+
* silent audio / black-frame video segments.
|
|
2850
|
+
*/
|
|
2851
|
+
forceLoadAVResource(block) {
|
|
2852
|
+
return this.#engine.forceLoadAVResource(block);
|
|
2853
|
+
}
|
|
2854
|
+
/**
|
|
2855
|
+
* Force-load every resource referenced by `blocks`. Useful before
|
|
2856
|
+
* `exportVideo` on a scene with multiple remote assets — saves N network
|
|
2857
|
+
* round-trips compared to calling `forceLoadAVResource` per block.
|
|
2858
|
+
*/
|
|
2859
|
+
forceLoadResources(blocks) {
|
|
2860
|
+
return this.#engine.forceLoadResources(blocks);
|
|
2861
|
+
}
|
|
2862
|
+
// -------------------------------------------------------------------------
|
|
2863
|
+
// Composition helpers (parity with @cesdk/node's `addImage` / `addVideo` /
|
|
2864
|
+
// `applyAnimation` / `applyDropShadow`).
|
|
2865
|
+
//
|
|
2866
|
+
// These are TS-level convenience wrappers, not engine primitives. WASM
|
|
2867
|
+
// ships them on its BlockAPI; native must too so a drop-in `addImage`
|
|
2868
|
+
// call doesn't throw `TypeError: not a function`.
|
|
2869
|
+
// -------------------------------------------------------------------------
|
|
2870
|
+
/**
|
|
2871
|
+
* Apply an animation set (in/loop/out) to a block. Mirrors
|
|
2872
|
+
* `@cesdk/node`'s `BlockAPI.applyAnimation` exactly.
|
|
2873
|
+
*
|
|
2874
|
+
* @public
|
|
2875
|
+
*/
|
|
2876
|
+
applyAnimation(block, animation = {}) {
|
|
2877
|
+
const apply = (entry, setter) => {
|
|
2878
|
+
if (entry == null) return;
|
|
2879
|
+
const animBlock = this.createAnimation(entry.type);
|
|
2880
|
+
setter(block, animBlock);
|
|
2881
|
+
if (entry.duration !== void 0) {
|
|
2882
|
+
this.setDuration(animBlock, entry.duration);
|
|
2883
|
+
}
|
|
2884
|
+
if (entry.easing != null) {
|
|
2885
|
+
try {
|
|
2886
|
+
const enumValues = this.getEnumValues("animationEasing");
|
|
2887
|
+
if (enumValues.includes(entry.easing)) {
|
|
2888
|
+
this.setEnum(animBlock, "animationEasing", entry.easing);
|
|
2889
|
+
}
|
|
2890
|
+
} catch {
|
|
2891
|
+
}
|
|
2892
|
+
}
|
|
2893
|
+
};
|
|
2894
|
+
apply(animation.in, (b, a) => this.setInAnimation(b, a));
|
|
2895
|
+
apply(animation.out, (b, a) => this.setOutAnimation(b, a));
|
|
2896
|
+
apply(animation.loop, (b, a) => this.setLoopAnimation(b, a));
|
|
2897
|
+
}
|
|
2898
|
+
/**
|
|
2899
|
+
* Apply a drop shadow effect to a block. Mirrors `@cesdk/node`'s
|
|
2900
|
+
* `BlockAPI.applyDropShadow` exactly.
|
|
2901
|
+
*
|
|
2902
|
+
* @public
|
|
2903
|
+
*/
|
|
2904
|
+
applyDropShadow(block, options = {}) {
|
|
2905
|
+
this.setDropShadowEnabled(block, true);
|
|
2906
|
+
if (options.color != null) {
|
|
2907
|
+
this.setDropShadowColor(block, options.color);
|
|
2908
|
+
}
|
|
2909
|
+
if (options.offset != null) {
|
|
2910
|
+
if (options.offset.x != null)
|
|
2911
|
+
this.setDropShadowOffsetX(block, options.offset.x);
|
|
2912
|
+
if (options.offset.y != null)
|
|
2913
|
+
this.setDropShadowOffsetY(block, options.offset.y);
|
|
2914
|
+
}
|
|
2915
|
+
if (options.blur != null) {
|
|
2916
|
+
if (options.blur.x != null)
|
|
2917
|
+
this.setDropShadowBlurRadiusX(block, options.blur.x);
|
|
2918
|
+
if (options.blur.y != null)
|
|
2919
|
+
this.setDropShadowBlurRadiusY(block, options.blur.y);
|
|
2920
|
+
}
|
|
2921
|
+
}
|
|
2922
|
+
/**
|
|
2923
|
+
* Add an image to the current page as a graphic block with an image fill.
|
|
2924
|
+
* Mirrors `@cesdk/node`'s `BlockAPI.addImage` shape — same options bag,
|
|
2925
|
+
* same chained-call sequence.
|
|
2926
|
+
*
|
|
2927
|
+
* @remarks Unlike WASM (which uses `new Image()` to auto-detect size when
|
|
2928
|
+
* `options.size` is omitted), Node has no DOM `Image` global. In Node,
|
|
2929
|
+
* `options.size` must be supplied; calling without it throws a clear
|
|
2930
|
+
* error with the suggested fix.
|
|
2931
|
+
*
|
|
2932
|
+
* @public
|
|
2933
|
+
*/
|
|
2934
|
+
addImage(url, options = {}) {
|
|
2935
|
+
const {
|
|
2936
|
+
x,
|
|
2937
|
+
y,
|
|
2938
|
+
size,
|
|
2939
|
+
timeline,
|
|
2940
|
+
animation,
|
|
2941
|
+
shadow,
|
|
2942
|
+
cornerRadius,
|
|
2943
|
+
sizeMode = "Absolute",
|
|
2944
|
+
positionMode = "Absolute"
|
|
2945
|
+
} = options;
|
|
2946
|
+
let finalWidth;
|
|
2947
|
+
let finalHeight;
|
|
2948
|
+
if (size != null) {
|
|
2949
|
+
if (typeof size === "number") {
|
|
2950
|
+
finalWidth = size;
|
|
2951
|
+
finalHeight = size;
|
|
2952
|
+
} else {
|
|
2953
|
+
finalWidth = size.width;
|
|
2954
|
+
finalHeight = size.height;
|
|
2955
|
+
}
|
|
2956
|
+
} else {
|
|
2957
|
+
throw new Error(
|
|
2958
|
+
"[@cesdk/node-native] block.addImage requires `options.size` in Node (no DOM Image global for auto-sizing). Pass `{ size: { width, height } }` or `{ size: <px> }`."
|
|
2959
|
+
);
|
|
2960
|
+
}
|
|
2961
|
+
const scenes = this.findByType("//ly.img.ubq/scene");
|
|
2962
|
+
if (scenes.length === 0) {
|
|
2963
|
+
throw new Error("No scene found. Call engine.scene.create() first.");
|
|
2964
|
+
}
|
|
2965
|
+
const pages = this.findByType("//ly.img.ubq/page");
|
|
2966
|
+
if (pages.length === 0) {
|
|
2967
|
+
throw new Error("No page found in scene. Create a page first.");
|
|
2968
|
+
}
|
|
2969
|
+
const page = pages[0];
|
|
2970
|
+
const graphicBlock = this.create("graphic");
|
|
2971
|
+
this.appendChild(page, graphicBlock);
|
|
2972
|
+
this.setPositionXMode(graphicBlock, positionMode);
|
|
2973
|
+
this.setPositionYMode(graphicBlock, positionMode);
|
|
2974
|
+
this.setWidthMode(graphicBlock, sizeMode);
|
|
2975
|
+
this.setHeightMode(graphicBlock, sizeMode);
|
|
2976
|
+
if (finalWidth != null) this.setWidth(graphicBlock, finalWidth);
|
|
2977
|
+
if (finalHeight != null) this.setHeight(graphicBlock, finalHeight);
|
|
2978
|
+
if (x != null) {
|
|
2979
|
+
this.setPositionX(graphicBlock, x);
|
|
2980
|
+
} else {
|
|
2981
|
+
this.alignHorizontally([graphicBlock], "Center");
|
|
2982
|
+
}
|
|
2983
|
+
if (y != null) {
|
|
2984
|
+
this.setPositionY(graphicBlock, y);
|
|
2985
|
+
} else {
|
|
2986
|
+
this.alignVertically([graphicBlock], "Center");
|
|
2987
|
+
}
|
|
2988
|
+
const shapeBlock = this.createShape("rect");
|
|
2989
|
+
this.setShape(graphicBlock, shapeBlock);
|
|
2990
|
+
if (cornerRadius != null) {
|
|
2991
|
+
this.setFloat(shapeBlock, "shape/rect/cornerRadiusBL", cornerRadius);
|
|
2992
|
+
this.setFloat(shapeBlock, "shape/rect/cornerRadiusBR", cornerRadius);
|
|
2993
|
+
this.setFloat(shapeBlock, "shape/rect/cornerRadiusTL", cornerRadius);
|
|
2994
|
+
this.setFloat(shapeBlock, "shape/rect/cornerRadiusTR", cornerRadius);
|
|
2995
|
+
}
|
|
2996
|
+
const fillBlock = this.createFill("image");
|
|
2997
|
+
this.setFill(graphicBlock, fillBlock);
|
|
2998
|
+
this.setString(fillBlock, "fill/image/imageFileURI", url);
|
|
2999
|
+
if (shadow != null) this.applyDropShadow(graphicBlock, shadow);
|
|
3000
|
+
if (timeline?.timeOffset != null)
|
|
3001
|
+
this.setTimeOffset(graphicBlock, timeline.timeOffset);
|
|
3002
|
+
if (timeline?.duration != null)
|
|
3003
|
+
this.setDuration(graphicBlock, timeline.duration);
|
|
3004
|
+
if (animation != null) this.applyAnimation(graphicBlock, animation);
|
|
3005
|
+
return graphicBlock;
|
|
3006
|
+
}
|
|
3007
|
+
/**
|
|
3008
|
+
* Add a video to the current page as a graphic block with a video fill.
|
|
3009
|
+
* Mirrors `@cesdk/node`'s `BlockAPI.addVideo` shape.
|
|
3010
|
+
*
|
|
3011
|
+
* @remarks Like `addImage`, requires explicit `options.size` in Node.
|
|
3012
|
+
*
|
|
3013
|
+
* @public
|
|
3014
|
+
*/
|
|
3015
|
+
addVideo(url, options = {}) {
|
|
3016
|
+
const {
|
|
3017
|
+
x,
|
|
3018
|
+
y,
|
|
3019
|
+
size,
|
|
3020
|
+
timeline,
|
|
3021
|
+
animation,
|
|
3022
|
+
shadow,
|
|
3023
|
+
cornerRadius,
|
|
3024
|
+
sizeMode = "Absolute",
|
|
3025
|
+
positionMode = "Absolute",
|
|
3026
|
+
trimOffset,
|
|
3027
|
+
loop,
|
|
3028
|
+
muted
|
|
3029
|
+
} = options;
|
|
3030
|
+
if (size == null) {
|
|
3031
|
+
throw new Error(
|
|
3032
|
+
"[@cesdk/node-native] block.addVideo requires `options.size` in Node (no auto-probe). Pass `{ size: { width, height } }`."
|
|
3033
|
+
);
|
|
3034
|
+
}
|
|
3035
|
+
const finalWidth = typeof size === "number" ? size : size.width;
|
|
3036
|
+
const finalHeight = typeof size === "number" ? size : size.height;
|
|
3037
|
+
const pages = this.findByType("//ly.img.ubq/page");
|
|
3038
|
+
if (pages.length === 0) {
|
|
3039
|
+
throw new Error("No page found. Create a page first.");
|
|
3040
|
+
}
|
|
3041
|
+
const page = pages[0];
|
|
3042
|
+
const graphicBlock = this.create("graphic");
|
|
3043
|
+
this.appendChild(page, graphicBlock);
|
|
3044
|
+
this.setPositionXMode(graphicBlock, positionMode);
|
|
3045
|
+
this.setPositionYMode(graphicBlock, positionMode);
|
|
3046
|
+
this.setWidthMode(graphicBlock, sizeMode);
|
|
3047
|
+
this.setHeightMode(graphicBlock, sizeMode);
|
|
3048
|
+
this.setWidth(graphicBlock, finalWidth);
|
|
3049
|
+
this.setHeight(graphicBlock, finalHeight);
|
|
3050
|
+
if (x != null) this.setPositionX(graphicBlock, x);
|
|
3051
|
+
else this.alignHorizontally([graphicBlock], "Center");
|
|
3052
|
+
if (y != null) this.setPositionY(graphicBlock, y);
|
|
3053
|
+
else this.alignVertically([graphicBlock], "Center");
|
|
3054
|
+
const shapeBlock = this.createShape("rect");
|
|
3055
|
+
this.setShape(graphicBlock, shapeBlock);
|
|
3056
|
+
if (cornerRadius != null) {
|
|
3057
|
+
this.setFloat(shapeBlock, "shape/rect/cornerRadiusBL", cornerRadius);
|
|
3058
|
+
this.setFloat(shapeBlock, "shape/rect/cornerRadiusBR", cornerRadius);
|
|
3059
|
+
this.setFloat(shapeBlock, "shape/rect/cornerRadiusTL", cornerRadius);
|
|
3060
|
+
this.setFloat(shapeBlock, "shape/rect/cornerRadiusTR", cornerRadius);
|
|
3061
|
+
}
|
|
3062
|
+
const fillBlock = this.createFill("video");
|
|
3063
|
+
this.setFill(graphicBlock, fillBlock);
|
|
3064
|
+
this.setString(fillBlock, "fill/video/fileURI", url);
|
|
3065
|
+
if (loop !== void 0) {
|
|
3066
|
+
try {
|
|
3067
|
+
this.setBool(fillBlock, "fill/video/looping", loop);
|
|
3068
|
+
} catch {
|
|
3069
|
+
}
|
|
3070
|
+
}
|
|
3071
|
+
if (muted !== void 0) {
|
|
3072
|
+
try {
|
|
3073
|
+
this.setBool(fillBlock, "fill/video/muted", muted);
|
|
3074
|
+
} catch {
|
|
3075
|
+
}
|
|
3076
|
+
}
|
|
3077
|
+
if (trimOffset !== void 0) {
|
|
3078
|
+
try {
|
|
3079
|
+
this.setFloat(fillBlock, "fill/video/trimOffset", trimOffset);
|
|
3080
|
+
} catch {
|
|
3081
|
+
}
|
|
3082
|
+
}
|
|
3083
|
+
if (shadow != null) this.applyDropShadow(graphicBlock, shadow);
|
|
3084
|
+
if (timeline?.timeOffset != null)
|
|
3085
|
+
this.setTimeOffset(graphicBlock, timeline.timeOffset);
|
|
3086
|
+
if (timeline?.duration != null)
|
|
3087
|
+
this.setDuration(graphicBlock, timeline.duration);
|
|
3088
|
+
if (animation != null) this.applyAnimation(graphicBlock, animation);
|
|
3089
|
+
return graphicBlock;
|
|
3090
|
+
}
|
|
3091
|
+
/**
|
|
3092
|
+
* Subscribe to state changes on a set of blocks. Matches WASM's
|
|
3093
|
+
* `engine.block.onStateChanged(ids, callback)` contract — pass an empty
|
|
3094
|
+
* array to monitor every block in the scene. The native C++ side
|
|
3095
|
+
* already implements this via `subscribeToBlockState`; this wrapper
|
|
3096
|
+
* exposes it on `engine.block` so portable consumers (e.g.
|
|
3097
|
+
* `@imgly/psd-importer`'s transient-relocation tests) can subscribe the
|
|
3098
|
+
* same way on both bindings.
|
|
3099
|
+
*
|
|
3100
|
+
* @returns A function to unsubscribe.
|
|
3101
|
+
*/
|
|
3102
|
+
onStateChanged(ids, callback) {
|
|
3103
|
+
const id = this.#engine.subscribeToBlockState(ids ?? [], callback);
|
|
3104
|
+
return () => this.#engine.unsubscribe(id);
|
|
3105
|
+
}
|
|
3106
|
+
/**
|
|
3107
|
+
* Subscribe to selection changes. Matches WASM's
|
|
3108
|
+
* `engine.block.onSelectionChanged(callback)` contract — fires when the
|
|
3109
|
+
* set of selected blocks changes. The native C++ side already implements
|
|
3110
|
+
* this via `subscribeToSelectionChange`; this wrapper exposes it so
|
|
3111
|
+
* portable consumers (selection-reactive UI) work on both bindings.
|
|
3112
|
+
*
|
|
3113
|
+
* @returns A function to unsubscribe.
|
|
3114
|
+
*/
|
|
3115
|
+
onSelectionChanged(callback) {
|
|
3116
|
+
const id = this.#engine.subscribeToSelectionChange(callback);
|
|
3117
|
+
return () => this.#engine.unsubscribe(id);
|
|
3118
|
+
}
|
|
3119
|
+
/**
|
|
3120
|
+
* Subscribe to block clicks. Matches WASM's
|
|
3121
|
+
* `engine.block.onClicked((id) => …)` contract. In a headless Node
|
|
3122
|
+
* context the engine never fires this event (no UI input), but the
|
|
3123
|
+
* subscription surface exists for API parity so the same code compiles
|
|
3124
|
+
* and runs against both bindings.
|
|
3125
|
+
*
|
|
3126
|
+
* @returns A function to unsubscribe.
|
|
3127
|
+
*/
|
|
3128
|
+
onClicked(callback) {
|
|
3129
|
+
const id = this.#engine.subscribeToBlockClicked(callback);
|
|
3130
|
+
return () => this.#engine.unsubscribe(id);
|
|
3131
|
+
}
|
|
3132
|
+
};
|
|
3133
|
+
var SceneAPI = class {
|
|
3134
|
+
#engine;
|
|
3135
|
+
constructor(engine) {
|
|
3136
|
+
this.#engine = engine;
|
|
3137
|
+
}
|
|
3138
|
+
/**
|
|
3139
|
+
* Create a new design scene, along with its own camera.
|
|
3140
|
+
* @param sceneLayout - The layout of the scene.
|
|
3141
|
+
* @returns The scene's handle.
|
|
3142
|
+
*/
|
|
3143
|
+
create(sceneLayout = "Free", options) {
|
|
3144
|
+
const scene = this.#engine.createScene(sceneLayout);
|
|
3145
|
+
if (options) {
|
|
3146
|
+
this.#createSceneElements(scene, options);
|
|
3147
|
+
}
|
|
3148
|
+
return scene;
|
|
3149
|
+
}
|
|
3150
|
+
/**
|
|
3151
|
+
* Create a new scene in video mode, along with its own camera.
|
|
3152
|
+
* @returns The scene's handle.
|
|
3153
|
+
*/
|
|
3154
|
+
createVideo(options) {
|
|
3155
|
+
const scene = this.#engine.createVideoScene();
|
|
3156
|
+
this.#engine.setSceneMode(scene, "Video");
|
|
3157
|
+
if (options) {
|
|
3158
|
+
this.#createSceneElements(scene, options);
|
|
3159
|
+
}
|
|
3160
|
+
return scene;
|
|
3161
|
+
}
|
|
3162
|
+
#createSceneElements(scene, options) {
|
|
3163
|
+
if (options.designUnit != null) {
|
|
3164
|
+
this.#engine.setDesignUnit(scene, options.designUnit);
|
|
3165
|
+
const pairedFontUnit = options.designUnit === "Pixel" ? "Pixel" : "Point";
|
|
3166
|
+
this.#engine.setFontSizeUnit(
|
|
3167
|
+
scene,
|
|
3168
|
+
options.fontSizeUnit ?? pairedFontUnit
|
|
3169
|
+
);
|
|
3170
|
+
} else if (options.fontSizeUnit != null) {
|
|
3171
|
+
this.#engine.setFontSizeUnit(scene, options.fontSizeUnit);
|
|
3172
|
+
}
|
|
3173
|
+
if (!options.page) {
|
|
3174
|
+
return;
|
|
3175
|
+
}
|
|
3176
|
+
let finalWidth = 0;
|
|
3177
|
+
let finalHeight = 0;
|
|
3178
|
+
if (typeof options.page.size === "number") {
|
|
3179
|
+
finalWidth = options.page.size;
|
|
3180
|
+
finalHeight = options.page.size;
|
|
3181
|
+
} else if (typeof options.page.size === "object") {
|
|
3182
|
+
finalWidth = options.page.size.width;
|
|
3183
|
+
finalHeight = options.page.size.height;
|
|
3184
|
+
} else {
|
|
3185
|
+
return;
|
|
3186
|
+
}
|
|
3187
|
+
const page = this.#engine.create("page");
|
|
3188
|
+
this.#engine.appendChild(scene, page);
|
|
3189
|
+
this.#engine.setWidth(page, finalWidth);
|
|
3190
|
+
this.#engine.setHeight(page, finalHeight);
|
|
3191
|
+
if (options.page.color) {
|
|
3192
|
+
const fill = this.#engine.createFill("color");
|
|
3193
|
+
this.#engine.setFill(page, fill);
|
|
3194
|
+
this.#engine.setColor(
|
|
3195
|
+
page,
|
|
3196
|
+
"fill/solid/color",
|
|
3197
|
+
NativeColorInternal.fromColor(options.page.color)
|
|
3198
|
+
);
|
|
3199
|
+
}
|
|
3200
|
+
}
|
|
3201
|
+
/**
|
|
3202
|
+
* Return the currently active scene.
|
|
3203
|
+
* @returns The scene or null, if none was created yet.
|
|
3204
|
+
*/
|
|
3205
|
+
get() {
|
|
3206
|
+
const scenes = this.#engine.findByType("scene");
|
|
3207
|
+
return scenes.length > 0 ? scenes[0] : null;
|
|
3208
|
+
}
|
|
3209
|
+
/**
|
|
3210
|
+
* Load the contents of a scene file.
|
|
3211
|
+
* @param sceneContent - The scene file contents, a base64 string.
|
|
3212
|
+
* @param overrideEditorConfig - Whether to override editor configuration.
|
|
3213
|
+
* @param waitForResources - Whether to wait for all resources to finish loading.
|
|
3214
|
+
* @returns A handle to the loaded scene.
|
|
3215
|
+
*/
|
|
3216
|
+
async loadFromString(sceneContent, overrideEditorConfig = false, waitForResources = false) {
|
|
3217
|
+
return this.#engine.loadSceneFromString(
|
|
3218
|
+
sceneContent,
|
|
3219
|
+
overrideEditorConfig,
|
|
3220
|
+
waitForResources
|
|
3221
|
+
);
|
|
3222
|
+
}
|
|
3223
|
+
/**
|
|
3224
|
+
* Load a scene from the URL to the scene file.
|
|
3225
|
+
* @param url - The URL of the scene file.
|
|
3226
|
+
* @param overrideEditorConfig - Whether to override editor configuration.
|
|
3227
|
+
* @param waitForResources - Whether to wait for all resources to finish loading.
|
|
3228
|
+
* @returns A promise that resolves with the scene ID.
|
|
3229
|
+
*/
|
|
3230
|
+
async loadFromURL(url, overrideEditorConfig = false, waitForResources = false) {
|
|
3231
|
+
return this.#engine.loadSceneFromURL(
|
|
3232
|
+
url,
|
|
3233
|
+
overrideEditorConfig,
|
|
3234
|
+
waitForResources
|
|
3235
|
+
);
|
|
3236
|
+
}
|
|
3237
|
+
/**
|
|
3238
|
+
* Load a previously archived scene from the URL to the scene file.
|
|
3239
|
+
* Also supports data URIs (data:application/zip;base64,...) which are converted to buffer:// protocol internally.
|
|
3240
|
+
* @param url - The URL of the scene archive file, or a data URI containing base64-encoded archive data.
|
|
3241
|
+
* @param overrideEditorConfig - Whether to override editor configuration.
|
|
3242
|
+
* @param waitForResources - Whether to wait for all resources to finish loading.
|
|
3243
|
+
* @returns A promise that resolves with the scene ID.
|
|
3244
|
+
*/
|
|
3245
|
+
async loadFromArchiveURL(url, overrideEditorConfig = false, waitForResources = false) {
|
|
3246
|
+
if (url.startsWith("data:")) {
|
|
3247
|
+
const matches = url.match(/^data:([^;,]+)?(?:;base64)?,(.*)$/);
|
|
3248
|
+
if (!matches) {
|
|
3249
|
+
throw new Error("Invalid data URI format");
|
|
3250
|
+
}
|
|
3251
|
+
const base64Data = matches[2];
|
|
3252
|
+
const buffer = Buffer.from(base64Data, "base64");
|
|
3253
|
+
const bufferUri = this.#engine.createBuffer();
|
|
3254
|
+
this.#engine.setBufferData(bufferUri, 0, new Uint8Array(buffer));
|
|
3255
|
+
try {
|
|
3256
|
+
return await this.#engine.loadSceneFromArchiveURL(
|
|
3257
|
+
bufferUri,
|
|
3258
|
+
overrideEditorConfig,
|
|
3259
|
+
waitForResources
|
|
3260
|
+
);
|
|
3261
|
+
} finally {
|
|
3262
|
+
this.#engine.destroyBuffer(bufferUri);
|
|
3263
|
+
}
|
|
3264
|
+
}
|
|
3265
|
+
return this.#engine.loadSceneFromArchiveURL(
|
|
3266
|
+
url,
|
|
3267
|
+
overrideEditorConfig,
|
|
3268
|
+
waitForResources
|
|
3269
|
+
);
|
|
3270
|
+
}
|
|
3271
|
+
/**
|
|
3272
|
+
* Serializes the current scene into a string.
|
|
3273
|
+
*
|
|
3274
|
+
* Optionally accepts a `compression` option to apply Zstd compression to
|
|
3275
|
+
* the output. When compression is enabled the returned string contains
|
|
3276
|
+
* raw compressed bytes (not base64) — pass it back to `loadFromString`
|
|
3277
|
+
* to round-trip.
|
|
3278
|
+
*
|
|
3279
|
+
* @returns A promise that resolves with the serialized scene.
|
|
3280
|
+
*/
|
|
3281
|
+
async saveToString(options) {
|
|
3282
|
+
const scene = this.get();
|
|
3283
|
+
if (scene === null) {
|
|
3284
|
+
throw new Error("No scene available.");
|
|
3285
|
+
}
|
|
3286
|
+
return this.#engine.saveSceneToString(scene, options);
|
|
3287
|
+
}
|
|
3288
|
+
/**
|
|
3289
|
+
* Saves the current scene and all of its referenced assets into an archive.
|
|
3290
|
+
* @returns A promise that resolves with a Uint8Array.
|
|
3291
|
+
*/
|
|
3292
|
+
async saveToArchive() {
|
|
3293
|
+
const scene = this.get();
|
|
3294
|
+
if (scene === null) {
|
|
3295
|
+
throw new Error("No scene available.");
|
|
3296
|
+
}
|
|
3297
|
+
const buffer = await this.#engine.saveSceneToArchive(scene);
|
|
3298
|
+
return new Blob([buffer]);
|
|
3299
|
+
}
|
|
3300
|
+
/**
|
|
3301
|
+
* Loads the given image and creates a scene with a single page showing the image.
|
|
3302
|
+
* @param url - The image URL.
|
|
3303
|
+
* @param dpi - The scene's DPI.
|
|
3304
|
+
* @param pixelScaleFactor - The display's pixel scale factor.
|
|
3305
|
+
* @returns A promise that resolves with the scene ID.
|
|
3306
|
+
*/
|
|
3307
|
+
/**
|
|
3308
|
+
* Loads the given image and creates a scene with a single page showing the image.
|
|
3309
|
+
*
|
|
3310
|
+
* @remarks The 4th/5th/6th args (`sceneLayout`, `spacing`,
|
|
3311
|
+
* `spacingInScreenSpace`) are part of `@cesdk/node`'s signature and
|
|
3312
|
+
* accepted here for shape parity. The C++ binding currently hardcodes
|
|
3313
|
+
* `Free`/`0.f`/`false`; non-default values are not yet plumbed
|
|
3314
|
+
* through. A warning is emitted when a caller passes a non-default
|
|
3315
|
+
* value so the discrepancy is visible.
|
|
3316
|
+
*
|
|
3317
|
+
* @public
|
|
3318
|
+
*/
|
|
3319
|
+
async createFromImage(url, dpi = 300, pixelScaleFactor = 1, sceneLayout, spacing, spacingInScreenSpace) {
|
|
3320
|
+
if (sceneLayout !== void 0 && sceneLayout !== "Free" || spacing !== void 0 && spacing !== 0 || spacingInScreenSpace !== void 0 && spacingInScreenSpace !== false) {
|
|
3321
|
+
console.warn(
|
|
3322
|
+
`[@cesdk/node-native] scene.createFromImage() arguments 'sceneLayout' / 'spacing' / 'spacingInScreenSpace' are accepted for shape parity but not yet plumbed through the C++ binding. The engine will use defaults (Free / 0 / false).`
|
|
3323
|
+
);
|
|
3324
|
+
}
|
|
3325
|
+
return this.#engine.createSceneFromImage(url, dpi, pixelScaleFactor);
|
|
3326
|
+
}
|
|
3327
|
+
/**
|
|
3328
|
+
* Loads the given video and creates a scene with a single page showing the video.
|
|
3329
|
+
* @param url - The video URL.
|
|
3330
|
+
* @returns A promise that resolves with the scene ID.
|
|
3331
|
+
*/
|
|
3332
|
+
async createFromVideo(url) {
|
|
3333
|
+
return this.#engine.createSceneFromVideo(url);
|
|
3334
|
+
}
|
|
3335
|
+
/**
|
|
3336
|
+
* Applies the contents of the given template scene to the currently loaded scene.
|
|
3337
|
+
* @param content - The template scene file contents, a base64 string.
|
|
3338
|
+
* @returns A Promise that resolves once the template was applied.
|
|
3339
|
+
*/
|
|
3340
|
+
async applyTemplateFromString(content) {
|
|
3341
|
+
return this.#engine.applyTemplateFromString(content);
|
|
3342
|
+
}
|
|
3343
|
+
/**
|
|
3344
|
+
* Applies the contents of the given template scene to the currently loaded scene.
|
|
3345
|
+
* @param url - The url to the template scene file.
|
|
3346
|
+
* @returns A Promise that resolves once the template was applied.
|
|
3347
|
+
*/
|
|
3348
|
+
async applyTemplateFromURL(url) {
|
|
3349
|
+
return this.#engine.applyTemplateFromURL(url);
|
|
3350
|
+
}
|
|
3351
|
+
/**
|
|
3352
|
+
* Get the current scene mode.
|
|
3353
|
+
* @deprecated Scene mode no longer affects engine behavior. All features work regardless of mode.
|
|
3354
|
+
* @returns The current mode of the scene, or null if no mode has been set.
|
|
3355
|
+
*/
|
|
3356
|
+
getMode() {
|
|
3357
|
+
const scene = this.get();
|
|
3358
|
+
if (scene === null) {
|
|
3359
|
+
return null;
|
|
3360
|
+
}
|
|
3361
|
+
try {
|
|
3362
|
+
return this.#engine.getSceneMode(scene);
|
|
3363
|
+
} catch {
|
|
3364
|
+
return null;
|
|
3365
|
+
}
|
|
3366
|
+
}
|
|
3367
|
+
/**
|
|
3368
|
+
* Set the mode of the current scene.
|
|
3369
|
+
* @param mode - The new mode for the scene ('Design' or 'Video').
|
|
3370
|
+
*/
|
|
3371
|
+
setMode(mode) {
|
|
3372
|
+
const scene = this.get();
|
|
3373
|
+
if (scene === null) {
|
|
3374
|
+
throw new Error("No scene available.");
|
|
3375
|
+
}
|
|
3376
|
+
this.#engine.setSceneMode(scene, mode);
|
|
3377
|
+
}
|
|
3378
|
+
/**
|
|
3379
|
+
* Converts all values of the current scene into the given design unit.
|
|
3380
|
+
* @param designUnit - The new design unit of the scene.
|
|
3381
|
+
*/
|
|
3382
|
+
setDesignUnit(designUnit) {
|
|
3383
|
+
const scene = this.get();
|
|
3384
|
+
if (scene === null) {
|
|
3385
|
+
throw new Error("No scene available.");
|
|
3386
|
+
}
|
|
3387
|
+
this.#engine.setDesignUnit(scene, designUnit);
|
|
3388
|
+
}
|
|
3389
|
+
/**
|
|
3390
|
+
* Returns the design unit of the current scene.
|
|
3391
|
+
* @returns The current design unit.
|
|
3392
|
+
*/
|
|
3393
|
+
getDesignUnit() {
|
|
3394
|
+
const scene = this.get();
|
|
3395
|
+
if (scene === null) {
|
|
3396
|
+
throw new Error("No scene available.");
|
|
3397
|
+
}
|
|
3398
|
+
return this.#engine.getDesignUnit(scene);
|
|
3399
|
+
}
|
|
3400
|
+
/**
|
|
3401
|
+
* Sets the unit ('Pixel' | 'Point') in which the current scene's font sizes
|
|
3402
|
+
* are interpreted at the API boundary (setTextFontSize / getTextFontSizes).
|
|
3403
|
+
* The engine stores font sizes in points internally.
|
|
3404
|
+
* @param unit - The new font-size unit.
|
|
3405
|
+
*/
|
|
3406
|
+
setFontSizeUnit(unit) {
|
|
3407
|
+
const scene = this.get();
|
|
3408
|
+
if (scene === null) {
|
|
3409
|
+
throw new Error("No scene available.");
|
|
3410
|
+
}
|
|
3411
|
+
this.#engine.setFontSizeUnit(scene, unit);
|
|
3412
|
+
}
|
|
3413
|
+
/**
|
|
3414
|
+
* Returns the font-size unit of the current scene ('Pixel' | 'Point').
|
|
3415
|
+
* @returns The current font-size unit.
|
|
3416
|
+
*/
|
|
3417
|
+
getFontSizeUnit() {
|
|
3418
|
+
const scene = this.get();
|
|
3419
|
+
if (scene === null) {
|
|
3420
|
+
throw new Error("No scene available.");
|
|
3421
|
+
}
|
|
3422
|
+
return this.#engine.getFontSizeUnit(scene);
|
|
3423
|
+
}
|
|
3424
|
+
/** Start or stop playback of the current page. */
|
|
3425
|
+
setPlaying(play) {
|
|
3426
|
+
const page = this.getCurrentPage();
|
|
3427
|
+
if (page == null) {
|
|
3428
|
+
throw new Error("No page to play");
|
|
3429
|
+
}
|
|
3430
|
+
this.#engine.setPlaying(page, play);
|
|
3431
|
+
}
|
|
3432
|
+
/**
|
|
3433
|
+
* Get the layout of the current scene.
|
|
3434
|
+
* @returns The current layout of the scene.
|
|
3435
|
+
*/
|
|
3436
|
+
getLayout() {
|
|
3437
|
+
const scene = this.get();
|
|
3438
|
+
if (scene === null) {
|
|
3439
|
+
throw new Error("No scene available.");
|
|
3440
|
+
}
|
|
3441
|
+
return this.#engine.getSceneLayout(scene);
|
|
3442
|
+
}
|
|
3443
|
+
/**
|
|
3444
|
+
* Set the layout of the current scene.
|
|
3445
|
+
* @param layout - The new layout for the scene.
|
|
3446
|
+
*/
|
|
3447
|
+
setLayout(layout) {
|
|
3448
|
+
const scene = this.get();
|
|
3449
|
+
if (scene === null) {
|
|
3450
|
+
throw new Error("No scene available.");
|
|
3451
|
+
}
|
|
3452
|
+
this.#engine.setSceneLayout(scene, layout);
|
|
3453
|
+
}
|
|
3454
|
+
/**
|
|
3455
|
+
* Get the sorted list of pages in the scene.
|
|
3456
|
+
* @returns The sorted list of pages in the scene.
|
|
3457
|
+
*/
|
|
3458
|
+
getPages() {
|
|
3459
|
+
const scene = this.get();
|
|
3460
|
+
if (scene === null) {
|
|
3461
|
+
return [];
|
|
3462
|
+
}
|
|
3463
|
+
return this.#engine.getPages(scene);
|
|
3464
|
+
}
|
|
3465
|
+
/**
|
|
3466
|
+
* Add a new page to the scene.
|
|
3467
|
+
* @param scene - Optional scene ID. If not provided, uses the current scene.
|
|
3468
|
+
* @returns The ID of the newly created page.
|
|
3469
|
+
*/
|
|
3470
|
+
addPage(scene) {
|
|
3471
|
+
const sceneId = scene ?? this.get();
|
|
3472
|
+
if (sceneId === null) {
|
|
3473
|
+
throw new Error("No scene available.");
|
|
3474
|
+
}
|
|
3475
|
+
const page = this.#engine.create("page");
|
|
3476
|
+
this.#engine.appendChild(sceneId, page);
|
|
3477
|
+
return page;
|
|
3478
|
+
}
|
|
3479
|
+
/**
|
|
3480
|
+
* Get the current page.
|
|
3481
|
+
* @returns The current page in the scene or null when there is no scene
|
|
3482
|
+
* available or no current page is set.
|
|
3483
|
+
*/
|
|
3484
|
+
getCurrentPage(scene) {
|
|
3485
|
+
const sceneId = scene ?? this.get();
|
|
3486
|
+
if (sceneId === null) {
|
|
3487
|
+
return null;
|
|
3488
|
+
}
|
|
3489
|
+
return this.#engine.getCurrentPage(sceneId);
|
|
3490
|
+
}
|
|
3491
|
+
/**
|
|
3492
|
+
* Find all blocks with the given type sorted by the distance to viewport center.
|
|
3493
|
+
* @param type - The type to search for.
|
|
3494
|
+
* @returns A list of block ids sorted by distance to viewport center.
|
|
3495
|
+
*/
|
|
3496
|
+
findNearestToViewPortCenterByType(type) {
|
|
3497
|
+
const scene = this.get();
|
|
3498
|
+
if (scene === null) {
|
|
3499
|
+
return [];
|
|
3500
|
+
}
|
|
3501
|
+
return this.#engine.findNearestToViewPortCenterByType(scene, type) || [];
|
|
3502
|
+
}
|
|
3503
|
+
/**
|
|
3504
|
+
* Find all blocks with the given kind sorted by the distance to viewport center.
|
|
3505
|
+
* @param kind - The kind to search for.
|
|
3506
|
+
* @returns A list of block ids sorted by distance to viewport center.
|
|
3507
|
+
*/
|
|
3508
|
+
findNearestToViewPortCenterByKind(kind) {
|
|
3509
|
+
const scene = this.get();
|
|
3510
|
+
if (scene === null) {
|
|
3511
|
+
return [];
|
|
3512
|
+
}
|
|
3513
|
+
return this.#engine.findNearestToViewPortCenterByKind(scene, kind) || [];
|
|
3514
|
+
}
|
|
3515
|
+
/**
|
|
3516
|
+
* Set the zoom level of the scene.
|
|
3517
|
+
* @param zoomLevel - The new zoom level.
|
|
3518
|
+
*/
|
|
3519
|
+
setZoomLevel(zoomLevel = 1) {
|
|
3520
|
+
const scene = this.get();
|
|
3521
|
+
if (scene === null) {
|
|
3522
|
+
throw new Error("No scene available.");
|
|
3523
|
+
}
|
|
3524
|
+
this.#engine.setZoomLevel(scene, zoomLevel);
|
|
3525
|
+
}
|
|
3526
|
+
/**
|
|
3527
|
+
* Get the zoom level of the scene.
|
|
3528
|
+
* @returns The zoom level of the scene.
|
|
3529
|
+
*/
|
|
3530
|
+
getZoomLevel() {
|
|
3531
|
+
const scene = this.get();
|
|
3532
|
+
if (scene === null) {
|
|
3533
|
+
throw new Error("No scene available.");
|
|
3534
|
+
}
|
|
3535
|
+
return this.#engine.getZoomLevel(scene);
|
|
3536
|
+
}
|
|
3537
|
+
async zoomToBlock(id, paddingLeftOrOptions, paddingTop, paddingRight, paddingBottom) {
|
|
3538
|
+
const options = typeof paddingLeftOrOptions === "object" ? paddingLeftOrOptions : {
|
|
3539
|
+
padding: {
|
|
3540
|
+
left: paddingLeftOrOptions ?? 0,
|
|
3541
|
+
top: paddingTop ?? 0,
|
|
3542
|
+
right: paddingRight ?? 0,
|
|
3543
|
+
bottom: paddingBottom ?? 0
|
|
3544
|
+
}
|
|
3545
|
+
};
|
|
3546
|
+
const paddings = {
|
|
3547
|
+
left: 0,
|
|
3548
|
+
top: 0,
|
|
3549
|
+
right: 0,
|
|
3550
|
+
bottom: 0
|
|
3551
|
+
};
|
|
3552
|
+
if (options.padding != null) {
|
|
3553
|
+
if (typeof options.padding === "number") {
|
|
3554
|
+
paddings.left = options.padding;
|
|
3555
|
+
paddings.top = options.padding;
|
|
3556
|
+
paddings.right = options.padding;
|
|
3557
|
+
paddings.bottom = options.padding;
|
|
3558
|
+
} else {
|
|
3559
|
+
if ("x" in options.padding || "y" in options.padding) {
|
|
3560
|
+
paddings.left = options.padding.x ?? paddings.left;
|
|
3561
|
+
paddings.right = options.padding.x ?? paddings.right;
|
|
3562
|
+
paddings.top = options.padding.y ?? paddings.top;
|
|
3563
|
+
paddings.bottom = options.padding.y ?? paddings.bottom;
|
|
3564
|
+
}
|
|
3565
|
+
if ("left" in options.padding || "top" in options.padding || "right" in options.padding || "bottom" in options.padding) {
|
|
3566
|
+
paddings.left = options.padding.left ?? paddings.left;
|
|
3567
|
+
paddings.top = options.padding.top ?? paddings.top;
|
|
3568
|
+
paddings.right = options.padding.right ?? paddings.right;
|
|
3569
|
+
paddings.bottom = options.padding.bottom ?? paddings.bottom;
|
|
3570
|
+
}
|
|
3571
|
+
}
|
|
3572
|
+
}
|
|
3573
|
+
if (options.animate) {
|
|
3574
|
+
const animationOptions = {
|
|
3575
|
+
duration: 0.5,
|
|
3576
|
+
easing: "EaseInOut",
|
|
3577
|
+
interruptible: false
|
|
3578
|
+
};
|
|
3579
|
+
if (typeof options.animate === "object") {
|
|
3580
|
+
animationOptions.duration = options.animate.duration ?? animationOptions.duration;
|
|
3581
|
+
animationOptions.easing = options.animate.easing ?? animationOptions.easing;
|
|
3582
|
+
animationOptions.interruptible = options.animate.interruptible ?? animationOptions.interruptible;
|
|
3583
|
+
}
|
|
3584
|
+
return this.#engine.zoomToBlockWithAnimation(
|
|
3585
|
+
id,
|
|
3586
|
+
paddings.left,
|
|
3587
|
+
paddings.top,
|
|
3588
|
+
paddings.right,
|
|
3589
|
+
paddings.bottom,
|
|
3590
|
+
animationOptions.duration,
|
|
3591
|
+
animationOptions.easing,
|
|
3592
|
+
animationOptions.interruptible
|
|
3593
|
+
);
|
|
3594
|
+
} else {
|
|
3595
|
+
return this.#engine.zoomToBlock(
|
|
3596
|
+
id,
|
|
3597
|
+
paddings.left,
|
|
3598
|
+
paddings.top,
|
|
3599
|
+
paddings.right,
|
|
3600
|
+
paddings.bottom
|
|
3601
|
+
);
|
|
3602
|
+
}
|
|
3603
|
+
}
|
|
3604
|
+
/**
|
|
3605
|
+
* Continually adjust the zoom level to fit the block's bounding box on the
|
|
3606
|
+
* chosen axis. For 'Horizontal'/'Vertical', the second/third arguments are
|
|
3607
|
+
* `paddingBefore`/`paddingAfter` along that axis. For 'Both' the four
|
|
3608
|
+
* arguments map to left/top/right/bottom.
|
|
3609
|
+
*
|
|
3610
|
+
* @param id - The block to follow.
|
|
3611
|
+
* @param axis - 'Horizontal' | 'Vertical' | 'Both'.
|
|
3612
|
+
*/
|
|
3613
|
+
enableZoomAutoFit(id, axis, paddingBeforeOrLeft = 0, paddingAfterOrTop = 0, paddingRight = 0, paddingBottom = 0) {
|
|
3614
|
+
if (axis === "Horizontal") {
|
|
3615
|
+
this.#engine.enableZoomAutoFit(
|
|
3616
|
+
id,
|
|
3617
|
+
axis,
|
|
3618
|
+
paddingBeforeOrLeft,
|
|
3619
|
+
0,
|
|
3620
|
+
paddingAfterOrTop,
|
|
3621
|
+
0
|
|
3622
|
+
);
|
|
3623
|
+
return;
|
|
3624
|
+
}
|
|
3625
|
+
if (axis === "Vertical") {
|
|
3626
|
+
this.#engine.enableZoomAutoFit(
|
|
3627
|
+
id,
|
|
3628
|
+
axis,
|
|
3629
|
+
0,
|
|
3630
|
+
paddingBeforeOrLeft,
|
|
3631
|
+
0,
|
|
3632
|
+
paddingAfterOrTop
|
|
3633
|
+
);
|
|
3634
|
+
return;
|
|
3635
|
+
}
|
|
3636
|
+
this.#engine.enableZoomAutoFit(
|
|
3637
|
+
id,
|
|
3638
|
+
axis,
|
|
3639
|
+
paddingBeforeOrLeft,
|
|
3640
|
+
paddingAfterOrTop,
|
|
3641
|
+
paddingRight,
|
|
3642
|
+
paddingBottom
|
|
3643
|
+
);
|
|
3644
|
+
}
|
|
3645
|
+
/**
|
|
3646
|
+
* Disables any previously set zoom auto-fit.
|
|
3647
|
+
* @param blockOrScene - The scene or a block in the scene.
|
|
3648
|
+
*/
|
|
3649
|
+
disableZoomAutoFit(blockOrScene) {
|
|
3650
|
+
this.#engine.disableZoomAutoFit(blockOrScene);
|
|
3651
|
+
}
|
|
3652
|
+
/**
|
|
3653
|
+
* Queries whether zoom auto-fit is enabled for the given block.
|
|
3654
|
+
* @param blockOrScene - The scene or a block in the scene.
|
|
3655
|
+
* @returns True if auto-fit is set, false otherwise.
|
|
3656
|
+
*/
|
|
3657
|
+
isZoomAutoFitEnabled(blockOrScene) {
|
|
3658
|
+
return this.#engine.isZoomAutoFitEnabled(blockOrScene);
|
|
3659
|
+
}
|
|
3660
|
+
/**
|
|
3661
|
+
* Continually clamp the camera position so that the given blocks stay
|
|
3662
|
+
* within view (with optional padding).
|
|
3663
|
+
* @experimental
|
|
3664
|
+
*/
|
|
3665
|
+
unstable_enableCameraPositionClamping(blocks, paddingLeft = 0, paddingTop = 0, paddingRight = 0, paddingBottom = 0, scaledPaddingLeft = 0, scaledPaddingTop = 0, scaledPaddingRight = 0, scaledPaddingBottom = 0) {
|
|
3666
|
+
this.#engine.unstable_enableCameraPositionClamping(
|
|
3667
|
+
blocks,
|
|
3668
|
+
paddingLeft,
|
|
3669
|
+
paddingTop,
|
|
3670
|
+
paddingRight,
|
|
3671
|
+
paddingBottom,
|
|
3672
|
+
scaledPaddingLeft,
|
|
3673
|
+
scaledPaddingTop,
|
|
3674
|
+
scaledPaddingRight,
|
|
3675
|
+
scaledPaddingBottom
|
|
3676
|
+
);
|
|
3677
|
+
}
|
|
3678
|
+
unstable_disableCameraPositionClamping(block) {
|
|
3679
|
+
const target = block ?? this.get();
|
|
3680
|
+
if (target == null) throw new Error("No scene available.");
|
|
3681
|
+
this.#engine.unstable_disableCameraPositionClamping(target);
|
|
3682
|
+
}
|
|
3683
|
+
unstable_isCameraPositionClampingEnabled(block) {
|
|
3684
|
+
const target = block ?? this.get();
|
|
3685
|
+
if (target == null) throw new Error("No scene available.");
|
|
3686
|
+
return this.#engine.unstable_isCameraPositionClampingEnabled(target);
|
|
3687
|
+
}
|
|
3688
|
+
/**
|
|
3689
|
+
* Continually clamp the camera zoom level to the range
|
|
3690
|
+
* `[minZoomLimit, maxZoomLimit]` while showing the given blocks (with
|
|
3691
|
+
* optional padding).
|
|
3692
|
+
* @experimental
|
|
3693
|
+
*/
|
|
3694
|
+
unstable_enableCameraZoomClamping(blocks, minZoomLimit = -1, maxZoomLimit = -1, paddingLeft = 0, paddingTop = 0, paddingRight = 0, paddingBottom = 0) {
|
|
3695
|
+
this.#engine.unstable_enableCameraZoomClamping(
|
|
3696
|
+
blocks,
|
|
3697
|
+
minZoomLimit,
|
|
3698
|
+
maxZoomLimit,
|
|
3699
|
+
paddingLeft,
|
|
3700
|
+
paddingTop,
|
|
3701
|
+
paddingRight,
|
|
3702
|
+
paddingBottom
|
|
3703
|
+
);
|
|
3704
|
+
}
|
|
3705
|
+
unstable_disableCameraZoomClamping(block) {
|
|
3706
|
+
const target = block ?? this.get();
|
|
3707
|
+
if (target == null) throw new Error("No scene available.");
|
|
3708
|
+
this.#engine.unstable_disableCameraZoomClamping(target);
|
|
3709
|
+
}
|
|
3710
|
+
unstable_isCameraZoomClampingEnabled(block) {
|
|
3711
|
+
const target = block ?? this.get();
|
|
3712
|
+
if (target == null) throw new Error("No scene available.");
|
|
3713
|
+
return this.#engine.unstable_isCameraZoomClampingEnabled(target);
|
|
3714
|
+
}
|
|
3715
|
+
/**
|
|
3716
|
+
* Subscribe to zoom-level changes.
|
|
3717
|
+
* @param callback - Called whenever the zoom level changes.
|
|
3718
|
+
* @returns A function that unsubscribes when called.
|
|
3719
|
+
*/
|
|
3720
|
+
onZoomLevelChanged(callback) {
|
|
3721
|
+
const id = this.#engine.subscribeToZoomLevel(callback);
|
|
3722
|
+
return () => this.#engine.unsubscribe(id);
|
|
3723
|
+
}
|
|
3724
|
+
/**
|
|
3725
|
+
* Subscribe to active-scene changes.
|
|
3726
|
+
* @param callback - Called whenever the active scene changes.
|
|
3727
|
+
* @returns A function that unsubscribes when called.
|
|
3728
|
+
*/
|
|
3729
|
+
onActiveChanged(callback) {
|
|
3730
|
+
const id = this.#engine.subscribeToActiveSceneChange(callback);
|
|
3731
|
+
return () => this.#engine.unsubscribe(id);
|
|
3732
|
+
}
|
|
3733
|
+
};
|
|
3734
|
+
var EditorAPI = class {
|
|
3735
|
+
#engine;
|
|
3736
|
+
constructor(engine) {
|
|
3737
|
+
this.#engine = engine;
|
|
3738
|
+
}
|
|
3739
|
+
getEditMode() {
|
|
3740
|
+
return this.#engine.getEditMode();
|
|
3741
|
+
}
|
|
3742
|
+
setEditMode(mode) {
|
|
3743
|
+
this.#engine.setEditMode(mode);
|
|
3744
|
+
}
|
|
3745
|
+
/**
|
|
3746
|
+
* Returns the JWT string of the currently active license. An empty string
|
|
3747
|
+
* indicates the engine is in Evaluation mode (the trial license created
|
|
3748
|
+
* when init() is called with an empty/null/undefined license). Throws if
|
|
3749
|
+
* the engine has no active license at all.
|
|
3750
|
+
*
|
|
3751
|
+
* Mirrors @cesdk/node's `engine.editor.getActiveLicense()`.
|
|
3752
|
+
* @internal
|
|
3753
|
+
*/
|
|
3754
|
+
getActiveLicense() {
|
|
3755
|
+
return this.#engine.getActiveLicense();
|
|
3756
|
+
}
|
|
3757
|
+
/**
|
|
3758
|
+
* Activate (or re-activate) the engine with a license key. Pass an empty
|
|
3759
|
+
* string to drop into Evaluation mode. Mirrors
|
|
3760
|
+
* `@cesdk/node`'s `engine.editor.unlockWithLicense()`.
|
|
3761
|
+
*
|
|
3762
|
+
* Most callers should pass `license` via `CreativeEngine.init({ license })`
|
|
3763
|
+
* — `init` calls this internally. Use this method only to switch licenses
|
|
3764
|
+
* at runtime (e.g. trial → paid upgrade in place).
|
|
3765
|
+
*/
|
|
3766
|
+
unlockWithLicense(license) {
|
|
3767
|
+
this.#engine.unlockWithLicense(license);
|
|
3768
|
+
}
|
|
3769
|
+
// Settings
|
|
3770
|
+
getSettingBool(key) {
|
|
3771
|
+
const settingType = this.getSettingType(key);
|
|
3772
|
+
if (settingType !== "Bool") {
|
|
3773
|
+
throw new Error(
|
|
3774
|
+
`Setting '${key}' is of type '${settingType}', not 'Bool'`
|
|
3775
|
+
);
|
|
3776
|
+
}
|
|
3777
|
+
return this.#engine.getSettingBool(key);
|
|
3778
|
+
}
|
|
3779
|
+
setSettingBool(key, value) {
|
|
3780
|
+
this.#engine.setSettingBool(key, value);
|
|
3781
|
+
}
|
|
3782
|
+
getSettingInt(key) {
|
|
3783
|
+
return this.#engine.getSettingInt(key);
|
|
3784
|
+
}
|
|
3785
|
+
setSettingInt(key, value) {
|
|
3786
|
+
this.#engine.setSettingInt(key, value);
|
|
3787
|
+
}
|
|
3788
|
+
getSettingFloat(key) {
|
|
3789
|
+
return this.#engine.getSettingFloat(key);
|
|
3790
|
+
}
|
|
3791
|
+
setSettingFloat(key, value) {
|
|
3792
|
+
this.#engine.setSettingFloat(key, value);
|
|
3793
|
+
}
|
|
3794
|
+
getSettingString(key) {
|
|
3795
|
+
return this.#engine.getSettingString(key);
|
|
3796
|
+
}
|
|
3797
|
+
setSettingString(key, value) {
|
|
3798
|
+
this.#engine.setSettingString(key, value);
|
|
3799
|
+
}
|
|
3800
|
+
getSettingColor(key) {
|
|
3801
|
+
const internalColor = this.#engine.getSettingColor(
|
|
3802
|
+
key
|
|
3803
|
+
);
|
|
3804
|
+
return NativeColorInternal.toColor(internalColor);
|
|
3805
|
+
}
|
|
3806
|
+
setSettingColor(key, value) {
|
|
3807
|
+
const internalColor = NativeColorInternal.fromColor(value);
|
|
3808
|
+
this.#engine.setSettingColor(key, internalColor);
|
|
3809
|
+
}
|
|
3810
|
+
getSettingEnum(key) {
|
|
3811
|
+
return this.#engine.getSettingEnum(key);
|
|
3812
|
+
}
|
|
3813
|
+
setSettingEnum(key, value) {
|
|
3814
|
+
const settingType = this.getSettingType(key);
|
|
3815
|
+
if (settingType !== "Enum") {
|
|
3816
|
+
throw new Error(
|
|
3817
|
+
`Setting '${key}' is of type '${settingType}', not 'Enum'`
|
|
3818
|
+
);
|
|
3819
|
+
}
|
|
3820
|
+
this.#engine.setSettingEnum(key, value);
|
|
3821
|
+
}
|
|
3822
|
+
findAllSettings() {
|
|
3823
|
+
return this.#engine.findAllSettings();
|
|
3824
|
+
}
|
|
3825
|
+
getSettingType(key) {
|
|
3826
|
+
const allSettings = this.#engine.findAllSettings();
|
|
3827
|
+
if (!allSettings.includes(key)) {
|
|
3828
|
+
throw new Error(`Setting '${key}' does not exist`);
|
|
3829
|
+
}
|
|
3830
|
+
return this.#engine.getSettingType(key);
|
|
3831
|
+
}
|
|
3832
|
+
getSettingEnumOptions(key) {
|
|
3833
|
+
return this.#engine.getSettingEnumOptions(key);
|
|
3834
|
+
}
|
|
3835
|
+
/**
|
|
3836
|
+
* Generic setting getter that dispatches to the typed getter based on
|
|
3837
|
+
* `getSettingType`.
|
|
3838
|
+
*/
|
|
3839
|
+
getSetting(key) {
|
|
3840
|
+
const settingType = this.getSettingType(key);
|
|
3841
|
+
switch (settingType) {
|
|
3842
|
+
case "Bool":
|
|
3843
|
+
return this.#engine.getSettingBool(key);
|
|
3844
|
+
case "Int":
|
|
3845
|
+
return this.#engine.getSettingInt(key);
|
|
3846
|
+
case "Float":
|
|
3847
|
+
return this.#engine.getSettingFloat(key);
|
|
3848
|
+
case "String":
|
|
3849
|
+
return this.#engine.getSettingString(key);
|
|
3850
|
+
case "Color": {
|
|
3851
|
+
const internalColor = this.#engine.getSettingColor(
|
|
3852
|
+
key
|
|
3853
|
+
);
|
|
3854
|
+
return NativeColorInternal.toColor(internalColor);
|
|
3855
|
+
}
|
|
3856
|
+
case "Enum":
|
|
3857
|
+
return this.#engine.getSettingEnum(key);
|
|
3858
|
+
default:
|
|
3859
|
+
throw new Error(
|
|
3860
|
+
`Unknown setting type for key '${key}': ${settingType}`
|
|
3861
|
+
);
|
|
3862
|
+
}
|
|
3863
|
+
}
|
|
3864
|
+
/**
|
|
3865
|
+
* Generic setting setter — dispatches to the typed setter via
|
|
3866
|
+
* `getSettingType`.
|
|
3867
|
+
*/
|
|
3868
|
+
setSetting(key, value) {
|
|
3869
|
+
const settingType = this.getSettingType(key);
|
|
3870
|
+
switch (settingType) {
|
|
3871
|
+
case "Bool":
|
|
3872
|
+
this.#engine.setSettingBool(key, value);
|
|
3873
|
+
return;
|
|
3874
|
+
case "Int":
|
|
3875
|
+
this.#engine.setSettingInt(key, value);
|
|
3876
|
+
return;
|
|
3877
|
+
case "Float":
|
|
3878
|
+
this.#engine.setSettingFloat(key, value);
|
|
3879
|
+
return;
|
|
3880
|
+
case "String":
|
|
3881
|
+
this.#engine.setSettingString(key, value);
|
|
3882
|
+
return;
|
|
3883
|
+
case "Color": {
|
|
3884
|
+
const internalColor = NativeColorInternal.fromColor(value);
|
|
3885
|
+
this.#engine.setSettingColor(key, internalColor);
|
|
3886
|
+
return;
|
|
3887
|
+
}
|
|
3888
|
+
case "Enum":
|
|
3889
|
+
this.#engine.setSettingEnum(key, value);
|
|
3890
|
+
return;
|
|
3891
|
+
default:
|
|
3892
|
+
throw new Error(
|
|
3893
|
+
`Unknown setting type for key '${key}': ${settingType}`
|
|
3894
|
+
);
|
|
3895
|
+
}
|
|
3896
|
+
}
|
|
3897
|
+
/** Get the font metrics for a font URI. */
|
|
3898
|
+
getFontMetrics(fontFileUri) {
|
|
3899
|
+
return this.#engine.getFontMetrics(fontFileUri);
|
|
3900
|
+
}
|
|
3901
|
+
/**
|
|
3902
|
+
* Set one or more rules limiting how far blocks may be moved outside their
|
|
3903
|
+
* parent page during user interactions.
|
|
3904
|
+
*/
|
|
3905
|
+
setMovementConstraint(rules) {
|
|
3906
|
+
const list = Array.isArray(rules) ? rules : [rules];
|
|
3907
|
+
for (const rule of list) {
|
|
3908
|
+
const targets = "block" in rule ? [rule.block] : "blockType" in rule ? [rule.blockType] : [];
|
|
3909
|
+
this.#engine.setMovementConstraint(targets, rule.overshoot);
|
|
3910
|
+
}
|
|
3911
|
+
}
|
|
3912
|
+
/**
|
|
3913
|
+
* Get the effective movement constraint for a block (most specific rule
|
|
3914
|
+
* wins: block > parent page > blockType > scene-wide). Returns `null`
|
|
3915
|
+
* when unconstrained.
|
|
3916
|
+
*/
|
|
3917
|
+
getMovementConstraint(id) {
|
|
3918
|
+
const value = this.#engine.getMovementConstraint(id);
|
|
3919
|
+
return value < 0 ? null : { overshoot: value };
|
|
3920
|
+
}
|
|
3921
|
+
/**
|
|
3922
|
+
* Remove movement constraints. No argument removes the scene-wide default.
|
|
3923
|
+
* `{ block }` / `{ blockType }` (or array) removes the matching scope(s).
|
|
3924
|
+
*/
|
|
3925
|
+
removeMovementConstraint(scopes) {
|
|
3926
|
+
if (scopes === void 0) {
|
|
3927
|
+
this.#engine.removeMovementConstraint([]);
|
|
3928
|
+
return;
|
|
3929
|
+
}
|
|
3930
|
+
const list = Array.isArray(scopes) ? scopes : [scopes];
|
|
3931
|
+
if (list.length === 0) return;
|
|
3932
|
+
const targets = list.map(
|
|
3933
|
+
(scope) => "block" in scope ? scope.block : scope.blockType
|
|
3934
|
+
);
|
|
3935
|
+
this.#engine.removeMovementConstraint(targets);
|
|
3936
|
+
}
|
|
3937
|
+
// Cursor
|
|
3938
|
+
getCursorType() {
|
|
3939
|
+
return this.#engine.getCursorType();
|
|
3940
|
+
}
|
|
3941
|
+
getCursorRotation() {
|
|
3942
|
+
return this.#engine.getCursorRotation();
|
|
3943
|
+
}
|
|
3944
|
+
// Safe area insets
|
|
3945
|
+
setSafeAreaInsets(insets) {
|
|
3946
|
+
this.#engine.setSafeAreaInsets(
|
|
3947
|
+
insets.left,
|
|
3948
|
+
insets.top,
|
|
3949
|
+
insets.right,
|
|
3950
|
+
insets.bottom
|
|
3951
|
+
);
|
|
3952
|
+
}
|
|
3953
|
+
getSafeAreaInsets() {
|
|
3954
|
+
return this.#engine.getSafeAreaInsets();
|
|
3955
|
+
}
|
|
3956
|
+
// Memory
|
|
3957
|
+
getUsedMemory() {
|
|
3958
|
+
return this.#engine.getUsedMemory();
|
|
3959
|
+
}
|
|
3960
|
+
getAvailableMemory() {
|
|
3961
|
+
return this.#engine.getAvailableMemory();
|
|
3962
|
+
}
|
|
3963
|
+
// Color
|
|
3964
|
+
convertColorToColorSpace(color, colorSpace) {
|
|
3965
|
+
const internalColor = NativeColorInternal.fromColor(color);
|
|
3966
|
+
let colorSpaceNum;
|
|
3967
|
+
if (colorSpace === "sRGB") {
|
|
3968
|
+
colorSpaceNum = 0 /* sRGB */;
|
|
3969
|
+
} else if (colorSpace === "CMYK") {
|
|
3970
|
+
colorSpaceNum = 1 /* CMYK */;
|
|
3971
|
+
} else if (colorSpace === "SpotColor") {
|
|
3972
|
+
colorSpaceNum = 2 /* SpotColor */;
|
|
3973
|
+
} else {
|
|
3974
|
+
colorSpaceNum = parseInt(colorSpace, 10);
|
|
3975
|
+
if (Number.isNaN(colorSpaceNum)) {
|
|
3976
|
+
throw new Error(`Unknown color space: ${colorSpace}`);
|
|
3977
|
+
}
|
|
3978
|
+
}
|
|
3979
|
+
const resultInternal = this.#engine.convertColorToColorSpace(
|
|
3980
|
+
internalColor,
|
|
3981
|
+
colorSpaceNum
|
|
3982
|
+
);
|
|
3983
|
+
return NativeColorInternal.toColor(resultInternal);
|
|
3984
|
+
}
|
|
3985
|
+
supportsP3() {
|
|
3986
|
+
return this.#engine.supportsP3();
|
|
3987
|
+
}
|
|
3988
|
+
// URI
|
|
3989
|
+
getAbsoluteURI(relativeUri) {
|
|
3990
|
+
return this.#engine.getAbsoluteURI(relativeUri);
|
|
3991
|
+
}
|
|
3992
|
+
getMimeType(uri) {
|
|
3993
|
+
return this.#engine.getMimeType(uri);
|
|
3994
|
+
}
|
|
3995
|
+
defaultURIResolver(relativePath) {
|
|
3996
|
+
return this.#engine.defaultURIResolver(relativePath);
|
|
3997
|
+
}
|
|
3998
|
+
/**
|
|
3999
|
+
* Register a synchronous URI resolver. Matches `@cesdk/node`'s
|
|
4000
|
+
* `(uri, defaultResolver) => string` signature
|
|
4001
|
+
* (`bindings/wasm/js_web/src/EditorAPI.ts`). The
|
|
4002
|
+
* `defaultResolver` argument is the engine's built-in resolver — call
|
|
4003
|
+
* it to delegate the lookup chain.
|
|
4004
|
+
*
|
|
4005
|
+
* @public
|
|
4006
|
+
*/
|
|
4007
|
+
setURIResolver(resolver) {
|
|
4008
|
+
if (resolver == null) {
|
|
4009
|
+
this.#engine.setURIResolver(
|
|
4010
|
+
(uri) => this.defaultURIResolver(uri)
|
|
4011
|
+
);
|
|
4012
|
+
return;
|
|
4013
|
+
}
|
|
4014
|
+
const wrapped = (uri) => {
|
|
4015
|
+
const defaultFn = (u) => this.defaultURIResolver(u);
|
|
4016
|
+
return resolver(uri, defaultFn);
|
|
4017
|
+
};
|
|
4018
|
+
this.#engine.setURIResolver(wrapped);
|
|
4019
|
+
}
|
|
4020
|
+
/**
|
|
4021
|
+
* Register an asynchronous URI resolver. Matches `@cesdk/node`'s
|
|
4022
|
+
* `(uri, defaultResolver) => Promise<string> | string` signature
|
|
4023
|
+
* (`bindings/wasm/js_web/src/EditorAPI.ts`). Bridges to the
|
|
4024
|
+
* native callback-style binding by adapting the returned Promise.
|
|
4025
|
+
*
|
|
4026
|
+
* Pass `null` to restore the default resolver.
|
|
4027
|
+
*
|
|
4028
|
+
* @public
|
|
4029
|
+
*/
|
|
4030
|
+
setURIResolverAsync(resolver) {
|
|
4031
|
+
if (resolver == null) {
|
|
4032
|
+
this.#engine.setURIResolverAsync(
|
|
4033
|
+
(uri, cb) => {
|
|
4034
|
+
this.getAbsoluteURI(uri).then(
|
|
4035
|
+
(resolved) => cb(resolved),
|
|
4036
|
+
(err) => cb(err instanceof Error ? err : new Error(String(err)))
|
|
4037
|
+
);
|
|
4038
|
+
}
|
|
4039
|
+
);
|
|
4040
|
+
return;
|
|
4041
|
+
}
|
|
4042
|
+
const defaultFn = async (uri) => this.getAbsoluteURI(uri);
|
|
4043
|
+
const adapter = (uri, cb) => {
|
|
4044
|
+
try {
|
|
4045
|
+
const out = resolver(uri, defaultFn);
|
|
4046
|
+
Promise.resolve(out).then(
|
|
4047
|
+
(resolved) => cb(resolved),
|
|
4048
|
+
(err) => cb(err instanceof Error ? err : new Error(String(err)))
|
|
4049
|
+
);
|
|
4050
|
+
} catch (err) {
|
|
4051
|
+
cb(err instanceof Error ? err : new Error(String(err)));
|
|
4052
|
+
}
|
|
4053
|
+
};
|
|
4054
|
+
this.#engine.setURIResolverAsync(adapter);
|
|
4055
|
+
}
|
|
4056
|
+
relocateResource(currentUri, newUri) {
|
|
4057
|
+
this.#engine.relocateResource(currentUri, newUri);
|
|
4058
|
+
}
|
|
4059
|
+
findAllMediaURIs() {
|
|
4060
|
+
return this.#engine.findAllMediaURIs();
|
|
4061
|
+
}
|
|
4062
|
+
/**
|
|
4063
|
+
* List all transient (in-engine) resources — typically `buffer://` URIs
|
|
4064
|
+
* created by importers (psd, pdf, idml) before they're uploaded to a
|
|
4065
|
+
* permanent location. Each entry is `{ uri, size }`.
|
|
4066
|
+
*
|
|
4067
|
+
* Note: WASM uses `URL` as the key name; consumers that target both
|
|
4068
|
+
* bindings should accept either (see e.g. psd-importer's
|
|
4069
|
+
* `transient-resource-relocation.test.ts`).
|
|
4070
|
+
*/
|
|
4071
|
+
findAllTransientResources() {
|
|
4072
|
+
return this.#engine.findAllTransientResources();
|
|
4073
|
+
}
|
|
4074
|
+
// Spot colors
|
|
4075
|
+
findAllSpotColors() {
|
|
4076
|
+
return this.#engine.findAllSpotColors();
|
|
4077
|
+
}
|
|
4078
|
+
getSpotColorRGBA(name) {
|
|
4079
|
+
const result = this.#engine.getSpotColorRGB(name);
|
|
4080
|
+
const tuple = Array.isArray(result) ? result.slice(0, 4) : [
|
|
4081
|
+
result.r,
|
|
4082
|
+
result.g,
|
|
4083
|
+
result.b,
|
|
4084
|
+
result.a
|
|
4085
|
+
];
|
|
4086
|
+
const rgba = tuple;
|
|
4087
|
+
rgba.r = tuple[0];
|
|
4088
|
+
rgba.g = tuple[1];
|
|
4089
|
+
rgba.b = tuple[2];
|
|
4090
|
+
rgba.a = tuple[3];
|
|
4091
|
+
return rgba;
|
|
4092
|
+
}
|
|
4093
|
+
getSpotColorCMYK(name) {
|
|
4094
|
+
const result = this.#engine.getSpotColorCMYK(name);
|
|
4095
|
+
const tuple = Array.isArray(result) ? result.slice(0, 4) : [
|
|
4096
|
+
result.c,
|
|
4097
|
+
result.m,
|
|
4098
|
+
result.y,
|
|
4099
|
+
result.k
|
|
4100
|
+
];
|
|
4101
|
+
const cmyk = tuple;
|
|
4102
|
+
cmyk.c = tuple[0];
|
|
4103
|
+
cmyk.m = tuple[1];
|
|
4104
|
+
cmyk.y = tuple[2];
|
|
4105
|
+
cmyk.k = tuple[3];
|
|
4106
|
+
cmyk.tint = !Array.isArray(result) && result.tint !== void 0 ? result.tint : 1;
|
|
4107
|
+
return cmyk;
|
|
4108
|
+
}
|
|
4109
|
+
setSpotColorRGB(name, r, g, b) {
|
|
4110
|
+
this.#engine.setSpotColorRGB(name, r, g, b);
|
|
4111
|
+
}
|
|
4112
|
+
setSpotColorCMYK(name, c, m, y, k) {
|
|
4113
|
+
this.#engine.setSpotColorCMYK(name, c, m, y, k);
|
|
4114
|
+
}
|
|
4115
|
+
removeSpotColor(name) {
|
|
4116
|
+
this.#engine.removeSpotColor(name);
|
|
4117
|
+
}
|
|
4118
|
+
// Role and scope - WASM EditorAPI methods
|
|
4119
|
+
getRole() {
|
|
4120
|
+
return this.#engine.getRole();
|
|
4121
|
+
}
|
|
4122
|
+
setRole(role) {
|
|
4123
|
+
this.#engine.setRole(role);
|
|
4124
|
+
}
|
|
4125
|
+
/**
|
|
4126
|
+
* Start the engine's analytics tracking pipeline. Mirrors
|
|
4127
|
+
* `@cesdk/node`'s `editor.startTracking(license, userId)`; invoked
|
|
4128
|
+
* automatically from {@link CreativeEngine.init} when `license` and/or
|
|
4129
|
+
* `userId` are passed in the Configuration. Safe to call multiple times.
|
|
4130
|
+
*
|
|
4131
|
+
* The C++ binding accepts a third `deviceId` argument that the engine
|
|
4132
|
+
* itself uses for tracking-pipeline disambiguation; WASM always passes
|
|
4133
|
+
* `''` (see `bindings/wasm/js_web/src/EditorAPI.ts`) — we
|
|
4134
|
+
* mirror that here so the no-args / "engine picks a default device id"
|
|
4135
|
+
* path is honored.
|
|
4136
|
+
*
|
|
4137
|
+
* @public
|
|
4138
|
+
*/
|
|
4139
|
+
startTracking(license, userId, deviceId = "") {
|
|
4140
|
+
this.#engine.startTracking(license, userId, deviceId);
|
|
4141
|
+
}
|
|
4142
|
+
findAllScopes() {
|
|
4143
|
+
return this.#engine.findAllScopes();
|
|
4144
|
+
}
|
|
4145
|
+
getGlobalScope(scope) {
|
|
4146
|
+
return this.#engine.getGlobalScope(scope);
|
|
4147
|
+
}
|
|
4148
|
+
setGlobalScope(scope, value) {
|
|
4149
|
+
this.#engine.setGlobalScope(scope, value);
|
|
4150
|
+
}
|
|
4151
|
+
// History management (matches WASM EditorAPI)
|
|
4152
|
+
createHistory() {
|
|
4153
|
+
return this.#engine.createHistory();
|
|
4154
|
+
}
|
|
4155
|
+
destroyHistory(history) {
|
|
4156
|
+
this.#engine.destroyHistory(history);
|
|
4157
|
+
}
|
|
4158
|
+
getActiveHistory() {
|
|
4159
|
+
return this.#engine.getActiveHistory();
|
|
4160
|
+
}
|
|
4161
|
+
setActiveHistory(history) {
|
|
4162
|
+
this.#engine.setActiveHistory(history);
|
|
4163
|
+
}
|
|
4164
|
+
/**
|
|
4165
|
+
* Undo one step in the active history if an undo step is available.
|
|
4166
|
+
* Use {@link canUndo} beforehand to determine whether a step is available.
|
|
4167
|
+
*/
|
|
4168
|
+
undo() {
|
|
4169
|
+
this.#engine.undo();
|
|
4170
|
+
}
|
|
4171
|
+
/**
|
|
4172
|
+
* Redo one step in the active history if a redo step is available.
|
|
4173
|
+
* Use {@link canRedo} beforehand to determine whether a step is available.
|
|
4174
|
+
*/
|
|
4175
|
+
redo() {
|
|
4176
|
+
this.#engine.redo();
|
|
4177
|
+
}
|
|
4178
|
+
canUndo() {
|
|
4179
|
+
return this.#engine.canUndo();
|
|
4180
|
+
}
|
|
4181
|
+
canRedo() {
|
|
4182
|
+
return this.#engine.canRedo();
|
|
4183
|
+
}
|
|
4184
|
+
addUndoStep() {
|
|
4185
|
+
this.#engine.addUndoStep();
|
|
4186
|
+
}
|
|
4187
|
+
removeUndoStep() {
|
|
4188
|
+
this.#engine.removeUndoStep();
|
|
4189
|
+
}
|
|
4190
|
+
/**
|
|
4191
|
+
* Subscribe to editor-state changes.
|
|
4192
|
+
* @param callback - Called whenever the editor state changes.
|
|
4193
|
+
* @returns A function that unsubscribes when called.
|
|
4194
|
+
*/
|
|
4195
|
+
onStateChanged(callback) {
|
|
4196
|
+
const id = this.#engine.subscribeToEditorState(callback);
|
|
4197
|
+
return () => this.#engine.unsubscribe(id);
|
|
4198
|
+
}
|
|
4199
|
+
/**
|
|
4200
|
+
* Subscribe to editor settings changes. Matches WASM's
|
|
4201
|
+
* `engine.editor.onSettingsChanged(callback)`. The native C++ side
|
|
4202
|
+
* implements this via `subscribeToSettings`; this wrapper exposes it on
|
|
4203
|
+
* the editor API so portable consumers (settings-reactive UI) work on
|
|
4204
|
+
* both bindings.
|
|
4205
|
+
* @returns A function that unsubscribes when called.
|
|
4206
|
+
*/
|
|
4207
|
+
onSettingsChanged(callback) {
|
|
4208
|
+
const id = this.#engine.subscribeToSettings(callback);
|
|
4209
|
+
return () => this.#engine.unsubscribe(id);
|
|
4210
|
+
}
|
|
4211
|
+
/**
|
|
4212
|
+
* Subscribe to history updates.
|
|
4213
|
+
* @deprecated Use {@link onHistoryUpdatedWithKind} instead, which also
|
|
4214
|
+
* reports the kind of update.
|
|
4215
|
+
* @param callback - Called when the undo/redo history changes.
|
|
4216
|
+
* @returns A function that unsubscribes when called.
|
|
4217
|
+
*/
|
|
4218
|
+
onHistoryUpdated(callback) {
|
|
4219
|
+
return this.onHistoryUpdatedWithKind(() => callback());
|
|
4220
|
+
}
|
|
4221
|
+
/**
|
|
4222
|
+
* Subscribe to history updates. The callback receives a `HistoryUpdate`
|
|
4223
|
+
* describing what kind of update happened (matches the node wasm
|
|
4224
|
+
* binding's `EditorAPI` surface) so consumers can distinguish a
|
|
4225
|
+
* snapshot mutation from an `Activated` event triggered by
|
|
4226
|
+
* `setActiveHistory` — important for save-button logic that should NOT
|
|
4227
|
+
* fire on activation alone.
|
|
4228
|
+
* @param callback - Called with the kind of update.
|
|
4229
|
+
* @returns A function that unsubscribes when called.
|
|
4230
|
+
*/
|
|
4231
|
+
onHistoryUpdatedWithKind(callback) {
|
|
4232
|
+
const id = this.#engine.subscribeToHistoryWithKind((value) => {
|
|
4233
|
+
callback(value === 1 ? "Activated" : "Updated");
|
|
4234
|
+
});
|
|
4235
|
+
return () => this.#engine.unsubscribe(id);
|
|
4236
|
+
}
|
|
4237
|
+
/**
|
|
4238
|
+
* Subscribe to role changes.
|
|
4239
|
+
* @param callback - Called with the new role when it changes.
|
|
4240
|
+
* @returns A function that unsubscribes when called.
|
|
4241
|
+
*/
|
|
4242
|
+
onRoleChanged(callback) {
|
|
4243
|
+
const id = this.#engine.subscribeToRoleChange(callback);
|
|
4244
|
+
return () => this.#engine.unsubscribe(id);
|
|
4245
|
+
}
|
|
4246
|
+
// Buffer management (matching WASM/Android EditorAPI)
|
|
4247
|
+
/**
|
|
4248
|
+
* Create a new buffer and return its URI.
|
|
4249
|
+
* @returns A URI to identify the created buffer (buffer://N format).
|
|
4250
|
+
*/
|
|
4251
|
+
createBuffer() {
|
|
4252
|
+
return this.#engine.createBuffer();
|
|
4253
|
+
}
|
|
4254
|
+
/**
|
|
4255
|
+
* Destroy a buffer and free its resources.
|
|
4256
|
+
* @param uri - The URI of the buffer to destroy.
|
|
4257
|
+
*/
|
|
4258
|
+
destroyBuffer(uri) {
|
|
4259
|
+
this.#engine.destroyBuffer(uri);
|
|
4260
|
+
}
|
|
4261
|
+
/**
|
|
4262
|
+
* Set the data of a buffer at a given offset.
|
|
4263
|
+
* @param uri - The URI of the buffer to update.
|
|
4264
|
+
* @param offset - The offset in bytes at which to start writing.
|
|
4265
|
+
* @param data - The data to write.
|
|
4266
|
+
*/
|
|
4267
|
+
setBufferData(uri, offset, data) {
|
|
4268
|
+
this.#engine.setBufferData(uri, offset, data);
|
|
4269
|
+
}
|
|
4270
|
+
/**
|
|
4271
|
+
* Get the data of a buffer at a given offset.
|
|
4272
|
+
* @param uri - The URI of the buffer to query.
|
|
4273
|
+
* @param offset - The offset in bytes at which to start reading.
|
|
4274
|
+
* @param length - The number of bytes to read.
|
|
4275
|
+
* @returns The data at the given offset.
|
|
4276
|
+
*/
|
|
4277
|
+
getBufferData(uri, offset, length) {
|
|
4278
|
+
return this.#engine.getBufferData(uri, offset, length);
|
|
4279
|
+
}
|
|
4280
|
+
/**
|
|
4281
|
+
* Get the length of a buffer.
|
|
4282
|
+
* @param uri - The URI of the buffer to query.
|
|
4283
|
+
* @returns The length of the buffer in bytes.
|
|
4284
|
+
*/
|
|
4285
|
+
getBufferLength(uri) {
|
|
4286
|
+
return this.#engine.getBufferLength(uri);
|
|
4287
|
+
}
|
|
4288
|
+
/**
|
|
4289
|
+
* Resize a buffer. Truncates if `length` is smaller than the current
|
|
4290
|
+
* size; zero-extends if larger. Matches the WASM `editor.setBufferLength`
|
|
4291
|
+
* shape used by psd/pdf/idml importers to pre-allocate a buffer before
|
|
4292
|
+
* writing data with `setBufferData`.
|
|
4293
|
+
*/
|
|
4294
|
+
setBufferLength(uri, length) {
|
|
4295
|
+
this.#engine.setBufferLength(uri, length);
|
|
4296
|
+
}
|
|
4297
|
+
};
|
|
4298
|
+
var EventAPI = class {
|
|
4299
|
+
constructor(engine) {
|
|
4300
|
+
/**
|
|
4301
|
+
* Subscribe to block lifecycle events.
|
|
4302
|
+
* Events are bundled and delivered at the end of each engine update cycle.
|
|
4303
|
+
* @param blocks - List of blocks to filter events by. If empty, events for all blocks are sent.
|
|
4304
|
+
* @param callback - Function called with bundled events.
|
|
4305
|
+
* @returns A method to unsubscribe from the events.
|
|
4306
|
+
*/
|
|
4307
|
+
this.subscribe = (blocks, callback) => {
|
|
4308
|
+
const safeCallback = (events) => {
|
|
4309
|
+
try {
|
|
4310
|
+
callback(events);
|
|
4311
|
+
} catch (err) {
|
|
4312
|
+
console.error("[cesdk_native] block-event subscriber threw:", err);
|
|
4313
|
+
}
|
|
4314
|
+
};
|
|
4315
|
+
const subscription = this.#engine.subscribe(blocks, safeCallback);
|
|
4316
|
+
return () => {
|
|
4317
|
+
this.#engine.unsubscribe(subscription);
|
|
4318
|
+
};
|
|
4319
|
+
};
|
|
4320
|
+
this.#engine = engine;
|
|
4321
|
+
}
|
|
4322
|
+
#engine;
|
|
4323
|
+
};
|
|
4324
|
+
var AssetAPI = class {
|
|
4325
|
+
#engine;
|
|
4326
|
+
constructor(engine) {
|
|
4327
|
+
this.#engine = engine;
|
|
4328
|
+
}
|
|
4329
|
+
/**
|
|
4330
|
+
* Add a custom asset source with callbacks.
|
|
4331
|
+
*
|
|
4332
|
+
* This allows you to provide custom implementations for finding, fetching,
|
|
4333
|
+
* and applying assets from any data source.
|
|
4334
|
+
*
|
|
4335
|
+
* @param source - The asset source configuration with callbacks.
|
|
4336
|
+
*/
|
|
4337
|
+
addSource(source) {
|
|
4338
|
+
this.#engine.addAssetSource({
|
|
4339
|
+
id: source.id,
|
|
4340
|
+
findAssets: (query, resultCb) => {
|
|
4341
|
+
Promise.resolve(source.findAssets(query)).then(
|
|
4342
|
+
(result) => resultCb(
|
|
4343
|
+
null,
|
|
4344
|
+
result ?? { assets: [], currentPage: 0, total: 0, nextPage: -1 }
|
|
4345
|
+
)
|
|
4346
|
+
).catch((err) => resultCb(err));
|
|
4347
|
+
},
|
|
4348
|
+
fetchAsset: source.fetchAsset ? (id, params, resultCb) => {
|
|
4349
|
+
Promise.resolve(source.fetchAsset(id, params)).then((result) => resultCb(null, result)).catch((err) => resultCb(err));
|
|
4350
|
+
} : void 0,
|
|
4351
|
+
getGroups: source.getGroups ? (resultCb) => {
|
|
4352
|
+
Promise.resolve(source.getGroups()).then((result) => resultCb(null, result)).catch((err) => resultCb(err));
|
|
4353
|
+
} : void 0,
|
|
4354
|
+
credits: source.credits,
|
|
4355
|
+
license: source.license,
|
|
4356
|
+
getSupportedMimeTypes: source.getSupportedMimeTypes,
|
|
4357
|
+
applyAsset: source.applyAsset ? (asset, resultCb) => {
|
|
4358
|
+
Promise.resolve(source.applyAsset(asset)).then((result) => resultCb(null, result)).catch((err) => resultCb(err));
|
|
4359
|
+
} : void 0,
|
|
4360
|
+
applyAssetToBlock: source.applyAssetToBlock ? (asset, block, resultCb) => {
|
|
4361
|
+
Promise.resolve(source.applyAssetToBlock(asset, block)).then(() => resultCb(null)).catch((err) => resultCb(err));
|
|
4362
|
+
} : void 0,
|
|
4363
|
+
applyAssetProperty: source.applyAssetProperty ? (asset, property, resultCb) => {
|
|
4364
|
+
Promise.resolve(source.applyAssetProperty(asset, property)).then(() => resultCb(null)).catch((err) => resultCb(err));
|
|
4365
|
+
} : void 0,
|
|
4366
|
+
addAsset: source.addAsset,
|
|
4367
|
+
removeAsset: source.removeAsset
|
|
4368
|
+
});
|
|
4369
|
+
}
|
|
4370
|
+
/**
|
|
4371
|
+
* Add a local asset source.
|
|
4372
|
+
*
|
|
4373
|
+
* Mirrors `@cesdk/node`'s 4-argument shape
|
|
4374
|
+
* (`bindings/wasm/js_web/src/AssetAPI.ts`): when `applyAsset`
|
|
4375
|
+
* or `applyAssetToBlock` is supplied, we wrap the local source as a
|
|
4376
|
+
* synthetic `AssetSource` via {@link addSource} so the callbacks are
|
|
4377
|
+
* honored. Without callbacks we go through the cheap `addLocalSource`
|
|
4378
|
+
* fast path.
|
|
4379
|
+
*
|
|
4380
|
+
* @param id - Unique identifier for the asset source.
|
|
4381
|
+
* @param supportedMimeTypes - The mime types of assets that are allowed to be added.
|
|
4382
|
+
* @param applyAsset - Optional callback invoked when the asset is applied to a new block.
|
|
4383
|
+
* @param applyAssetToBlock - Optional callback invoked when the asset is applied to an existing block.
|
|
4384
|
+
*/
|
|
4385
|
+
addLocalSource(id, supportedMimeTypes, applyAsset, applyAssetToBlock) {
|
|
4386
|
+
if (applyAsset == null && applyAssetToBlock == null) {
|
|
4387
|
+
this.#engine.addLocalAssetSource(id, supportedMimeTypes ?? []);
|
|
4388
|
+
return;
|
|
4389
|
+
}
|
|
4390
|
+
this.#engine.addLocalAssetSource(id, supportedMimeTypes ?? []);
|
|
4391
|
+
if (applyAsset != null) {
|
|
4392
|
+
this.registerApplyMiddleware(id, async (asset, next) => {
|
|
4393
|
+
const result = await applyAsset(asset);
|
|
4394
|
+
if (result !== void 0) return result;
|
|
4395
|
+
return next(asset);
|
|
4396
|
+
});
|
|
4397
|
+
}
|
|
4398
|
+
if (applyAssetToBlock != null) {
|
|
4399
|
+
this.registerApplyToBlockMiddleware(id, async (asset, block, next) => {
|
|
4400
|
+
await applyAssetToBlock(asset, block);
|
|
4401
|
+
await next(asset, block);
|
|
4402
|
+
});
|
|
4403
|
+
}
|
|
4404
|
+
}
|
|
4405
|
+
/**
|
|
4406
|
+
* Creates a new local asset source from a JSON string.
|
|
4407
|
+
* @param contentJSON - The JSON string containing the asset definitions.
|
|
4408
|
+
* @param basePath - Optional base path for resolving relative URLs.
|
|
4409
|
+
* @param options - Optional configuration with matcher patterns.
|
|
4410
|
+
* @returns The ID of the created asset source.
|
|
4411
|
+
*/
|
|
4412
|
+
addLocalAssetSourceFromJSONString(contentJSON, basePath, options) {
|
|
4413
|
+
try {
|
|
4414
|
+
const sourceId = this.#engine.addLocalAssetSourceFromJSONString(
|
|
4415
|
+
contentJSON,
|
|
4416
|
+
basePath,
|
|
4417
|
+
options?.matcher
|
|
4418
|
+
);
|
|
4419
|
+
return Promise.resolve(sourceId);
|
|
4420
|
+
} catch (e) {
|
|
4421
|
+
return Promise.reject(e);
|
|
4422
|
+
}
|
|
4423
|
+
}
|
|
4424
|
+
/**
|
|
4425
|
+
* Creates a new local asset source from a JSON URI.
|
|
4426
|
+
* @param contentURI - The URI for the JSON file to load.
|
|
4427
|
+
* @param options - Optional configuration with matcher patterns.
|
|
4428
|
+
* @returns The ID of the created asset source.
|
|
4429
|
+
*/
|
|
4430
|
+
addLocalAssetSourceFromJSONURI(contentURI, options) {
|
|
4431
|
+
return this.#engine.addLocalAssetSourceFromJSONURI(
|
|
4432
|
+
contentURI,
|
|
4433
|
+
options?.matcher
|
|
4434
|
+
);
|
|
4435
|
+
}
|
|
4436
|
+
/**
|
|
4437
|
+
* Remove a registered asset source.
|
|
4438
|
+
* @param id - The ID of the asset source to remove.
|
|
4439
|
+
*/
|
|
4440
|
+
removeSource(id) {
|
|
4441
|
+
this.#engine.removeAssetSource(id);
|
|
4442
|
+
}
|
|
4443
|
+
/**
|
|
4444
|
+
* Get all registered asset source IDs.
|
|
4445
|
+
* @returns A list with the IDs of all registered asset sources.
|
|
4446
|
+
*/
|
|
4447
|
+
findAllSources() {
|
|
4448
|
+
return this.#engine.findAllAssetSources();
|
|
4449
|
+
}
|
|
4450
|
+
/**
|
|
4451
|
+
* Search for assets in a specific source.
|
|
4452
|
+
*
|
|
4453
|
+
* @param sourceId - The ID of the asset source.
|
|
4454
|
+
* @param query - Query options to filter and sort the search results.
|
|
4455
|
+
* @returns Promise resolving to paginated search results.
|
|
4456
|
+
*/
|
|
4457
|
+
async findAssets(sourceId, query) {
|
|
4458
|
+
const q = query;
|
|
4459
|
+
const tagsRaw = q?.tags;
|
|
4460
|
+
const tags = Array.isArray(tagsRaw) ? tagsRaw : typeof tagsRaw === "string" ? [tagsRaw] : tagsRaw && typeof tagsRaw === "object" ? tagsRaw : [];
|
|
4461
|
+
const normalizedQuery = {
|
|
4462
|
+
perPage: q?.perPage ?? 0,
|
|
4463
|
+
page: q?.page ?? 0,
|
|
4464
|
+
query: q?.query ?? "",
|
|
4465
|
+
tags,
|
|
4466
|
+
groups: q?.groups ?? [],
|
|
4467
|
+
excludeGroups: q?.excludeGroups ?? [],
|
|
4468
|
+
locale: q?.locale ?? "",
|
|
4469
|
+
sortingOrder: q?.sortingOrder ?? "None",
|
|
4470
|
+
sortKey: q?.sortKey ?? "",
|
|
4471
|
+
sortActiveFirst: q?.sortActiveFirst ?? false,
|
|
4472
|
+
filter: q?.filter ?? []
|
|
4473
|
+
};
|
|
4474
|
+
const result = await this.#engine.findAssetSourceAssets(
|
|
4475
|
+
sourceId,
|
|
4476
|
+
normalizedQuery
|
|
4477
|
+
);
|
|
4478
|
+
const r = result;
|
|
4479
|
+
return {
|
|
4480
|
+
...result,
|
|
4481
|
+
nextPage: r.nextPage === -1 ? void 0 : r.nextPage
|
|
4482
|
+
};
|
|
4483
|
+
}
|
|
4484
|
+
/**
|
|
4485
|
+
* Fetch a specific asset by id from an asset source.
|
|
4486
|
+
* Returns `null` when the asset is not found.
|
|
4487
|
+
*/
|
|
4488
|
+
async fetchAsset(sourceId, assetId, params = {}) {
|
|
4489
|
+
const fetchParams = { locale: params.locale ?? "" };
|
|
4490
|
+
return this.#engine.fetchAssetSourceAsset(sourceId, assetId, fetchParams);
|
|
4491
|
+
}
|
|
4492
|
+
/**
|
|
4493
|
+
* Get available asset groups from a source.
|
|
4494
|
+
* @param id - The ID of the asset source.
|
|
4495
|
+
* @returns Promise resolving to list of available group names.
|
|
4496
|
+
*/
|
|
4497
|
+
async getGroups(id) {
|
|
4498
|
+
return this.#engine.getAssetSourceGroups(id);
|
|
4499
|
+
}
|
|
4500
|
+
/**
|
|
4501
|
+
* Get license information for an asset source.
|
|
4502
|
+
* @param sourceId - The ID of the asset source.
|
|
4503
|
+
* @returns The asset source's license info.
|
|
4504
|
+
*/
|
|
4505
|
+
getLicense(sourceId) {
|
|
4506
|
+
const license = this.#engine.getAssetSourceLicense(sourceId);
|
|
4507
|
+
if (!license || !license.name && !license.url) {
|
|
4508
|
+
return void 0;
|
|
4509
|
+
}
|
|
4510
|
+
return { name: license.name, url: license.url || void 0 };
|
|
4511
|
+
}
|
|
4512
|
+
/**
|
|
4513
|
+
* Get attribution credits for an asset source.
|
|
4514
|
+
* @param sourceId - The ID of the asset source.
|
|
4515
|
+
* @returns The asset source's credits info.
|
|
4516
|
+
*/
|
|
4517
|
+
getCredits(sourceId) {
|
|
4518
|
+
const credits = this.#engine.getAssetSourceCredits(sourceId);
|
|
4519
|
+
if (!credits || !credits.name && !credits.url) {
|
|
4520
|
+
return void 0;
|
|
4521
|
+
}
|
|
4522
|
+
return { name: credits.name, url: credits.url || void 0 };
|
|
4523
|
+
}
|
|
4524
|
+
/**
|
|
4525
|
+
* Get supported MIME types for an asset source.
|
|
4526
|
+
* @param sourceId - The ID of the asset source.
|
|
4527
|
+
* @returns Array of supported MIME type strings.
|
|
4528
|
+
*/
|
|
4529
|
+
getSupportedMimeTypes(sourceId) {
|
|
4530
|
+
return this.#engine.getAssetSourceSupportedMimeTypes(sourceId);
|
|
4531
|
+
}
|
|
4532
|
+
/**
|
|
4533
|
+
* Add an asset to a local asset source.
|
|
4534
|
+
* @param sourceId - The local asset source ID.
|
|
4535
|
+
* @param asset - The asset definition to add.
|
|
4536
|
+
*/
|
|
4537
|
+
addAssetToSource(sourceId, asset) {
|
|
4538
|
+
this.#engine.addAssetToSource(sourceId, asset);
|
|
4539
|
+
}
|
|
4540
|
+
/**
|
|
4541
|
+
* Remove an asset from a local asset source.
|
|
4542
|
+
* @param sourceId - The ID of the local asset source.
|
|
4543
|
+
* @param assetId - The ID of the asset to remove.
|
|
4544
|
+
*/
|
|
4545
|
+
removeAssetFromSource(sourceId, assetId) {
|
|
4546
|
+
this.#engine.removeAssetFromSource(sourceId, assetId);
|
|
4547
|
+
}
|
|
4548
|
+
/**
|
|
4549
|
+
* Notify the engine that an asset source's contents have changed.
|
|
4550
|
+
* @param sourceID - The asset source whose contents changed.
|
|
4551
|
+
*/
|
|
4552
|
+
assetSourceContentsChanged(sourceID) {
|
|
4553
|
+
this.#engine.assetSourceContentsChanged(sourceID);
|
|
4554
|
+
}
|
|
4555
|
+
/**
|
|
4556
|
+
* Subscribe to "asset source added" events.
|
|
4557
|
+
* @param callback - Called with the source ID whenever a new asset source is registered.
|
|
4558
|
+
* @returns A function that unsubscribes when called.
|
|
4559
|
+
*/
|
|
4560
|
+
onAssetSourceAdded(callback) {
|
|
4561
|
+
const id = this.#engine.subscribeToAssetSourceAdded(callback);
|
|
4562
|
+
return () => this.#engine.unsubscribe(id);
|
|
4563
|
+
}
|
|
4564
|
+
/**
|
|
4565
|
+
* Subscribe to "asset source removed" events.
|
|
4566
|
+
* @param callback - Called with the source ID whenever an asset source is removed.
|
|
4567
|
+
* @returns A function that unsubscribes when called.
|
|
4568
|
+
*/
|
|
4569
|
+
onAssetSourceRemoved(callback) {
|
|
4570
|
+
const id = this.#engine.subscribeToAssetSourceRemoved(callback);
|
|
4571
|
+
return () => this.#engine.unsubscribe(id);
|
|
4572
|
+
}
|
|
4573
|
+
/**
|
|
4574
|
+
* Subscribe to "asset source updated" events.
|
|
4575
|
+
* @param callback - Called with the source ID whenever an asset source's contents change.
|
|
4576
|
+
* @returns A function that unsubscribes when called.
|
|
4577
|
+
*/
|
|
4578
|
+
onAssetSourceUpdated(callback) {
|
|
4579
|
+
const id = this.#engine.subscribeToAssetSourceUpdated(callback);
|
|
4580
|
+
return () => this.#engine.unsubscribe(id);
|
|
4581
|
+
}
|
|
4582
|
+
// -------------------------------------------------------------------------
|
|
4583
|
+
// Apply-asset surface (parity with @cesdk/node's AssetAPI:955-1195).
|
|
4584
|
+
//
|
|
4585
|
+
// The C++ binding already exposes the four primitives (`applyAssetSourceAsset`,
|
|
4586
|
+
// `applyAssetSourceAssetToBlock`, `applyAssetSourceProperty`,
|
|
4587
|
+
// `defaultApplyAsset`, `defaultApplyAssetToBlock`) — we only need to bridge
|
|
4588
|
+
// them through a TS-level middleware chain so registerApplyMiddleware /
|
|
4589
|
+
// registerApplyToBlockMiddleware work.
|
|
4590
|
+
// -------------------------------------------------------------------------
|
|
4591
|
+
#applyMiddleware = /* @__PURE__ */ new Map();
|
|
4592
|
+
#applyToBlockMiddleware = /* @__PURE__ */ new Map();
|
|
4593
|
+
/**
|
|
4594
|
+
* Apply an asset to the current scene. Honors any middleware registered
|
|
4595
|
+
* via {@link registerApplyMiddleware} and falls back to
|
|
4596
|
+
* {@link defaultApplyAsset}.
|
|
4597
|
+
*
|
|
4598
|
+
* @public
|
|
4599
|
+
*/
|
|
4600
|
+
async apply(sourceId, asset) {
|
|
4601
|
+
const tail = (a) => this.defaultApplyAsset(a);
|
|
4602
|
+
const middlewares = this.#applyMiddleware.get(sourceId) ?? [];
|
|
4603
|
+
let next = tail;
|
|
4604
|
+
for (let i = middlewares.length - 1; i >= 0; i--) {
|
|
4605
|
+
const mw = middlewares[i];
|
|
4606
|
+
const prev = next;
|
|
4607
|
+
next = (a) => mw(a, prev);
|
|
4608
|
+
}
|
|
4609
|
+
return next(asset);
|
|
4610
|
+
}
|
|
4611
|
+
/**
|
|
4612
|
+
* Apply an asset to a specific block. Honors any middleware registered
|
|
4613
|
+
* via {@link registerApplyToBlockMiddleware} and falls back to
|
|
4614
|
+
* {@link defaultApplyAssetToBlock}.
|
|
4615
|
+
*
|
|
4616
|
+
* @public
|
|
4617
|
+
*/
|
|
4618
|
+
async applyToBlock(sourceId, asset, block) {
|
|
4619
|
+
const tail = (a, b) => this.defaultApplyAssetToBlock(a, b);
|
|
4620
|
+
const middlewares = this.#applyToBlockMiddleware.get(sourceId) ?? [];
|
|
4621
|
+
let next = tail;
|
|
4622
|
+
for (let i = middlewares.length - 1; i >= 0; i--) {
|
|
4623
|
+
const mw = middlewares[i];
|
|
4624
|
+
const prev = next;
|
|
4625
|
+
next = (a, b) => mw(a, b, prev);
|
|
4626
|
+
}
|
|
4627
|
+
return next(asset, block);
|
|
4628
|
+
}
|
|
4629
|
+
/**
|
|
4630
|
+
* Apply a property change from an asset payload.
|
|
4631
|
+
*
|
|
4632
|
+
* @public
|
|
4633
|
+
*/
|
|
4634
|
+
async applyProperty(sourceId, asset, property) {
|
|
4635
|
+
return this.#engine.applyAssetSourceProperty(sourceId, asset, property);
|
|
4636
|
+
}
|
|
4637
|
+
/**
|
|
4638
|
+
* Default apply-asset implementation (no middleware). Calls the engine's
|
|
4639
|
+
* built-in apply logic; used as the tail of the middleware chain in
|
|
4640
|
+
* {@link apply}.
|
|
4641
|
+
*
|
|
4642
|
+
* @public
|
|
4643
|
+
*/
|
|
4644
|
+
async defaultApplyAsset(asset) {
|
|
4645
|
+
const result = await this.#engine.defaultApplyAsset(asset);
|
|
4646
|
+
return result === -1 || result == null ? void 0 : result;
|
|
4647
|
+
}
|
|
4648
|
+
/**
|
|
4649
|
+
* Default apply-to-block implementation (no middleware). Used as the
|
|
4650
|
+
* tail of the middleware chain in {@link applyToBlock}.
|
|
4651
|
+
*
|
|
4652
|
+
* @public
|
|
4653
|
+
*/
|
|
4654
|
+
async defaultApplyAssetToBlock(asset, block) {
|
|
4655
|
+
await this.#engine.defaultApplyAssetToBlock(asset, block);
|
|
4656
|
+
}
|
|
4657
|
+
/**
|
|
4658
|
+
* Register a middleware in the apply-asset chain for a source.
|
|
4659
|
+
*
|
|
4660
|
+
* @param sourceId - The source to install the middleware on.
|
|
4661
|
+
* @param middleware - Callable that may consume the asset, defer to
|
|
4662
|
+
* the next middleware, or short-circuit. Returns the created block id
|
|
4663
|
+
* (or undefined to fall through).
|
|
4664
|
+
* @public
|
|
4665
|
+
*/
|
|
4666
|
+
registerApplyMiddleware(sourceId, middleware) {
|
|
4667
|
+
const arr = this.#applyMiddleware.get(sourceId) ?? [];
|
|
4668
|
+
arr.push(middleware);
|
|
4669
|
+
this.#applyMiddleware.set(sourceId, arr);
|
|
4670
|
+
}
|
|
4671
|
+
/**
|
|
4672
|
+
* Register a middleware in the apply-asset-to-block chain for a source.
|
|
4673
|
+
*
|
|
4674
|
+
* @public
|
|
4675
|
+
*/
|
|
4676
|
+
registerApplyToBlockMiddleware(sourceId, middleware) {
|
|
4677
|
+
const arr = this.#applyToBlockMiddleware.get(sourceId) ?? [];
|
|
4678
|
+
arr.push(middleware);
|
|
4679
|
+
this.#applyToBlockMiddleware.set(sourceId, arr);
|
|
4680
|
+
}
|
|
4681
|
+
/**
|
|
4682
|
+
* Whether the named source supports `addAssetToSource` /
|
|
4683
|
+
* `removeAssetFromSource`. Local sources return `true` by default; custom
|
|
4684
|
+
* sources return whatever they declared via `canManageAssets` in their
|
|
4685
|
+
* registration object.
|
|
4686
|
+
*
|
|
4687
|
+
* @public
|
|
4688
|
+
*/
|
|
4689
|
+
canManageAssets(sourceId) {
|
|
4690
|
+
try {
|
|
4691
|
+
this.#engine.removeAssetFromSource(
|
|
4692
|
+
sourceId,
|
|
4693
|
+
"__cesdk_probe_does_not_exist__"
|
|
4694
|
+
);
|
|
4695
|
+
return true;
|
|
4696
|
+
} catch {
|
|
4697
|
+
return false;
|
|
4698
|
+
}
|
|
4699
|
+
}
|
|
4700
|
+
};
|
|
4701
|
+
var _version = true ? "1.77.0-nightly.20260610" : "0.0.0";
|
|
4702
|
+
var CreativeEngine = class _CreativeEngine {
|
|
4703
|
+
constructor(engine) {
|
|
4704
|
+
this.version = _CreativeEngine.version;
|
|
4705
|
+
this.#updateInterval = null;
|
|
4706
|
+
this.#baseURL = "";
|
|
4707
|
+
this.#engine = engine;
|
|
4708
|
+
this.asset = new AssetAPI(engine);
|
|
4709
|
+
this.block = new BlockAPI(engine);
|
|
4710
|
+
this.editor = new EditorAPI(engine);
|
|
4711
|
+
this.event = new EventAPI(engine);
|
|
4712
|
+
this.scene = new SceneAPI(engine);
|
|
4713
|
+
this.variable = new VariableAPI(engine);
|
|
4714
|
+
this.#startUpdateLoop();
|
|
4715
|
+
}
|
|
4716
|
+
static {
|
|
4717
|
+
this.version = _version;
|
|
4718
|
+
}
|
|
4719
|
+
#engine;
|
|
4720
|
+
#updateInterval;
|
|
4721
|
+
#baseURL;
|
|
4722
|
+
#startUpdateLoop() {
|
|
4723
|
+
if (this.#updateInterval) return;
|
|
4724
|
+
const updateLoop = () => {
|
|
4725
|
+
let needsUpdate = false;
|
|
4726
|
+
if (this.#engine) {
|
|
4727
|
+
needsUpdate = this.update();
|
|
4728
|
+
}
|
|
4729
|
+
this.#updateInterval = needsUpdate ? setImmediate(updateLoop) : setTimeout(updateLoop, 16);
|
|
4730
|
+
};
|
|
4731
|
+
this.#updateInterval = setImmediate(updateLoop);
|
|
4732
|
+
}
|
|
4733
|
+
#stopUpdateLoop() {
|
|
4734
|
+
if (this.#updateInterval) {
|
|
4735
|
+
clearTimeout(this.#updateInterval);
|
|
4736
|
+
clearImmediate(this.#updateInterval);
|
|
4737
|
+
this.#updateInterval = null;
|
|
4738
|
+
}
|
|
4739
|
+
}
|
|
4740
|
+
/**
|
|
4741
|
+
* Update the engine's internal state
|
|
4742
|
+
* @returns Whether the engine needed an update.
|
|
4743
|
+
*/
|
|
4744
|
+
update() {
|
|
4745
|
+
return this.#engine.update();
|
|
4746
|
+
}
|
|
4747
|
+
/**
|
|
4748
|
+
* Dispose the engine and clean up all resources
|
|
4749
|
+
*/
|
|
4750
|
+
dispose() {
|
|
4751
|
+
this.#stopUpdateLoop();
|
|
4752
|
+
this.#engine.dispose();
|
|
4753
|
+
this.#engine = null;
|
|
4754
|
+
this.asset = null;
|
|
4755
|
+
this.block = null;
|
|
4756
|
+
this.editor = null;
|
|
4757
|
+
this.event = null;
|
|
4758
|
+
this.scene = null;
|
|
4759
|
+
this.variable = null;
|
|
4760
|
+
}
|
|
4761
|
+
/**
|
|
4762
|
+
* Initialize a CreativeEngine.
|
|
4763
|
+
*
|
|
4764
|
+
* Mirrors `@cesdk/node`'s {@link Configuration} shape exactly. The
|
|
4765
|
+
* native-only `device` field selects the render backend
|
|
4766
|
+
* (`'auto'` | `'cpu'` | `'gpu'`); web/WASM Node accept the field for shape
|
|
4767
|
+
* parity but ignore non-`'auto'` values.
|
|
4768
|
+
*
|
|
4769
|
+
* @param config - Engine configuration. All fields optional; defaults
|
|
4770
|
+
* match `@cesdk/node` + `'auto'` device selection.
|
|
4771
|
+
* @returns A ready-to-use engine instance.
|
|
4772
|
+
* @public
|
|
4773
|
+
*/
|
|
4774
|
+
static async init(config) {
|
|
4775
|
+
const { addon: nativeAddon, addonPath: nativeAddonPath } = await getNativeAddon();
|
|
4776
|
+
const engineDevice = resolveEngineDevice(config);
|
|
4777
|
+
const { baseURL, enginePath } = resolveEngineBaseURL(
|
|
4778
|
+
config,
|
|
4779
|
+
nativeAddonPath
|
|
4780
|
+
);
|
|
4781
|
+
const engine = nativeAddon.createEngine(enginePath, engineDevice);
|
|
4782
|
+
let resolvedLicense = "";
|
|
4783
|
+
try {
|
|
4784
|
+
resolvedLicense = await downloadAndCheckLicense(config ?? {});
|
|
4785
|
+
} catch (err) {
|
|
4786
|
+
try {
|
|
4787
|
+
engine.dispose();
|
|
4788
|
+
} catch {
|
|
4789
|
+
}
|
|
4790
|
+
throw err;
|
|
4791
|
+
}
|
|
4792
|
+
engine.unlockWithLicense(resolvedLicense);
|
|
4793
|
+
const creativeEngine = new _CreativeEngine(engine);
|
|
4794
|
+
creativeEngine.#baseURL = baseURL;
|
|
4795
|
+
configureEngine(creativeEngine, config, { baseURL });
|
|
4796
|
+
await registerBuiltinTypeface(creativeEngine);
|
|
4797
|
+
return creativeEngine;
|
|
4798
|
+
}
|
|
4799
|
+
/**
|
|
4800
|
+
* Get the base URL for engine assets
|
|
4801
|
+
*/
|
|
4802
|
+
getBaseURL() {
|
|
4803
|
+
return this.#baseURL;
|
|
4804
|
+
}
|
|
4805
|
+
/**
|
|
4806
|
+
* Register a set of default asset sources containing default assets.
|
|
4807
|
+
*
|
|
4808
|
+
* Mirrors `@cesdk/node`'s instance method
|
|
4809
|
+
* (bindings/wasm/js_node/src/CreativeEngine.ts). Loads
|
|
4810
|
+
* `${baseURL}/<source-id>/content.json` for each id in the default set
|
|
4811
|
+
* and registers the contents as a local asset source. baseURL defaults
|
|
4812
|
+
* to the engine's configured baseURL (`file://<addon>/assets/` if none
|
|
4813
|
+
* was passed to init).
|
|
4814
|
+
*
|
|
4815
|
+
* @public
|
|
4816
|
+
*/
|
|
4817
|
+
async addDefaultAssetSources({
|
|
4818
|
+
baseURL,
|
|
4819
|
+
excludeAssetSourceIds = []
|
|
4820
|
+
} = {}) {
|
|
4821
|
+
const resolvedBaseURL = baseURL ?? this.#baseURL;
|
|
4822
|
+
if (!resolvedBaseURL) {
|
|
4823
|
+
throw new Error(
|
|
4824
|
+
"addDefaultAssetSources: no baseURL configured. Pass { baseURL } or set baseURL on init."
|
|
4825
|
+
);
|
|
4826
|
+
}
|
|
4827
|
+
await loadDefaultAssetSources(
|
|
4828
|
+
this.asset,
|
|
4829
|
+
resolvedBaseURL,
|
|
4830
|
+
new Set(excludeAssetSourceIds)
|
|
4831
|
+
);
|
|
4832
|
+
}
|
|
4833
|
+
/**
|
|
4834
|
+
* Register a set of demo asset sources containing example assets.
|
|
4835
|
+
*
|
|
4836
|
+
* Mirrors `@cesdk/node`'s `bindings/wasm/js_web/src/addDemoAssetSources.ts`
|
|
4837
|
+
* — accepts `sceneMode`, `withUploadAssetSources`, and the full demo
|
|
4838
|
+
* source-ID union (templates + textComponents + uploads + media).
|
|
4839
|
+
*
|
|
4840
|
+
* @public
|
|
4841
|
+
*/
|
|
4842
|
+
async addDemoAssetSources({
|
|
4843
|
+
baseURL,
|
|
4844
|
+
excludeAssetSourceIds = [],
|
|
4845
|
+
sceneMode = "Design",
|
|
4846
|
+
withUploadAssetSources = false
|
|
4847
|
+
} = {}) {
|
|
4848
|
+
const resolvedBaseURL = baseURL ?? this.#baseURL;
|
|
4849
|
+
if (!resolvedBaseURL) {
|
|
4850
|
+
throw new Error(
|
|
4851
|
+
"addDemoAssetSources: no baseURL configured. Pass { baseURL } or set baseURL on init."
|
|
4852
|
+
);
|
|
4853
|
+
}
|
|
4854
|
+
await loadDemoAssetSources(
|
|
4855
|
+
this.asset,
|
|
4856
|
+
resolvedBaseURL,
|
|
4857
|
+
new Set(excludeAssetSourceIds),
|
|
4858
|
+
{
|
|
4859
|
+
sceneMode,
|
|
4860
|
+
withUploadAssetSources,
|
|
4861
|
+
// Pass the scene API so template sources have something to call.
|
|
4862
|
+
sceneAPI: {
|
|
4863
|
+
applyTemplateFromString: (s) => this.scene.applyTemplateFromString(s),
|
|
4864
|
+
applyTemplateFromURL: (u) => this.scene.applyTemplateFromURL(u)
|
|
4865
|
+
}
|
|
4866
|
+
}
|
|
4867
|
+
);
|
|
4868
|
+
}
|
|
4869
|
+
};
|
|
4870
|
+
|
|
4871
|
+
// ts/src/types.ts
|
|
4872
|
+
var CompressionFormat = /* @__PURE__ */ ((CompressionFormat2) => {
|
|
4873
|
+
CompressionFormat2[CompressionFormat2["None"] = 0] = "None";
|
|
4874
|
+
CompressionFormat2[CompressionFormat2["Zstd"] = 1] = "Zstd";
|
|
4875
|
+
return CompressionFormat2;
|
|
4876
|
+
})(CompressionFormat || {});
|
|
4877
|
+
var CompressionLevel = /* @__PURE__ */ ((CompressionLevel2) => {
|
|
4878
|
+
CompressionLevel2[CompressionLevel2["Fastest"] = 0] = "Fastest";
|
|
4879
|
+
CompressionLevel2[CompressionLevel2["Default"] = 1] = "Default";
|
|
4880
|
+
CompressionLevel2[CompressionLevel2["Best"] = 2] = "Best";
|
|
4881
|
+
return CompressionLevel2;
|
|
4882
|
+
})(CompressionLevel || {});
|
|
4883
|
+
|
|
4884
|
+
// ts/src/index.ts
|
|
4885
|
+
var index_default = CreativeEngine;
|
|
4886
|
+
module.exports = CreativeEngine;
|
|
4887
|
+
Object.defineProperty(module.exports, "__esModule", { value: true });
|
|
4888
|
+
Object.defineProperty(module.exports, "default", { value: CreativeEngine });
|
|
4889
|
+
Object.defineProperties(module.exports, {
|
|
4890
|
+
MimeType: { value: MimeType, enumerable: true },
|
|
4891
|
+
LogLevel: { value: LogLevel, enumerable: true },
|
|
4892
|
+
defaultLogger: { value: defaultLogger, enumerable: true },
|
|
4893
|
+
isRGBAColor: { value: isRGBAColor, enumerable: true },
|
|
4894
|
+
isCMYKColor: { value: isCMYKColor, enumerable: true },
|
|
4895
|
+
isSpotColor: { value: isSpotColor, enumerable: true },
|
|
4896
|
+
ANIMATION_TYPES: { value: ANIMATION_TYPES, enumerable: true },
|
|
4897
|
+
DESIGN_BLOCK_TYPES: { value: DESIGN_BLOCK_TYPES, enumerable: true },
|
|
4898
|
+
SHAPE_TYPES: { value: SHAPE_TYPES, enumerable: true },
|
|
4899
|
+
FILL_TYPES: { value: FILL_TYPES, enumerable: true },
|
|
4900
|
+
EFFECT_TYPES: { value: EFFECT_TYPES, enumerable: true },
|
|
4901
|
+
BLUR_TYPES: { value: BLUR_TYPES, enumerable: true },
|
|
4902
|
+
CompressionFormat: { value: CompressionFormat, enumerable: true },
|
|
4903
|
+
CompressionLevel: { value: CompressionLevel, enumerable: true }
|
|
4904
|
+
});
|
|
4905
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
4906
|
+
0 && (module.exports = {
|
|
4907
|
+
ANIMATION_TYPES,
|
|
4908
|
+
BLUR_TYPES,
|
|
4909
|
+
CompressionFormat,
|
|
4910
|
+
CompressionLevel,
|
|
4911
|
+
DESIGN_BLOCK_TYPES,
|
|
4912
|
+
EFFECT_TYPES,
|
|
4913
|
+
FILL_TYPES,
|
|
4914
|
+
LogLevel,
|
|
4915
|
+
MimeType,
|
|
4916
|
+
SHAPE_TYPES,
|
|
4917
|
+
defaultLogger,
|
|
4918
|
+
isCMYKColor,
|
|
4919
|
+
isRGBAColor,
|
|
4920
|
+
isSpotColor
|
|
4921
|
+
});
|
|
4922
|
+
//# sourceMappingURL=index.js.map
|