@clypra/engine 1.2.1 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -19,6 +19,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
19
19
  // src/index.ts
20
20
  var index_exports = {};
21
21
  __export(index_exports, {
22
+ AnimationSchema: () => AnimationSchema,
22
23
  COMPOSITION_PRESETS: () => COMPOSITION_PRESETS,
23
24
  CUSTOM_ENGINE_IDS: () => CUSTOM_ENGINE_IDS,
24
25
  CanvasDevice: () => CanvasDevice,
@@ -32,8 +33,19 @@ __export(index_exports, {
32
33
  ENGINE_ID_TO_LEGACY: () => ENGINE_ID_TO_LEGACY,
33
34
  ENTRANCE_PRESETS: () => ENTRANCE_PRESETS,
34
35
  EXIT_PRESETS: () => EXIT_PRESETS,
36
+ EffectBevelSchema: () => EffectBevelSchema,
37
+ EffectFillSchema: () => EffectFillSchema,
38
+ EffectFullDefinitionSchema: () => EffectFullDefinitionSchema,
39
+ EffectGlowSchema: () => EffectGlowSchema,
40
+ EffectIndexItemSchema: () => EffectIndexItemSchema,
41
+ EffectPanelSchema: () => EffectPanelSchema,
42
+ EffectShadowSchema: () => EffectShadowSchema,
43
+ EffectStackSchema: () => EffectStackSchema,
44
+ EffectStrokeSchema: () => EffectStrokeSchema,
35
45
  FONT_WEIGHT_OPTIONS: () => FONT_WEIGHT_OPTIONS,
36
46
  FontLoader: () => FontLoader,
47
+ FontSchema: () => FontSchema,
48
+ GradientStopSchema: () => GradientStopSchema,
37
49
  InkBrushEngine: () => InkBrushEngine,
38
50
  LEGACY_RENDERER_MAP: () => LEGACY_RENDERER_MAP,
39
51
  LOOP_PRESETS: () => LOOP_PRESETS,
@@ -42,6 +54,8 @@ __export(index_exports, {
42
54
  SCENE_VERSION: () => SCENE_VERSION,
43
55
  SUPPORTED_FONT_FAMILIES: () => SUPPORTED_FONT_FAMILIES,
44
56
  TEMPLATE_CATEGORIES: () => TEMPLATE_CATEGORIES,
57
+ TextEffectBuilder: () => TextEffectBuilder,
58
+ TextEffectDefinitionSchema: () => TextEffectDefinitionSchema,
45
59
  TextEffectRenderer: () => TextEffectRenderer,
46
60
  WEBM_EXPORT_MAX_FRAMES: () => WEBM_EXPORT_MAX_FRAMES,
47
61
  WebGLCompositor: () => WebGLCompositor,
@@ -107,6 +121,7 @@ __export(index_exports, {
107
121
  evaluateConfig: () => evaluateConfig,
108
122
  evaluateScene: () => evaluateScene,
109
123
  findTrackIndex: () => findTrackIndex,
124
+ formatValidationErrors: () => formatValidationErrors,
110
125
  getAnimPreset: () => getAnimPreset,
111
126
  getAnimatableParamDef: () => getAnimatableParamDef,
112
127
  getAnimatableParamsForLayer: () => getAnimatableParamsForLayer,
@@ -178,16 +193,198 @@ __export(index_exports, {
178
193
  textEffectConfigToScene: () => textEffectConfigToScene,
179
194
  trackId: () => trackId,
180
195
  updateKeyframe: () => updateKeyframe,
196
+ updateSceneBevel: () => updateSceneBevel,
197
+ updateSceneCanvas: () => updateSceneCanvas,
198
+ updateSceneCustomEngine: () => updateSceneCustomEngine,
199
+ updateSceneFill: () => updateSceneFill,
200
+ updateSceneGlow: () => updateSceneGlow,
201
+ updateScenePanel: () => updateScenePanel,
202
+ updateSceneShadow: () => updateSceneShadow,
203
+ updateSceneStack: () => updateSceneStack,
204
+ updateSceneStroke: () => updateSceneStroke,
205
+ updateSceneText: () => updateSceneText,
181
206
  updateStaticProperty: () => updateStaticProperty,
182
207
  updateTimeline: () => updateTimeline,
183
208
  updateTrack: () => updateTrack,
184
209
  updateTrackMatte: () => updateTrackMatte,
185
210
  upsertKeyframe: () => upsertKeyframe,
211
+ validateEffectDefinition: () => validateEffectDefinition,
212
+ validateEffectDefinitionStrict: () => validateEffectDefinitionStrict,
213
+ validateTextEffectDefinition: () => validateTextEffectDefinition,
214
+ validateTextEffectDefinitionStrict: () => validateTextEffectDefinitionStrict,
186
215
  waitForFontsReady: () => waitForFontsReady,
187
216
  wrapTextToWidth: () => wrapTextToWidth
188
217
  });
189
218
  module.exports = __toCommonJS(index_exports);
190
219
 
220
+ // src/validation.ts
221
+ var import_zod = require("zod");
222
+ var GradientStopSchema = import_zod.z.object({
223
+ color: import_zod.z.string(),
224
+ offset: import_zod.z.number().min(0).max(100)
225
+ });
226
+ var EffectFillSchema = import_zod.z.object({
227
+ type: import_zod.z.enum(["solid", "linear", "radial", "pattern", "none"]),
228
+ color: import_zod.z.string().optional(),
229
+ gradient: import_zod.z.object({
230
+ angle: import_zod.z.number(),
231
+ stops: import_zod.z.array(GradientStopSchema)
232
+ }).optional(),
233
+ patternType: import_zod.z.string().optional(),
234
+ perCharFillEnabled: import_zod.z.boolean().optional(),
235
+ charFillColors: import_zod.z.array(import_zod.z.string()).optional()
236
+ });
237
+ var EffectStrokeSchema = import_zod.z.object({
238
+ color: import_zod.z.string(),
239
+ width: import_zod.z.number().min(0),
240
+ position: import_zod.z.enum(["outside", "center", "inside"]).optional(),
241
+ opacity: import_zod.z.number().min(0).max(100).optional(),
242
+ lineJoin: import_zod.z.enum(["round", "miter", "bevel"]).optional(),
243
+ blur: import_zod.z.number().min(0).optional(),
244
+ type: import_zod.z.enum(["solid", "gradient"]).optional(),
245
+ colorSecondary: import_zod.z.string().optional(),
246
+ widthSecondary: import_zod.z.number().min(0).optional(),
247
+ fadeRange: import_zod.z.tuple([import_zod.z.number(), import_zod.z.number()]).optional()
248
+ });
249
+ var EffectShadowSchema = import_zod.z.object({
250
+ type: import_zod.z.enum(["drop", "inner"]).optional(),
251
+ color: import_zod.z.string(),
252
+ blur: import_zod.z.number().min(0),
253
+ offset: import_zod.z.object({
254
+ x: import_zod.z.number(),
255
+ y: import_zod.z.number()
256
+ }).optional(),
257
+ offsetX: import_zod.z.number().optional(),
258
+ // Legacy flat format
259
+ offsetY: import_zod.z.number().optional(),
260
+ // Legacy flat format
261
+ opacity: import_zod.z.number().min(0).max(100).optional()
262
+ }).refine((data) => data.offset !== void 0 || data.offsetX !== void 0 && data.offsetY !== void 0, { message: "Shadow must have either nested 'offset' or flat 'offsetX/offsetY'" });
263
+ var EffectBevelSchema = import_zod.z.object({
264
+ depth: import_zod.z.number().min(0),
265
+ highlight: import_zod.z.string().optional(),
266
+ // Current Studio output
267
+ highlightColor: import_zod.z.string().optional(),
268
+ // Legacy format
269
+ shadow: import_zod.z.string().optional(),
270
+ // Current Studio output
271
+ shadowColor: import_zod.z.string().optional(),
272
+ // Legacy format
273
+ direction: import_zod.z.enum(["bottom-right", "bottom", "right"]).optional(),
274
+ coreColor: import_zod.z.string().optional(),
275
+ edgeColor: import_zod.z.string().optional(),
276
+ edgeWidth: import_zod.z.number().min(0).optional(),
277
+ blur: import_zod.z.number().min(0).optional(),
278
+ blurColor: import_zod.z.string().optional(),
279
+ perspectiveEnabled: import_zod.z.boolean().optional(),
280
+ vanishingPointX: import_zod.z.number().optional(),
281
+ vanishingPointY: import_zod.z.number().optional(),
282
+ focalLength: import_zod.z.number().optional()
283
+ }).refine((data) => data.highlight !== void 0 || data.highlightColor !== void 0, { message: "Bevel must have either 'highlight' or 'highlightColor'" }).refine((data) => data.shadow !== void 0 || data.shadowColor !== void 0, { message: "Bevel must have either 'shadow' or 'shadowColor'" });
284
+ var EffectGlowSchema = import_zod.z.object({
285
+ color: import_zod.z.string(),
286
+ blur: import_zod.z.number().min(0),
287
+ opacity: import_zod.z.number().min(0).max(100),
288
+ type: import_zod.z.enum(["outer", "inner"]).optional(),
289
+ strength: import_zod.z.number().min(0).optional(),
290
+ spread: import_zod.z.number().min(0).optional()
291
+ });
292
+ var EffectPanelSchema = import_zod.z.object({
293
+ color: import_zod.z.string(),
294
+ opacity: import_zod.z.number().min(0).max(100),
295
+ radius: import_zod.z.number().min(0),
296
+ padding: import_zod.z.object({
297
+ x: import_zod.z.number().min(0),
298
+ y: import_zod.z.number().min(0)
299
+ }).optional(),
300
+ paddingX: import_zod.z.number().min(0).optional(),
301
+ // Legacy flat format
302
+ paddingY: import_zod.z.number().min(0).optional(),
303
+ // Legacy flat format
304
+ stroke: import_zod.z.object({
305
+ color: import_zod.z.string(),
306
+ width: import_zod.z.number().min(0)
307
+ }).nullable().optional()
308
+ }).refine((data) => data.padding !== void 0 || data.paddingX !== void 0 && data.paddingY !== void 0, { message: "Panel must have either nested 'padding' or flat 'paddingX/paddingY'" });
309
+ var EffectStackSchema = import_zod.z.object({
310
+ count: import_zod.z.number().int().min(1).max(100),
311
+ offsetX: import_zod.z.number(),
312
+ offsetY: import_zod.z.number(),
313
+ opacityDecay: import_zod.z.number().min(0).max(1),
314
+ color1: import_zod.z.string().optional(),
315
+ color2: import_zod.z.string().optional(),
316
+ color3: import_zod.z.string().optional(),
317
+ color4: import_zod.z.string().optional()
318
+ });
319
+ var FontSchema = import_zod.z.object({
320
+ family: import_zod.z.string().min(1),
321
+ weight: import_zod.z.number().int().min(100).max(900),
322
+ style: import_zod.z.enum(["normal", "italic"]),
323
+ letterSpacing: import_zod.z.number(),
324
+ lineHeight: import_zod.z.number().positive()
325
+ });
326
+ var AnimationSchema = import_zod.z.object({
327
+ type: import_zod.z.enum(["none", "typewriter", "wave", "fade", "glitch"]),
328
+ speed: import_zod.z.number().positive().optional(),
329
+ amplitude: import_zod.z.number().optional(),
330
+ frequency: import_zod.z.number().positive().optional()
331
+ });
332
+ var EffectIndexItemSchema = import_zod.z.object({
333
+ id: import_zod.z.string().min(1),
334
+ name: import_zod.z.string().min(1),
335
+ category: import_zod.z.string().min(1),
336
+ description: import_zod.z.string().optional(),
337
+ tags: import_zod.z.array(import_zod.z.string()).optional(),
338
+ isPremium: import_zod.z.boolean().optional(),
339
+ previewType: import_zod.z.enum(["static", "video", "lottie"]).optional(),
340
+ thumbnailUrl: import_zod.z.string().url().optional(),
341
+ thumbnail: import_zod.z.string().optional(),
342
+ previewUrl: import_zod.z.string().url().optional(),
343
+ durationMs: import_zod.z.number().positive().optional()
344
+ });
345
+ var EffectFullDefinitionSchema = EffectIndexItemSchema.extend({
346
+ version: import_zod.z.string().optional(),
347
+ description: import_zod.z.string(),
348
+ tags: import_zod.z.array(import_zod.z.string()),
349
+ font: FontSchema,
350
+ fills: import_zod.z.array(EffectFillSchema),
351
+ strokes: import_zod.z.array(EffectStrokeSchema),
352
+ shadows: import_zod.z.array(EffectShadowSchema),
353
+ bevel: EffectBevelSchema.optional(),
354
+ glow: EffectGlowSchema.optional(),
355
+ // Legacy single glow
356
+ glows: import_zod.z.array(EffectGlowSchema).optional(),
357
+ // Current multi-layer glows
358
+ panel: EffectPanelSchema.optional(),
359
+ glitch: import_zod.z.any().optional(),
360
+ // TODO: Define proper schema when glitch effects are implemented
361
+ animation: AnimationSchema.optional(),
362
+ background: import_zod.z.any().optional(),
363
+ // DEPRECATED: kept for backward compatibility
364
+ stack: EffectStackSchema.optional()
365
+ });
366
+ var TextEffectDefinitionSchema = EffectFullDefinitionSchema.extend({
367
+ text: import_zod.z.string().optional()
368
+ });
369
+ function validateEffectDefinition(data) {
370
+ return EffectFullDefinitionSchema.safeParse(data);
371
+ }
372
+ function validateEffectDefinitionStrict(data) {
373
+ return EffectFullDefinitionSchema.parse(data);
374
+ }
375
+ function validateTextEffectDefinition(data) {
376
+ return TextEffectDefinitionSchema.safeParse(data);
377
+ }
378
+ function validateTextEffectDefinitionStrict(data) {
379
+ return TextEffectDefinitionSchema.parse(data);
380
+ }
381
+ function formatValidationErrors(error) {
382
+ return error.issues.map((err) => {
383
+ const path = err.path.join(".");
384
+ return `${path ? `${path}: ` : ""}${err.message}`;
385
+ });
386
+ }
387
+
191
388
  // src/engine/schema.ts
192
389
  var SCENE_VERSION = 1;
193
390
  var DEFAULT_CANVAS_WIDTH = 800;
@@ -3219,16 +3416,20 @@ function _buildConfig(effect, text, fontSize, canvasWidth, canvasHeight, time, c
3219
3416
  if (shadow) {
3220
3417
  if (shadow.color !== void 0) config.shadowColor = shadow.color;
3221
3418
  if (shadow.blur !== void 0) config.shadowBlur = shadow.blur * ratio;
3222
- if (shadow.offsetX !== void 0) config.shadowOffsetX = shadow.offsetX * ratio;
3223
- if (shadow.offsetY !== void 0) config.shadowOffsetY = shadow.offsetY * ratio;
3419
+ if (shadow.offset?.x !== void 0) config.shadowOffsetX = shadow.offset.x * ratio;
3420
+ else if (shadow.offsetX !== void 0) config.shadowOffsetX = shadow.offsetX * ratio;
3421
+ if (shadow.offset?.y !== void 0) config.shadowOffsetY = shadow.offset.y * ratio;
3422
+ else if (shadow.offsetY !== void 0) config.shadowOffsetY = shadow.offsetY * ratio;
3224
3423
  if (shadow.opacity !== void 0) config.shadowOpacity = shadow.opacity;
3225
3424
  if (shadow.type !== void 0) config.shadowType = shadow.type;
3226
3425
  }
3227
3426
  config.bevelEnabled = !!bevel;
3228
3427
  if (bevel) {
3229
3428
  if (bevel.depth !== void 0) config.bevelDepth = Math.round(bevel.depth * ratio);
3230
- if (bevel.highlightColor !== void 0) config.bevelHighlight = bevel.highlightColor;
3231
- if (bevel.shadowColor !== void 0) config.bevelShadow = bevel.shadowColor;
3429
+ if (bevel.highlight !== void 0) config.bevelHighlight = bevel.highlight;
3430
+ else if (bevel.highlightColor !== void 0) config.bevelHighlight = bevel.highlightColor;
3431
+ if (bevel.shadow !== void 0) config.bevelShadow = bevel.shadow;
3432
+ else if (bevel.shadowColor !== void 0) config.bevelShadow = bevel.shadowColor;
3232
3433
  if (bevel.direction !== void 0) config.bevelDirection = bevel.direction;
3233
3434
  if (bevel.coreColor !== void 0) config.bevelCoreColor = bevel.coreColor;
3234
3435
  if (bevel.edgeColor !== void 0) config.bevelEdgeColor = bevel.edgeColor;
@@ -3256,8 +3457,10 @@ function _buildConfig(effect, text, fontSize, canvasWidth, canvasHeight, time, c
3256
3457
  if (panel.color !== void 0) config.panelColor = panel.color;
3257
3458
  if (panel.opacity !== void 0) config.panelOpacity = panel.opacity;
3258
3459
  if (panel.radius !== void 0) config.panelRadius = panel.radius;
3259
- if (panel.paddingX !== void 0) config.panelPaddingX = panel.paddingX * ratio;
3260
- if (panel.paddingY !== void 0) config.panelPaddingY = panel.paddingY * ratio;
3460
+ if (panel.padding?.x !== void 0) config.panelPaddingX = panel.padding.x * ratio;
3461
+ else if (panel.paddingX !== void 0) config.panelPaddingX = panel.paddingX * ratio;
3462
+ if (panel.padding?.y !== void 0) config.panelPaddingY = panel.padding.y * ratio;
3463
+ else if (panel.paddingY !== void 0) config.panelPaddingY = panel.paddingY * ratio;
3261
3464
  if (panel.stroke !== void 0) {
3262
3465
  config.panelStrokeEnabled = !!panel.stroke;
3263
3466
  if (panel.stroke.color !== void 0) config.panelStrokeColor = panel.stroke.color;
@@ -3278,23 +3481,7 @@ function _buildConfig(effect, text, fontSize, canvasWidth, canvasHeight, time, c
3278
3481
  return mappedGlow;
3279
3482
  });
3280
3483
  }
3281
- const standardKeys = /* @__PURE__ */ new Set([
3282
- "id",
3283
- "name",
3284
- "category",
3285
- "description",
3286
- "tags",
3287
- "font",
3288
- "fills",
3289
- "strokes",
3290
- "shadows",
3291
- "glows",
3292
- "bevel",
3293
- "panel",
3294
- "text",
3295
- "animation",
3296
- "stack"
3297
- ]);
3484
+ const standardKeys = /* @__PURE__ */ new Set(["id", "name", "category", "description", "tags", "font", "fills", "strokes", "shadows", "glows", "bevel", "panel", "text", "animation", "stack"]);
3298
3485
  for (const key of Object.keys(effect)) {
3299
3486
  if (!standardKeys.has(key)) {
3300
3487
  config[key] = effect[key];
@@ -4347,8 +4534,8 @@ function applyToLayerTransform(layer2, override) {
4347
4534
  ks.s.k = [override.scaleX, override.scaleY, 100];
4348
4535
  }
4349
4536
  if (override.posX !== void 0 && override.posY !== void 0 && ks.p?.a === 0) {
4350
- const z = Array.isArray(ks.p.k) ? ks.p.k[2] ?? 0 : 0;
4351
- ks.p.k = [override.posX, override.posY, z];
4537
+ const z2 = Array.isArray(ks.p.k) ? ks.p.k[2] ?? 0 : 0;
4538
+ ks.p.k = [override.posX, override.posY, z2];
4352
4539
  }
4353
4540
  }
4354
4541
  function mutateTextLayer(layer2, override) {
@@ -6632,8 +6819,824 @@ function duplicateTrackAtPlayhead(doc, trackIndex, previewTime) {
6632
6819
  const value = layer2 ? readLayerScalar(layer2, track.paramPath) : 0;
6633
6820
  return addKeyframeAtTime(doc, trackIndex, previewTime, value);
6634
6821
  }
6822
+
6823
+ // src/engine/api.ts
6824
+ function updateSceneText(doc, patch) {
6825
+ const nextText = { ...doc.text };
6826
+ if (patch.content !== void 0) nextText.content = patch.content;
6827
+ if (patch.fontFamily !== void 0) nextText.fontFamily = patch.fontFamily;
6828
+ if (patch.fontWeight !== void 0) nextText.fontWeight = patch.fontWeight;
6829
+ if (patch.fontStyle !== void 0) nextText.fontStyle = patch.fontStyle;
6830
+ if (patch.fontSize !== void 0) nextText.fontSize = patch.fontSize;
6831
+ if (patch.letterSpacing !== void 0) nextText.letterSpacing = patch.letterSpacing;
6832
+ if (patch.lineHeight !== void 0) nextText.lineHeight = patch.lineHeight;
6833
+ if (patch.textPosX !== void 0) nextText.textPosX = patch.textPosX;
6834
+ if (patch.textPosY !== void 0) nextText.textPosY = patch.textPosY;
6835
+ if (patch.wrapText !== void 0) nextText.wrapText = patch.wrapText;
6836
+ if (patch.autoFitText !== void 0) nextText.autoFitText = patch.autoFitText;
6837
+ if (patch.perCharFillEnabled !== void 0) nextText.perCharFillEnabled = patch.perCharFillEnabled;
6838
+ if (patch.charFillColors !== void 0) nextText.charFillColors = patch.charFillColors;
6839
+ const nextLegacyConfig = doc.legacyConfig ? { ...doc.legacyConfig } : void 0;
6840
+ if (nextLegacyConfig) {
6841
+ if (patch.content !== void 0) nextLegacyConfig.text = patch.content;
6842
+ if (patch.fontFamily !== void 0) nextLegacyConfig.fontFamily = patch.fontFamily;
6843
+ if (patch.fontWeight !== void 0) nextLegacyConfig.fontWeight = patch.fontWeight;
6844
+ if (patch.fontStyle !== void 0) nextLegacyConfig.fontStyle = patch.fontStyle;
6845
+ if (patch.fontSize !== void 0) nextLegacyConfig.fontSize = patch.fontSize;
6846
+ if (patch.letterSpacing !== void 0) nextLegacyConfig.letterSpacing = patch.letterSpacing;
6847
+ if (patch.lineHeight !== void 0) nextLegacyConfig.lineHeight = patch.lineHeight;
6848
+ if (patch.textPosX !== void 0) nextLegacyConfig.textPosX = patch.textPosX;
6849
+ if (patch.textPosY !== void 0) nextLegacyConfig.textPosY = patch.textPosY;
6850
+ if (patch.wrapText !== void 0) nextLegacyConfig.wrapText = patch.wrapText;
6851
+ if (patch.autoFitText !== void 0) nextLegacyConfig.autoFitText = patch.autoFitText;
6852
+ if (patch.perCharFillEnabled !== void 0) nextLegacyConfig.perCharFillEnabled = patch.perCharFillEnabled;
6853
+ if (patch.charFillColors !== void 0) nextLegacyConfig.charFillColors = patch.charFillColors;
6854
+ }
6855
+ return {
6856
+ ...doc,
6857
+ text: nextText,
6858
+ legacyConfig: nextLegacyConfig
6859
+ };
6860
+ }
6861
+ function updateScenePanel(doc, patch) {
6862
+ let panelFound = false;
6863
+ const nextLayers = doc.effectLayers.map((layer2) => {
6864
+ if (layer2.type === "panel") {
6865
+ panelFound = true;
6866
+ const nextParams = { ...layer2.params };
6867
+ if (patch.color !== void 0) nextParams.panelColor = patch.color;
6868
+ if (patch.opacity !== void 0) nextParams.panelOpacity = patch.opacity;
6869
+ if (patch.radius !== void 0) nextParams.panelRadius = patch.radius;
6870
+ if (patch.paddingX !== void 0) nextParams.panelPaddingX = patch.paddingX;
6871
+ if (patch.paddingY !== void 0) nextParams.panelPaddingY = patch.paddingY;
6872
+ if (patch.strokeEnabled !== void 0) nextParams.panelStrokeEnabled = patch.strokeEnabled;
6873
+ if (patch.strokeColor !== void 0) nextParams.panelStrokeColor = patch.strokeColor;
6874
+ if (patch.strokeWidth !== void 0) nextParams.panelStrokeWidth = patch.strokeWidth;
6875
+ const enabled = patch.enabled !== void 0 ? patch.enabled : layer2.enabled;
6876
+ if (patch.enabled !== void 0) {
6877
+ nextParams.panelEnabled = patch.enabled;
6878
+ }
6879
+ return {
6880
+ ...layer2,
6881
+ enabled,
6882
+ params: nextParams
6883
+ };
6884
+ }
6885
+ return layer2;
6886
+ });
6887
+ const layers = [...nextLayers];
6888
+ if (!panelFound) {
6889
+ const defaultParams = {
6890
+ panelEnabled: patch.enabled ?? true,
6891
+ panelColor: patch.color ?? "#1E1E26",
6892
+ panelOpacity: patch.opacity ?? 80,
6893
+ panelRadius: patch.radius ?? 12,
6894
+ panelPaddingX: patch.paddingX ?? 40,
6895
+ panelPaddingY: patch.paddingY ?? 20,
6896
+ panelStrokeEnabled: patch.strokeEnabled ?? false,
6897
+ panelStrokeColor: patch.strokeColor ?? "#2A2A38",
6898
+ panelStrokeWidth: patch.strokeWidth ?? 2
6899
+ };
6900
+ const newL = {
6901
+ id: newLayerId(),
6902
+ type: "panel",
6903
+ name: "Background Panel",
6904
+ enabled: patch.enabled ?? true,
6905
+ opacity: 1,
6906
+ blendMode: "source-over",
6907
+ target: "scene",
6908
+ params: defaultParams
6909
+ };
6910
+ layers.unshift(newL);
6911
+ }
6912
+ const nextLegacyConfig = doc.legacyConfig ? { ...doc.legacyConfig } : void 0;
6913
+ if (nextLegacyConfig) {
6914
+ if (patch.enabled !== void 0) nextLegacyConfig.panelEnabled = patch.enabled;
6915
+ if (patch.color !== void 0) nextLegacyConfig.panelColor = patch.color;
6916
+ if (patch.opacity !== void 0) nextLegacyConfig.panelOpacity = patch.opacity;
6917
+ if (patch.radius !== void 0) nextLegacyConfig.panelRadius = patch.radius;
6918
+ if (patch.paddingX !== void 0) nextLegacyConfig.panelPaddingX = patch.paddingX;
6919
+ if (patch.paddingY !== void 0) nextLegacyConfig.panelPaddingY = patch.paddingY;
6920
+ if (patch.strokeEnabled !== void 0) nextLegacyConfig.panelStrokeEnabled = patch.strokeEnabled;
6921
+ if (patch.strokeColor !== void 0) nextLegacyConfig.panelStrokeColor = patch.strokeColor;
6922
+ if (patch.strokeWidth !== void 0) nextLegacyConfig.panelStrokeWidth = patch.strokeWidth;
6923
+ }
6924
+ return {
6925
+ ...doc,
6926
+ effectLayers: layers,
6927
+ legacyConfig: nextLegacyConfig
6928
+ };
6929
+ }
6930
+ function updateSceneStroke(doc, patch) {
6931
+ let found = false;
6932
+ const nextLayers = doc.effectLayers.map((layer2) => {
6933
+ if (layer2.type === "stroke") {
6934
+ found = true;
6935
+ const nextParams = { ...layer2.params };
6936
+ if (patch.strokeColor !== void 0) nextParams.strokeColor = patch.strokeColor;
6937
+ if (patch.strokeWidth !== void 0) nextParams.strokeWidth = patch.strokeWidth;
6938
+ if (patch.strokePosition !== void 0) nextParams.strokePosition = patch.strokePosition;
6939
+ if (patch.strokeOpacity !== void 0) nextParams.strokeOpacity = patch.strokeOpacity;
6940
+ if (patch.strokeLineJoin !== void 0) nextParams.strokeLineJoin = patch.strokeLineJoin;
6941
+ if (patch.strokeBlur !== void 0) nextParams.strokeBlur = patch.strokeBlur;
6942
+ if (patch.strokeType !== void 0) nextParams.strokeType = patch.strokeType;
6943
+ if (patch.strokeColorSecondary !== void 0) nextParams.strokeColorSecondary = patch.strokeColorSecondary;
6944
+ if (patch.strokeWidthSecondary !== void 0) nextParams.strokeWidthSecondary = patch.strokeWidthSecondary;
6945
+ if (patch.strokeFadeRange !== void 0) nextParams.strokeFadeRange = patch.strokeFadeRange;
6946
+ const enabled = patch.enabled !== void 0 ? patch.enabled : layer2.enabled;
6947
+ if (patch.enabled !== void 0) {
6948
+ nextParams.strokeEnabled = patch.enabled;
6949
+ }
6950
+ return {
6951
+ ...layer2,
6952
+ enabled,
6953
+ params: nextParams
6954
+ };
6955
+ }
6956
+ return layer2;
6957
+ });
6958
+ const layers = [...nextLayers];
6959
+ if (!found) {
6960
+ const defaultParams = {
6961
+ strokeEnabled: patch.enabled ?? true,
6962
+ strokeColor: patch.strokeColor ?? "#7C6FFF",
6963
+ strokeWidth: patch.strokeWidth ?? 4,
6964
+ strokePosition: patch.strokePosition ?? "outside",
6965
+ strokeOpacity: patch.strokeOpacity ?? 100,
6966
+ strokeLineJoin: patch.strokeLineJoin ?? "round",
6967
+ strokeBlur: patch.strokeBlur ?? 0,
6968
+ strokeType: patch.strokeType ?? "single",
6969
+ strokeColorSecondary: patch.strokeColorSecondary ?? "#FFFFFF",
6970
+ strokeWidthSecondary: patch.strokeWidthSecondary ?? 4,
6971
+ strokeFadeRange: patch.strokeFadeRange ?? 0
6972
+ };
6973
+ const newL = {
6974
+ id: newLayerId(),
6975
+ type: "stroke",
6976
+ name: "Stroke",
6977
+ enabled: patch.enabled ?? true,
6978
+ opacity: 1,
6979
+ blendMode: "source-over",
6980
+ target: "text",
6981
+ params: defaultParams
6982
+ };
6983
+ const fillIdx = layers.findIndex((l) => l.type === "fill");
6984
+ if (fillIdx >= 0) {
6985
+ layers.splice(fillIdx, 0, newL);
6986
+ } else {
6987
+ const maskIdx = layers.findIndex((l) => l.type === "mask" || l.type === "filter");
6988
+ if (maskIdx >= 0) {
6989
+ layers.splice(maskIdx, 0, newL);
6990
+ } else {
6991
+ layers.push(newL);
6992
+ }
6993
+ }
6994
+ }
6995
+ const nextLegacyConfig = doc.legacyConfig ? { ...doc.legacyConfig } : void 0;
6996
+ if (nextLegacyConfig) {
6997
+ if (patch.enabled !== void 0) nextLegacyConfig.strokeEnabled = patch.enabled;
6998
+ if (patch.strokeColor !== void 0) nextLegacyConfig.strokeColor = patch.strokeColor;
6999
+ if (patch.strokeWidth !== void 0) nextLegacyConfig.strokeWidth = patch.strokeWidth;
7000
+ if (patch.strokePosition !== void 0) nextLegacyConfig.strokePosition = patch.strokePosition;
7001
+ if (patch.strokeOpacity !== void 0) nextLegacyConfig.strokeOpacity = patch.strokeOpacity;
7002
+ if (patch.strokeLineJoin !== void 0) nextLegacyConfig.strokeLineJoin = patch.strokeLineJoin;
7003
+ if (patch.strokeBlur !== void 0) nextLegacyConfig.strokeBlur = patch.strokeBlur;
7004
+ if (patch.strokeType !== void 0) nextLegacyConfig.strokeType = patch.strokeType;
7005
+ if (patch.strokeColorSecondary !== void 0) nextLegacyConfig.strokeColorSecondary = patch.strokeColorSecondary;
7006
+ if (patch.strokeWidthSecondary !== void 0) nextLegacyConfig.strokeWidthSecondary = patch.strokeWidthSecondary;
7007
+ if (patch.strokeFadeRange !== void 0) nextLegacyConfig.strokeFadeRange = patch.strokeFadeRange;
7008
+ }
7009
+ return {
7010
+ ...doc,
7011
+ effectLayers: layers,
7012
+ legacyConfig: nextLegacyConfig
7013
+ };
7014
+ }
7015
+ function updateSceneShadow(doc, patch) {
7016
+ let found = false;
7017
+ const nextLayers = doc.effectLayers.map((layer2) => {
7018
+ if (layer2.type === "shadow") {
7019
+ found = true;
7020
+ const nextParams = { ...layer2.params };
7021
+ if (patch.shadowColor !== void 0) nextParams.shadowColor = patch.shadowColor;
7022
+ if (patch.shadowBlur !== void 0) nextParams.shadowBlur = patch.shadowBlur;
7023
+ if (patch.shadowOffsetX !== void 0) nextParams.shadowOffsetX = patch.shadowOffsetX;
7024
+ if (patch.shadowOffsetY !== void 0) nextParams.shadowOffsetY = patch.shadowOffsetY;
7025
+ if (patch.shadowOpacity !== void 0) nextParams.shadowOpacity = patch.shadowOpacity;
7026
+ if (patch.shadowType !== void 0) nextParams.shadowType = patch.shadowType;
7027
+ const enabled = patch.enabled !== void 0 ? patch.enabled : layer2.enabled;
7028
+ if (patch.enabled !== void 0) {
7029
+ nextParams.shadowEnabled = patch.enabled;
7030
+ }
7031
+ return {
7032
+ ...layer2,
7033
+ enabled,
7034
+ params: nextParams
7035
+ };
7036
+ }
7037
+ return layer2;
7038
+ });
7039
+ const layers = [...nextLayers];
7040
+ if (!found) {
7041
+ const defaultParams = {
7042
+ shadowEnabled: patch.enabled ?? true,
7043
+ shadowColor: patch.shadowColor ?? "#000000",
7044
+ shadowBlur: patch.shadowBlur ?? 10,
7045
+ shadowOffsetX: patch.shadowOffsetX ?? 5,
7046
+ shadowOffsetY: patch.shadowOffsetY ?? 5,
7047
+ shadowOpacity: patch.shadowOpacity ?? 80,
7048
+ shadowType: patch.shadowType ?? "drop"
7049
+ };
7050
+ const newL = {
7051
+ id: newLayerId(),
7052
+ type: "shadow",
7053
+ name: "Shadow",
7054
+ enabled: patch.enabled ?? true,
7055
+ opacity: 1,
7056
+ blendMode: "source-over",
7057
+ target: "text",
7058
+ params: defaultParams
7059
+ };
7060
+ const panelIdx = layers.findIndex((l) => l.type === "panel");
7061
+ if (panelIdx >= 0) {
7062
+ layers.splice(panelIdx + 1, 0, newL);
7063
+ } else {
7064
+ layers.unshift(newL);
7065
+ }
7066
+ }
7067
+ const nextLegacyConfig = doc.legacyConfig ? { ...doc.legacyConfig } : void 0;
7068
+ if (nextLegacyConfig) {
7069
+ if (patch.enabled !== void 0) nextLegacyConfig.shadowEnabled = patch.enabled;
7070
+ if (patch.shadowColor !== void 0) nextLegacyConfig.shadowColor = patch.shadowColor;
7071
+ if (patch.shadowBlur !== void 0) nextLegacyConfig.shadowBlur = patch.shadowBlur;
7072
+ if (patch.shadowOffsetX !== void 0) nextLegacyConfig.shadowOffsetX = patch.shadowOffsetX;
7073
+ if (patch.shadowOffsetY !== void 0) nextLegacyConfig.shadowOffsetY = patch.shadowOffsetY;
7074
+ if (patch.shadowOpacity !== void 0) nextLegacyConfig.shadowOpacity = patch.shadowOpacity;
7075
+ if (patch.shadowType !== void 0) nextLegacyConfig.shadowType = patch.shadowType;
7076
+ }
7077
+ return {
7078
+ ...doc,
7079
+ effectLayers: layers,
7080
+ legacyConfig: nextLegacyConfig
7081
+ };
7082
+ }
7083
+ function updateSceneBevel(doc, patch) {
7084
+ let found = false;
7085
+ const nextLayers = doc.effectLayers.map((layer2) => {
7086
+ if (layer2.type === "extrusion") {
7087
+ found = true;
7088
+ const nextParams = { ...layer2.params };
7089
+ if (patch.bevelDepth !== void 0) nextParams.bevelDepth = patch.bevelDepth;
7090
+ if (patch.bevelHighlight !== void 0) nextParams.bevelHighlight = patch.bevelHighlight;
7091
+ if (patch.bevelShadow !== void 0) nextParams.bevelShadow = patch.bevelShadow;
7092
+ if (patch.bevelDirection !== void 0) nextParams.bevelDirection = patch.bevelDirection;
7093
+ if (patch.bevelCoreColor !== void 0) nextParams.bevelCoreColor = patch.bevelCoreColor;
7094
+ if (patch.bevelEdgeColor !== void 0) nextParams.bevelEdgeColor = patch.bevelEdgeColor;
7095
+ if (patch.bevelEdgeWidth !== void 0) nextParams.bevelEdgeWidth = patch.bevelEdgeWidth;
7096
+ if (patch.bevelBlur !== void 0) nextParams.bevelBlur = patch.bevelBlur;
7097
+ if (patch.bevelBlurColor !== void 0) nextParams.bevelBlurColor = patch.bevelBlurColor;
7098
+ if (patch.bevelPerspectiveEnabled !== void 0) nextParams.bevelPerspectiveEnabled = patch.bevelPerspectiveEnabled;
7099
+ if (patch.bevelVanishingPointX !== void 0) nextParams.bevelVanishingPointX = patch.bevelVanishingPointX;
7100
+ if (patch.bevelVanishingPointY !== void 0) nextParams.bevelVanishingPointY = patch.bevelVanishingPointY;
7101
+ if (patch.bevelFocalLength !== void 0) nextParams.bevelFocalLength = patch.bevelFocalLength;
7102
+ const enabled = patch.enabled !== void 0 ? patch.enabled : layer2.enabled;
7103
+ if (patch.enabled !== void 0) {
7104
+ nextParams.bevelEnabled = patch.enabled;
7105
+ }
7106
+ return {
7107
+ ...layer2,
7108
+ enabled,
7109
+ params: nextParams
7110
+ };
7111
+ }
7112
+ return layer2;
7113
+ });
7114
+ const layers = [...nextLayers];
7115
+ if (!found) {
7116
+ const defaultParams = {
7117
+ bevelEnabled: patch.enabled ?? true,
7118
+ bevelDepth: patch.bevelDepth ?? 5,
7119
+ bevelHighlight: patch.bevelHighlight ?? "#FFFFFF",
7120
+ bevelShadow: patch.bevelShadow ?? "#000000",
7121
+ bevelDirection: patch.bevelDirection ?? "bottom-right",
7122
+ bevelCoreColor: patch.bevelCoreColor ?? "#000000",
7123
+ bevelEdgeColor: patch.bevelEdgeColor ?? "#2A2A38",
7124
+ bevelEdgeWidth: patch.bevelEdgeWidth ?? 0,
7125
+ bevelBlur: patch.bevelBlur ?? 0,
7126
+ bevelBlurColor: patch.bevelBlurColor ?? "#000000",
7127
+ bevelPerspectiveEnabled: patch.bevelPerspectiveEnabled ?? false,
7128
+ bevelVanishingPointX: patch.bevelVanishingPointX ?? 40,
7129
+ bevelVanishingPointY: patch.bevelVanishingPointY ?? 80,
7130
+ bevelFocalLength: patch.bevelFocalLength ?? 400
7131
+ };
7132
+ const newL = {
7133
+ id: newLayerId(),
7134
+ type: "extrusion",
7135
+ name: "Bevel / Extrusion",
7136
+ enabled: patch.enabled ?? true,
7137
+ opacity: 1,
7138
+ blendMode: "source-over",
7139
+ target: "text",
7140
+ params: defaultParams
7141
+ };
7142
+ const stackIdx = layers.findIndex((l) => l.type === "duplicateStack");
7143
+ if (stackIdx >= 0) {
7144
+ layers.splice(stackIdx, 0, newL);
7145
+ } else {
7146
+ const strokeIdx = layers.findIndex((l) => l.type === "stroke");
7147
+ if (strokeIdx >= 0) {
7148
+ layers.splice(strokeIdx, 0, newL);
7149
+ } else {
7150
+ const maskIdx = layers.findIndex((l) => l.type === "mask" || l.type === "filter");
7151
+ if (maskIdx >= 0) {
7152
+ layers.splice(maskIdx, 0, newL);
7153
+ } else {
7154
+ layers.push(newL);
7155
+ }
7156
+ }
7157
+ }
7158
+ }
7159
+ const nextLegacyConfig = doc.legacyConfig ? { ...doc.legacyConfig } : void 0;
7160
+ if (nextLegacyConfig) {
7161
+ if (patch.enabled !== void 0) nextLegacyConfig.bevelEnabled = patch.enabled;
7162
+ if (patch.bevelDepth !== void 0) nextLegacyConfig.bevelDepth = patch.bevelDepth;
7163
+ if (patch.bevelHighlight !== void 0) nextLegacyConfig.bevelHighlight = patch.bevelHighlight;
7164
+ if (patch.bevelShadow !== void 0) nextLegacyConfig.bevelShadow = patch.bevelShadow;
7165
+ if (patch.bevelDirection !== void 0) nextLegacyConfig.bevelDirection = patch.bevelDirection;
7166
+ if (patch.bevelCoreColor !== void 0) nextLegacyConfig.bevelCoreColor = patch.bevelCoreColor;
7167
+ if (patch.bevelEdgeColor !== void 0) nextLegacyConfig.bevelEdgeColor = patch.bevelEdgeColor;
7168
+ if (patch.bevelEdgeWidth !== void 0) nextLegacyConfig.bevelEdgeWidth = patch.bevelEdgeWidth;
7169
+ if (patch.bevelBlur !== void 0) nextLegacyConfig.bevelBlur = patch.bevelBlur;
7170
+ if (patch.bevelBlurColor !== void 0) nextLegacyConfig.bevelBlurColor = patch.bevelBlurColor;
7171
+ if (patch.bevelPerspectiveEnabled !== void 0) nextLegacyConfig.bevelPerspectiveEnabled = patch.bevelPerspectiveEnabled;
7172
+ if (patch.bevelVanishingPointX !== void 0) nextLegacyConfig.bevelVanishingPointX = patch.bevelVanishingPointX;
7173
+ if (patch.bevelVanishingPointY !== void 0) nextLegacyConfig.bevelVanishingPointY = patch.bevelVanishingPointY;
7174
+ if (patch.bevelFocalLength !== void 0) nextLegacyConfig.bevelFocalLength = patch.bevelFocalLength;
7175
+ }
7176
+ return {
7177
+ ...doc,
7178
+ effectLayers: layers,
7179
+ legacyConfig: nextLegacyConfig
7180
+ };
7181
+ }
7182
+ function updateSceneStack(doc, patch) {
7183
+ let found = false;
7184
+ const nextLayers = doc.effectLayers.map((layer2) => {
7185
+ if (layer2.type === "duplicateStack") {
7186
+ found = true;
7187
+ const nextParams = { ...layer2.params };
7188
+ if (patch.stackCount !== void 0) nextParams.stackCount = patch.stackCount;
7189
+ if (patch.stackOffsetX !== void 0) nextParams.stackOffsetX = patch.stackOffsetX;
7190
+ if (patch.stackOffsetY !== void 0) nextParams.stackOffsetY = patch.stackOffsetY;
7191
+ if (patch.stackOpacityDecay !== void 0) nextParams.stackOpacityDecay = patch.stackOpacityDecay;
7192
+ if (patch.stackColor1 !== void 0) nextParams.stackColor1 = patch.stackColor1;
7193
+ if (patch.stackColor2 !== void 0) nextParams.stackColor2 = patch.stackColor2;
7194
+ if (patch.stackColor3 !== void 0) nextParams.stackColor3 = patch.stackColor3;
7195
+ if (patch.stackColor4 !== void 0) nextParams.stackColor4 = patch.stackColor4;
7196
+ const enabled = patch.enabled !== void 0 ? patch.enabled : layer2.enabled;
7197
+ if (patch.enabled !== void 0) {
7198
+ nextParams.stackEnabled = patch.enabled;
7199
+ }
7200
+ return {
7201
+ ...layer2,
7202
+ enabled,
7203
+ params: nextParams
7204
+ };
7205
+ }
7206
+ return layer2;
7207
+ });
7208
+ const layers = [...nextLayers];
7209
+ if (!found) {
7210
+ const defaultParams = {
7211
+ stackEnabled: patch.enabled ?? true,
7212
+ stackCount: patch.stackCount ?? 3,
7213
+ stackOffsetX: patch.stackOffsetX ?? 10,
7214
+ stackOffsetY: patch.stackOffsetY ?? -10,
7215
+ stackOpacityDecay: patch.stackOpacityDecay ?? 20,
7216
+ stackColor1: patch.stackColor1 ?? "#FF7C00",
7217
+ stackColor2: patch.stackColor2 ?? "#00FFDD",
7218
+ stackColor3: patch.stackColor3 ?? "#FF00AA",
7219
+ stackColor4: patch.stackColor4 ?? "#AA00FF"
7220
+ };
7221
+ const newL = {
7222
+ id: newLayerId(),
7223
+ type: "duplicateStack",
7224
+ name: "Stack Extrusion",
7225
+ enabled: patch.enabled ?? true,
7226
+ opacity: 1,
7227
+ blendMode: "source-over",
7228
+ target: "text",
7229
+ params: defaultParams
7230
+ };
7231
+ const strokeIdx = layers.findIndex((l) => l.type === "stroke");
7232
+ if (strokeIdx >= 0) {
7233
+ layers.splice(strokeIdx, 0, newL);
7234
+ } else {
7235
+ const maskIdx = layers.findIndex((l) => l.type === "mask" || l.type === "filter");
7236
+ if (maskIdx >= 0) {
7237
+ layers.splice(maskIdx, 0, newL);
7238
+ } else {
7239
+ layers.push(newL);
7240
+ }
7241
+ }
7242
+ }
7243
+ const nextLegacyConfig = doc.legacyConfig ? { ...doc.legacyConfig } : void 0;
7244
+ if (nextLegacyConfig) {
7245
+ if (patch.enabled !== void 0) nextLegacyConfig.stackEnabled = patch.enabled;
7246
+ if (patch.stackCount !== void 0) nextLegacyConfig.stackCount = patch.stackCount;
7247
+ if (patch.stackOffsetX !== void 0) nextLegacyConfig.stackOffsetX = patch.stackOffsetX;
7248
+ if (patch.stackOffsetY !== void 0) nextLegacyConfig.stackOffsetY = patch.stackOffsetY;
7249
+ if (patch.stackOpacityDecay !== void 0) nextLegacyConfig.stackOpacityDecay = patch.stackOpacityDecay;
7250
+ if (patch.stackColor1 !== void 0) nextLegacyConfig.stackColor1 = patch.stackColor1;
7251
+ if (patch.stackColor2 !== void 0) nextLegacyConfig.stackColor2 = patch.stackColor2;
7252
+ if (patch.stackColor3 !== void 0) nextLegacyConfig.stackColor3 = patch.stackColor3;
7253
+ if (patch.stackColor4 !== void 0) nextLegacyConfig.stackColor4 = patch.stackColor4;
7254
+ }
7255
+ return {
7256
+ ...doc,
7257
+ effectLayers: layers,
7258
+ legacyConfig: nextLegacyConfig
7259
+ };
7260
+ }
7261
+ function updateSceneFill(doc, patch) {
7262
+ let found = false;
7263
+ const nextLayers = doc.effectLayers.map((layer2) => {
7264
+ if (layer2.type === "fill") {
7265
+ found = true;
7266
+ const nextParams = { ...layer2.params };
7267
+ if (patch.fillType !== void 0) nextParams.fillType = patch.fillType;
7268
+ if (patch.fillColor !== void 0) nextParams.fillColor = patch.fillColor;
7269
+ if (patch.fillGradientAngle !== void 0) nextParams.fillGradientAngle = patch.fillGradientAngle;
7270
+ if (patch.fillGradientStops !== void 0) nextParams.fillGradientStops = patch.fillGradientStops;
7271
+ if (patch.patternType !== void 0) nextParams.patternType = patch.patternType;
7272
+ if (patch.perCharFillEnabled !== void 0) nextParams.perCharFillEnabled = patch.perCharFillEnabled;
7273
+ if (patch.charFillColors !== void 0) nextParams.charFillColors = patch.charFillColors;
7274
+ const enabled = patch.fillType !== void 0 ? patch.fillType !== "none" : layer2.enabled;
7275
+ return {
7276
+ ...layer2,
7277
+ enabled,
7278
+ params: nextParams
7279
+ };
7280
+ }
7281
+ return layer2;
7282
+ });
7283
+ const layers = [...nextLayers];
7284
+ if (!found) {
7285
+ const defaultParams = {
7286
+ fillType: patch.fillType ?? "solid",
7287
+ fillColor: patch.fillColor ?? "#FFFFFF",
7288
+ fillGradientAngle: patch.fillGradientAngle ?? 90,
7289
+ fillGradientStops: patch.fillGradientStops ?? [
7290
+ { color: "#FFFFFF", offset: 0 },
7291
+ { color: "#E0E0E0", offset: 100 }
7292
+ ],
7293
+ patternType: patch.patternType ?? "chalk",
7294
+ perCharFillEnabled: patch.perCharFillEnabled ?? false,
7295
+ charFillColors: patch.charFillColors ?? []
7296
+ };
7297
+ const newL = {
7298
+ id: newLayerId(),
7299
+ type: "fill",
7300
+ name: "Fill",
7301
+ enabled: patch.fillType !== "none",
7302
+ opacity: 1,
7303
+ blendMode: "source-over",
7304
+ target: "text",
7305
+ params: defaultParams
7306
+ };
7307
+ const maskIdx = layers.findIndex((l) => l.type === "mask" || l.type === "filter");
7308
+ if (maskIdx >= 0) {
7309
+ layers.splice(maskIdx, 0, newL);
7310
+ } else {
7311
+ layers.push(newL);
7312
+ }
7313
+ }
7314
+ const nextLegacyConfig = doc.legacyConfig ? { ...doc.legacyConfig } : void 0;
7315
+ if (nextLegacyConfig) {
7316
+ if (patch.fillType !== void 0) nextLegacyConfig.fillType = patch.fillType;
7317
+ if (patch.fillColor !== void 0) nextLegacyConfig.fillColor = patch.fillColor;
7318
+ if (patch.fillGradientAngle !== void 0) nextLegacyConfig.fillGradientAngle = patch.fillGradientAngle;
7319
+ if (patch.fillGradientStops !== void 0) nextLegacyConfig.fillGradientStops = patch.fillGradientStops;
7320
+ if (patch.patternType !== void 0) nextLegacyConfig.patternType = patch.patternType;
7321
+ if (patch.perCharFillEnabled !== void 0) nextLegacyConfig.perCharFillEnabled = patch.perCharFillEnabled;
7322
+ if (patch.charFillColors !== void 0) nextLegacyConfig.charFillColors = patch.charFillColors;
7323
+ }
7324
+ return {
7325
+ ...doc,
7326
+ effectLayers: layers,
7327
+ legacyConfig: nextLegacyConfig
7328
+ };
7329
+ }
7330
+ function updateSceneGlow(doc, index, patch) {
7331
+ const currentGlowLayers = doc.effectLayers.filter((l) => l.type === "glow");
7332
+ const layers = [...doc.effectLayers];
7333
+ if (index >= currentGlowLayers.length) {
7334
+ const needed = index - currentGlowLayers.length + 1;
7335
+ for (let i = 0; i < needed; i++) {
7336
+ const isTarget = i === needed - 1;
7337
+ const defaultGlow = {
7338
+ enabled: isTarget ? patch.enabled ?? false : false,
7339
+ color: isTarget ? patch.color ?? "#7C6FFF" : "#7C6FFF",
7340
+ blur: isTarget ? patch.blur ?? 20 : 20,
7341
+ opacity: isTarget ? patch.opacity ?? 80 : 80,
7342
+ type: isTarget ? patch.type ?? "outer" : "outer",
7343
+ strength: isTarget ? patch.strength : void 0,
7344
+ spread: isTarget ? patch.spread : void 0
7345
+ };
7346
+ const newL = {
7347
+ id: newLayerId(),
7348
+ type: "glow",
7349
+ name: `Glow ${currentGlowLayers.length + i + 1}`,
7350
+ enabled: defaultGlow.enabled,
7351
+ opacity: defaultGlow.opacity / 100,
7352
+ blendMode: "source-over",
7353
+ target: "text",
7354
+ params: defaultGlow
7355
+ };
7356
+ const lastGlowIdx = layers.map((l) => l.type).lastIndexOf("glow");
7357
+ if (lastGlowIdx >= 0) {
7358
+ layers.splice(lastGlowIdx + 1 + i, 0, newL);
7359
+ } else {
7360
+ const insertIdx = layers.findIndex((l) => l.type === "mask" || l.type === "filter");
7361
+ if (insertIdx >= 0) {
7362
+ layers.splice(insertIdx + i, 0, newL);
7363
+ } else {
7364
+ layers.push(newL);
7365
+ }
7366
+ }
7367
+ }
7368
+ } else {
7369
+ let glowCount = 0;
7370
+ for (let i = 0; i < layers.length; i++) {
7371
+ if (layers[i].type === "glow") {
7372
+ if (glowCount === index) {
7373
+ const layer2 = layers[i];
7374
+ const nextParams = { ...layer2.params, ...patch };
7375
+ const enabled = patch.enabled !== void 0 ? patch.enabled : layer2.enabled;
7376
+ const opacity = patch.opacity !== void 0 ? patch.opacity / 100 : layer2.opacity;
7377
+ layers[i] = {
7378
+ ...layer2,
7379
+ enabled,
7380
+ opacity,
7381
+ params: nextParams
7382
+ };
7383
+ break;
7384
+ }
7385
+ glowCount++;
7386
+ }
7387
+ }
7388
+ }
7389
+ const nextLegacyConfig = doc.legacyConfig ? { ...doc.legacyConfig } : void 0;
7390
+ if (nextLegacyConfig) {
7391
+ if (!nextLegacyConfig.glowLayers) nextLegacyConfig.glowLayers = [];
7392
+ while (nextLegacyConfig.glowLayers.length <= index) {
7393
+ nextLegacyConfig.glowLayers.push({
7394
+ enabled: false,
7395
+ color: "#7C6FFF",
7396
+ blur: 20,
7397
+ opacity: 80,
7398
+ type: "outer"
7399
+ });
7400
+ }
7401
+ nextLegacyConfig.glowLayers[index] = { ...nextLegacyConfig.glowLayers[index], ...patch };
7402
+ }
7403
+ return {
7404
+ ...doc,
7405
+ effectLayers: layers,
7406
+ legacyConfig: nextLegacyConfig
7407
+ };
7408
+ }
7409
+ function updateSceneCanvas(doc, patch) {
7410
+ const nextCanvas = { ...doc.canvas };
7411
+ if (patch.width !== void 0) nextCanvas.width = patch.width;
7412
+ if (patch.height !== void 0) nextCanvas.height = patch.height;
7413
+ if (patch.background !== void 0) nextCanvas.background = patch.background;
7414
+ const nextLegacyConfig = doc.legacyConfig ? { ...doc.legacyConfig } : void 0;
7415
+ if (nextLegacyConfig) {
7416
+ if (patch.width !== void 0) nextLegacyConfig.canvasWidth = patch.width;
7417
+ if (patch.height !== void 0) nextLegacyConfig.canvasHeight = patch.height;
7418
+ }
7419
+ return {
7420
+ ...doc,
7421
+ canvas: nextCanvas,
7422
+ legacyConfig: nextLegacyConfig
7423
+ };
7424
+ }
7425
+ function updateSceneCustomEngine(doc, patch) {
7426
+ let nextEngineId = doc.customEngineId;
7427
+ if (patch.customRenderer !== void 0) {
7428
+ nextEngineId = patch.customRenderer ? LEGACY_RENDERER_MAP[patch.customRenderer] ?? null : null;
7429
+ }
7430
+ const nextParams = { ...doc.engineParams, ...patch };
7431
+ delete nextParams.customRenderer;
7432
+ const nextLayers = doc.effectLayers.map((layer2) => {
7433
+ if (layer2.type === "customEngine") {
7434
+ if (layer2.name === "Custom Engine") {
7435
+ return {
7436
+ ...layer2,
7437
+ params: { ...layer2.params, engineId: nextEngineId }
7438
+ };
7439
+ } else if (layer2.name === "Engine Params") {
7440
+ return {
7441
+ ...layer2,
7442
+ params: { ...layer2.params, ...nextParams }
7443
+ };
7444
+ }
7445
+ }
7446
+ return layer2;
7447
+ });
7448
+ const nextLegacyConfig = doc.legacyConfig ? { ...doc.legacyConfig } : void 0;
7449
+ if (nextLegacyConfig) {
7450
+ if (patch.customRenderer !== void 0) nextLegacyConfig.customRenderer = patch.customRenderer;
7451
+ if (patch.inkColor !== void 0) nextLegacyConfig.inkColor = patch.inkColor;
7452
+ if (patch.bristleDensity !== void 0) nextLegacyConfig.bristleDensity = patch.bristleDensity;
7453
+ if (patch.bristleSkipRate !== void 0) nextLegacyConfig.bristleSkipRate = patch.bristleSkipRate;
7454
+ if (patch.dripRate !== void 0) nextLegacyConfig.dripRate = patch.dripRate;
7455
+ if (patch.dripMaxLength !== void 0) nextLegacyConfig.dripMaxLength = patch.dripMaxLength;
7456
+ if (patch.grainDensity !== void 0) nextLegacyConfig.grainDensity = patch.grainDensity;
7457
+ if (patch.skewX !== void 0) nextLegacyConfig.skewX = patch.skewX;
7458
+ }
7459
+ return {
7460
+ ...doc,
7461
+ customEngineId: nextEngineId,
7462
+ engineParams: nextParams,
7463
+ effectLayers: nextLayers,
7464
+ legacyConfig: nextLegacyConfig
7465
+ };
7466
+ }
7467
+ var TextEffectBuilder = class _TextEffectBuilder {
7468
+ config;
7469
+ constructor(initialConfig) {
7470
+ this.config = { ...defaultConfig, ...initialConfig };
7471
+ }
7472
+ /** Load builder from an existing TextEffectConfig object */
7473
+ static fromConfig(config) {
7474
+ return new _TextEffectBuilder(config);
7475
+ }
7476
+ /** Load builder from an existing SceneDocument */
7477
+ static fromScene(scene) {
7478
+ return new _TextEffectBuilder(sceneToConfig(scene));
7479
+ }
7480
+ /**
7481
+ * Load builder from a downloaded TextEffectDefinition.
7482
+ * Resolves the styling definition structure to a flat engine config.
7483
+ */
7484
+ static fromDefinition(effect, text = "CLYPRA", fontSize = 80, canvasWidth = 800, canvasHeight = 200) {
7485
+ const config = _buildConfig(effect, text, fontSize, canvasWidth, canvasHeight);
7486
+ return new _TextEffectBuilder(config);
7487
+ }
7488
+ /** Set text string content */
7489
+ setText(text) {
7490
+ this.config.text = text;
7491
+ return this;
7492
+ }
7493
+ /** Configure Font and alignment settings */
7494
+ setFont(font) {
7495
+ if (font.family !== void 0) this.config.fontFamily = font.family;
7496
+ if (font.weight !== void 0) this.config.fontWeight = font.weight;
7497
+ if (font.style !== void 0) this.config.fontStyle = font.style;
7498
+ if (font.size !== void 0) this.config.fontSize = font.size;
7499
+ if (font.letterSpacing !== void 0) this.config.letterSpacing = font.letterSpacing;
7500
+ if (font.lineHeight !== void 0) this.config.lineHeight = font.lineHeight;
7501
+ return this;
7502
+ }
7503
+ /** Configure Background Panel (bounding plate) */
7504
+ setPanel(panel) {
7505
+ if (panel.enabled !== void 0) this.config.panelEnabled = panel.enabled;
7506
+ if (panel.color !== void 0) this.config.panelColor = panel.color;
7507
+ if (panel.opacity !== void 0) this.config.panelOpacity = panel.opacity;
7508
+ if (panel.radius !== void 0) this.config.panelRadius = panel.radius;
7509
+ if (panel.paddingX !== void 0) this.config.panelPaddingX = panel.paddingX;
7510
+ if (panel.paddingY !== void 0) this.config.panelPaddingY = panel.paddingY;
7511
+ if (panel.strokeEnabled !== void 0) this.config.panelStrokeEnabled = panel.strokeEnabled;
7512
+ if (panel.strokeColor !== void 0) this.config.panelStrokeColor = panel.strokeColor;
7513
+ if (panel.strokeWidth !== void 0) this.config.panelStrokeWidth = panel.strokeWidth;
7514
+ return this;
7515
+ }
7516
+ /** Configure outline / stroke styling */
7517
+ setStroke(stroke) {
7518
+ if (stroke.enabled !== void 0) this.config.strokeEnabled = stroke.enabled;
7519
+ if (stroke.color !== void 0) this.config.strokeColor = stroke.color;
7520
+ if (stroke.width !== void 0) this.config.strokeWidth = stroke.width;
7521
+ if (stroke.position !== void 0) this.config.strokePosition = stroke.position;
7522
+ if (stroke.opacity !== void 0) this.config.strokeOpacity = stroke.opacity;
7523
+ if (stroke.lineJoin !== void 0) this.config.strokeLineJoin = stroke.lineJoin;
7524
+ if (stroke.blur !== void 0) this.config.strokeBlur = stroke.blur;
7525
+ if (stroke.type !== void 0) this.config.strokeType = stroke.type;
7526
+ if (stroke.colorSecondary !== void 0) this.config.strokeColorSecondary = stroke.colorSecondary;
7527
+ if (stroke.widthSecondary !== void 0) this.config.strokeWidthSecondary = stroke.widthSecondary;
7528
+ if (stroke.fadeRange !== void 0) this.config.strokeFadeRange = stroke.fadeRange;
7529
+ return this;
7530
+ }
7531
+ /** Configure drop shadow / inner shadow styling */
7532
+ setShadow(shadow) {
7533
+ if (shadow.enabled !== void 0) this.config.shadowEnabled = shadow.enabled;
7534
+ if (shadow.color !== void 0) this.config.shadowColor = shadow.color;
7535
+ if (shadow.blur !== void 0) this.config.shadowBlur = shadow.blur;
7536
+ if (shadow.offsetX !== void 0) this.config.shadowOffsetX = shadow.offsetX;
7537
+ if (shadow.offsetY !== void 0) this.config.shadowOffsetY = shadow.offsetY;
7538
+ if (shadow.opacity !== void 0) this.config.shadowOpacity = shadow.opacity;
7539
+ if (shadow.type !== void 0) this.config.shadowType = shadow.type;
7540
+ return this;
7541
+ }
7542
+ /** Configure a specific glow layer by index */
7543
+ setGlow(index, glow) {
7544
+ if (!this.config.glowLayers) this.config.glowLayers = [];
7545
+ while (this.config.glowLayers.length <= index) {
7546
+ this.config.glowLayers.push({ enabled: false, color: "#7C6FFF", blur: 20, opacity: 80, type: "outer" });
7547
+ }
7548
+ this.config.glowLayers[index] = { ...this.config.glowLayers[index], ...glow };
7549
+ return this;
7550
+ }
7551
+ /** Configure solid color fill */
7552
+ setFillColor(color) {
7553
+ this.config.fillType = "solid";
7554
+ this.config.fillColor = color;
7555
+ return this;
7556
+ }
7557
+ /** Configure linear gradient fill */
7558
+ setFillGradient(angle, stops) {
7559
+ this.config.fillType = "linear";
7560
+ this.config.fillGradientAngle = angle;
7561
+ this.config.fillGradientStops = stops;
7562
+ return this;
7563
+ }
7564
+ /** Configure texture pattern fill */
7565
+ setFillPattern(patternType) {
7566
+ this.config.fillType = "pattern";
7567
+ this.config.patternType = patternType;
7568
+ return this;
7569
+ }
7570
+ /** Configure per-character solid color fill overrides */
7571
+ setPerCharFill(enabled, colors) {
7572
+ this.config.perCharFillEnabled = enabled;
7573
+ this.config.charFillColors = colors;
7574
+ return this;
7575
+ }
7576
+ /** Configure 3D extrusion/bevel settings */
7577
+ setBevel(bevel) {
7578
+ if (bevel.enabled !== void 0) this.config.bevelEnabled = bevel.enabled;
7579
+ if (bevel.depth !== void 0) this.config.bevelDepth = bevel.depth;
7580
+ if (bevel.highlight !== void 0) this.config.bevelHighlight = bevel.highlight;
7581
+ if (bevel.bevelShadow !== void 0) this.config.bevelShadow = bevel.bevelShadow;
7582
+ if (bevel.direction !== void 0) this.config.bevelDirection = bevel.direction;
7583
+ if (bevel.coreColor !== void 0) this.config.bevelCoreColor = bevel.coreColor;
7584
+ if (bevel.edgeColor !== void 0) this.config.bevelEdgeColor = bevel.edgeColor;
7585
+ if (bevel.edgeWidth !== void 0) this.config.bevelEdgeWidth = bevel.edgeWidth;
7586
+ if (bevel.blur !== void 0) this.config.bevelBlur = bevel.blur;
7587
+ if (bevel.blurColor !== void 0) this.config.bevelBlurColor = bevel.blurColor;
7588
+ if (bevel.perspectiveEnabled !== void 0) this.config.bevelPerspectiveEnabled = bevel.perspectiveEnabled;
7589
+ if (bevel.vanishingPointX !== void 0) this.config.bevelVanishingPointX = bevel.vanishingPointX;
7590
+ if (bevel.vanishingPointY !== void 0) this.config.bevelVanishingPointY = bevel.vanishingPointY;
7591
+ if (bevel.focalLength !== void 0) this.config.bevelFocalLength = bevel.focalLength;
7592
+ return this;
7593
+ }
7594
+ /** Configure multi-stack duplicate extrusion */
7595
+ setStack(stack) {
7596
+ if (stack.enabled !== void 0) this.config.stackEnabled = stack.enabled;
7597
+ if (stack.count !== void 0) this.config.stackCount = stack.count;
7598
+ if (stack.offsetX !== void 0) this.config.stackOffsetX = stack.offsetX;
7599
+ if (stack.offsetY !== void 0) this.config.stackOffsetY = stack.offsetY;
7600
+ if (stack.opacityDecay !== void 0) this.config.stackOpacityDecay = stack.opacityDecay;
7601
+ if (stack.color1 !== void 0) this.config.stackColor1 = stack.color1;
7602
+ if (stack.color2 !== void 0) this.config.stackColor2 = stack.color2;
7603
+ if (stack.color3 !== void 0) this.config.stackColor3 = stack.color3;
7604
+ if (stack.color4 !== void 0) this.config.stackColor4 = stack.color4;
7605
+ return this;
7606
+ }
7607
+ /** Configure canvas viewport size, alignment positioning, and wrapping behavior */
7608
+ setCanvas(canvas) {
7609
+ if (canvas.width !== void 0) this.config.canvasWidth = canvas.width;
7610
+ if (canvas.height !== void 0) this.config.canvasHeight = canvas.height;
7611
+ if (canvas.posX !== void 0) this.config.textPosX = canvas.posX;
7612
+ if (canvas.posY !== void 0) this.config.textPosY = canvas.posY;
7613
+ if (canvas.wrapText !== void 0) this.config.wrapText = canvas.wrapText;
7614
+ if (canvas.autoFitText !== void 0) this.config.autoFitText = canvas.autoFitText;
7615
+ return this;
7616
+ }
7617
+ /** Configure procedural InkBrushEngine variables (when customRenderer = InkBrushEngine) */
7618
+ setInkBrush(ink) {
7619
+ if (ink.inkColor !== void 0) this.config.inkColor = ink.inkColor;
7620
+ if (ink.bristleDensity !== void 0) this.config.bristleDensity = ink.bristleDensity;
7621
+ if (ink.bristleSkipRate !== void 0) this.config.bristleSkipRate = ink.bristleSkipRate;
7622
+ if (ink.dripRate !== void 0) this.config.dripRate = ink.dripRate;
7623
+ if (ink.dripMaxLength !== void 0) this.config.dripMaxLength = ink.dripMaxLength;
7624
+ if (ink.grainDensity !== void 0) this.config.grainDensity = ink.grainDensity;
7625
+ if (ink.skewX !== void 0) this.config.skewX = ink.skewX;
7626
+ return this;
7627
+ }
7628
+ /** Build and return a copy of the updated TextEffectConfig */
7629
+ buildConfig() {
7630
+ return { ...this.config };
7631
+ }
7632
+ /** Build and return a SceneDocument prepared for rendering with evaluateScene */
7633
+ buildScene() {
7634
+ return textEffectConfigToScene(this.config);
7635
+ }
7636
+ };
6635
7637
  // Annotate the CommonJS export names for ESM import in node:
6636
7638
  0 && (module.exports = {
7639
+ AnimationSchema,
6637
7640
  COMPOSITION_PRESETS,
6638
7641
  CUSTOM_ENGINE_IDS,
6639
7642
  CanvasDevice,
@@ -6647,8 +7650,19 @@ function duplicateTrackAtPlayhead(doc, trackIndex, previewTime) {
6647
7650
  ENGINE_ID_TO_LEGACY,
6648
7651
  ENTRANCE_PRESETS,
6649
7652
  EXIT_PRESETS,
7653
+ EffectBevelSchema,
7654
+ EffectFillSchema,
7655
+ EffectFullDefinitionSchema,
7656
+ EffectGlowSchema,
7657
+ EffectIndexItemSchema,
7658
+ EffectPanelSchema,
7659
+ EffectShadowSchema,
7660
+ EffectStackSchema,
7661
+ EffectStrokeSchema,
6650
7662
  FONT_WEIGHT_OPTIONS,
6651
7663
  FontLoader,
7664
+ FontSchema,
7665
+ GradientStopSchema,
6652
7666
  InkBrushEngine,
6653
7667
  LEGACY_RENDERER_MAP,
6654
7668
  LOOP_PRESETS,
@@ -6657,6 +7671,8 @@ function duplicateTrackAtPlayhead(doc, trackIndex, previewTime) {
6657
7671
  SCENE_VERSION,
6658
7672
  SUPPORTED_FONT_FAMILIES,
6659
7673
  TEMPLATE_CATEGORIES,
7674
+ TextEffectBuilder,
7675
+ TextEffectDefinitionSchema,
6660
7676
  TextEffectRenderer,
6661
7677
  WEBM_EXPORT_MAX_FRAMES,
6662
7678
  WebGLCompositor,
@@ -6722,6 +7738,7 @@ function duplicateTrackAtPlayhead(doc, trackIndex, previewTime) {
6722
7738
  evaluateConfig,
6723
7739
  evaluateScene,
6724
7740
  findTrackIndex,
7741
+ formatValidationErrors,
6725
7742
  getAnimPreset,
6726
7743
  getAnimatableParamDef,
6727
7744
  getAnimatableParamsForLayer,
@@ -6793,11 +7810,25 @@ function duplicateTrackAtPlayhead(doc, trackIndex, previewTime) {
6793
7810
  textEffectConfigToScene,
6794
7811
  trackId,
6795
7812
  updateKeyframe,
7813
+ updateSceneBevel,
7814
+ updateSceneCanvas,
7815
+ updateSceneCustomEngine,
7816
+ updateSceneFill,
7817
+ updateSceneGlow,
7818
+ updateScenePanel,
7819
+ updateSceneShadow,
7820
+ updateSceneStack,
7821
+ updateSceneStroke,
7822
+ updateSceneText,
6796
7823
  updateStaticProperty,
6797
7824
  updateTimeline,
6798
7825
  updateTrack,
6799
7826
  updateTrackMatte,
6800
7827
  upsertKeyframe,
7828
+ validateEffectDefinition,
7829
+ validateEffectDefinitionStrict,
7830
+ validateTextEffectDefinition,
7831
+ validateTextEffectDefinitionStrict,
6801
7832
  waitForFontsReady,
6802
7833
  wrapTextToWidth
6803
7834
  });