@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.js CHANGED
@@ -1,3 +1,171 @@
1
+ // src/validation.ts
2
+ import { z } from "zod";
3
+ var GradientStopSchema = z.object({
4
+ color: z.string(),
5
+ offset: z.number().min(0).max(100)
6
+ });
7
+ var EffectFillSchema = z.object({
8
+ type: z.enum(["solid", "linear", "radial", "pattern", "none"]),
9
+ color: z.string().optional(),
10
+ gradient: z.object({
11
+ angle: z.number(),
12
+ stops: z.array(GradientStopSchema)
13
+ }).optional(),
14
+ patternType: z.string().optional(),
15
+ perCharFillEnabled: z.boolean().optional(),
16
+ charFillColors: z.array(z.string()).optional()
17
+ });
18
+ var EffectStrokeSchema = z.object({
19
+ color: z.string(),
20
+ width: z.number().min(0),
21
+ position: z.enum(["outside", "center", "inside"]).optional(),
22
+ opacity: z.number().min(0).max(100).optional(),
23
+ lineJoin: z.enum(["round", "miter", "bevel"]).optional(),
24
+ blur: z.number().min(0).optional(),
25
+ type: z.enum(["solid", "gradient"]).optional(),
26
+ colorSecondary: z.string().optional(),
27
+ widthSecondary: z.number().min(0).optional(),
28
+ fadeRange: z.tuple([z.number(), z.number()]).optional()
29
+ });
30
+ var EffectShadowSchema = z.object({
31
+ type: z.enum(["drop", "inner"]).optional(),
32
+ color: z.string(),
33
+ blur: z.number().min(0),
34
+ offset: z.object({
35
+ x: z.number(),
36
+ y: z.number()
37
+ }).optional(),
38
+ offsetX: z.number().optional(),
39
+ // Legacy flat format
40
+ offsetY: z.number().optional(),
41
+ // Legacy flat format
42
+ opacity: z.number().min(0).max(100).optional()
43
+ }).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'" });
44
+ var EffectBevelSchema = z.object({
45
+ depth: z.number().min(0),
46
+ highlight: z.string().optional(),
47
+ // Current Studio output
48
+ highlightColor: z.string().optional(),
49
+ // Legacy format
50
+ shadow: z.string().optional(),
51
+ // Current Studio output
52
+ shadowColor: z.string().optional(),
53
+ // Legacy format
54
+ direction: z.enum(["bottom-right", "bottom", "right"]).optional(),
55
+ coreColor: z.string().optional(),
56
+ edgeColor: z.string().optional(),
57
+ edgeWidth: z.number().min(0).optional(),
58
+ blur: z.number().min(0).optional(),
59
+ blurColor: z.string().optional(),
60
+ perspectiveEnabled: z.boolean().optional(),
61
+ vanishingPointX: z.number().optional(),
62
+ vanishingPointY: z.number().optional(),
63
+ focalLength: z.number().optional()
64
+ }).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'" });
65
+ var EffectGlowSchema = z.object({
66
+ color: z.string(),
67
+ blur: z.number().min(0),
68
+ opacity: z.number().min(0).max(100),
69
+ type: z.enum(["outer", "inner"]).optional(),
70
+ strength: z.number().min(0).optional(),
71
+ spread: z.number().min(0).optional()
72
+ });
73
+ var EffectPanelSchema = z.object({
74
+ color: z.string(),
75
+ opacity: z.number().min(0).max(100),
76
+ radius: z.number().min(0),
77
+ padding: z.object({
78
+ x: z.number().min(0),
79
+ y: z.number().min(0)
80
+ }).optional(),
81
+ paddingX: z.number().min(0).optional(),
82
+ // Legacy flat format
83
+ paddingY: z.number().min(0).optional(),
84
+ // Legacy flat format
85
+ stroke: z.object({
86
+ color: z.string(),
87
+ width: z.number().min(0)
88
+ }).nullable().optional()
89
+ }).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'" });
90
+ var EffectStackSchema = z.object({
91
+ count: z.number().int().min(1).max(100),
92
+ offsetX: z.number(),
93
+ offsetY: z.number(),
94
+ opacityDecay: z.number().min(0).max(1),
95
+ color1: z.string().optional(),
96
+ color2: z.string().optional(),
97
+ color3: z.string().optional(),
98
+ color4: z.string().optional()
99
+ });
100
+ var FontSchema = z.object({
101
+ family: z.string().min(1),
102
+ weight: z.number().int().min(100).max(900),
103
+ style: z.enum(["normal", "italic"]),
104
+ letterSpacing: z.number(),
105
+ lineHeight: z.number().positive()
106
+ });
107
+ var AnimationSchema = z.object({
108
+ type: z.enum(["none", "typewriter", "wave", "fade", "glitch"]),
109
+ speed: z.number().positive().optional(),
110
+ amplitude: z.number().optional(),
111
+ frequency: z.number().positive().optional()
112
+ });
113
+ var EffectIndexItemSchema = z.object({
114
+ id: z.string().min(1),
115
+ name: z.string().min(1),
116
+ category: z.string().min(1),
117
+ description: z.string().optional(),
118
+ tags: z.array(z.string()).optional(),
119
+ isPremium: z.boolean().optional(),
120
+ previewType: z.enum(["static", "video", "lottie"]).optional(),
121
+ thumbnailUrl: z.string().url().optional(),
122
+ thumbnail: z.string().optional(),
123
+ previewUrl: z.string().url().optional(),
124
+ durationMs: z.number().positive().optional()
125
+ });
126
+ var EffectFullDefinitionSchema = EffectIndexItemSchema.extend({
127
+ version: z.string().optional(),
128
+ description: z.string(),
129
+ tags: z.array(z.string()),
130
+ font: FontSchema,
131
+ fills: z.array(EffectFillSchema),
132
+ strokes: z.array(EffectStrokeSchema),
133
+ shadows: z.array(EffectShadowSchema),
134
+ bevel: EffectBevelSchema.optional(),
135
+ glow: EffectGlowSchema.optional(),
136
+ // Legacy single glow
137
+ glows: z.array(EffectGlowSchema).optional(),
138
+ // Current multi-layer glows
139
+ panel: EffectPanelSchema.optional(),
140
+ glitch: z.any().optional(),
141
+ // TODO: Define proper schema when glitch effects are implemented
142
+ animation: AnimationSchema.optional(),
143
+ background: z.any().optional(),
144
+ // DEPRECATED: kept for backward compatibility
145
+ stack: EffectStackSchema.optional()
146
+ });
147
+ var TextEffectDefinitionSchema = EffectFullDefinitionSchema.extend({
148
+ text: z.string().optional()
149
+ });
150
+ function validateEffectDefinition(data) {
151
+ return EffectFullDefinitionSchema.safeParse(data);
152
+ }
153
+ function validateEffectDefinitionStrict(data) {
154
+ return EffectFullDefinitionSchema.parse(data);
155
+ }
156
+ function validateTextEffectDefinition(data) {
157
+ return TextEffectDefinitionSchema.safeParse(data);
158
+ }
159
+ function validateTextEffectDefinitionStrict(data) {
160
+ return TextEffectDefinitionSchema.parse(data);
161
+ }
162
+ function formatValidationErrors(error) {
163
+ return error.issues.map((err) => {
164
+ const path = err.path.join(".");
165
+ return `${path ? `${path}: ` : ""}${err.message}`;
166
+ });
167
+ }
168
+
1
169
  // src/engine/schema.ts
2
170
  var SCENE_VERSION = 1;
3
171
  var DEFAULT_CANVAS_WIDTH = 800;
@@ -3029,16 +3197,20 @@ function _buildConfig(effect, text, fontSize, canvasWidth, canvasHeight, time, c
3029
3197
  if (shadow) {
3030
3198
  if (shadow.color !== void 0) config.shadowColor = shadow.color;
3031
3199
  if (shadow.blur !== void 0) config.shadowBlur = shadow.blur * ratio;
3032
- if (shadow.offsetX !== void 0) config.shadowOffsetX = shadow.offsetX * ratio;
3033
- if (shadow.offsetY !== void 0) config.shadowOffsetY = shadow.offsetY * ratio;
3200
+ if (shadow.offset?.x !== void 0) config.shadowOffsetX = shadow.offset.x * ratio;
3201
+ else if (shadow.offsetX !== void 0) config.shadowOffsetX = shadow.offsetX * ratio;
3202
+ if (shadow.offset?.y !== void 0) config.shadowOffsetY = shadow.offset.y * ratio;
3203
+ else if (shadow.offsetY !== void 0) config.shadowOffsetY = shadow.offsetY * ratio;
3034
3204
  if (shadow.opacity !== void 0) config.shadowOpacity = shadow.opacity;
3035
3205
  if (shadow.type !== void 0) config.shadowType = shadow.type;
3036
3206
  }
3037
3207
  config.bevelEnabled = !!bevel;
3038
3208
  if (bevel) {
3039
3209
  if (bevel.depth !== void 0) config.bevelDepth = Math.round(bevel.depth * ratio);
3040
- if (bevel.highlightColor !== void 0) config.bevelHighlight = bevel.highlightColor;
3041
- if (bevel.shadowColor !== void 0) config.bevelShadow = bevel.shadowColor;
3210
+ if (bevel.highlight !== void 0) config.bevelHighlight = bevel.highlight;
3211
+ else if (bevel.highlightColor !== void 0) config.bevelHighlight = bevel.highlightColor;
3212
+ if (bevel.shadow !== void 0) config.bevelShadow = bevel.shadow;
3213
+ else if (bevel.shadowColor !== void 0) config.bevelShadow = bevel.shadowColor;
3042
3214
  if (bevel.direction !== void 0) config.bevelDirection = bevel.direction;
3043
3215
  if (bevel.coreColor !== void 0) config.bevelCoreColor = bevel.coreColor;
3044
3216
  if (bevel.edgeColor !== void 0) config.bevelEdgeColor = bevel.edgeColor;
@@ -3066,8 +3238,10 @@ function _buildConfig(effect, text, fontSize, canvasWidth, canvasHeight, time, c
3066
3238
  if (panel.color !== void 0) config.panelColor = panel.color;
3067
3239
  if (panel.opacity !== void 0) config.panelOpacity = panel.opacity;
3068
3240
  if (panel.radius !== void 0) config.panelRadius = panel.radius;
3069
- if (panel.paddingX !== void 0) config.panelPaddingX = panel.paddingX * ratio;
3070
- if (panel.paddingY !== void 0) config.panelPaddingY = panel.paddingY * ratio;
3241
+ if (panel.padding?.x !== void 0) config.panelPaddingX = panel.padding.x * ratio;
3242
+ else if (panel.paddingX !== void 0) config.panelPaddingX = panel.paddingX * ratio;
3243
+ if (panel.padding?.y !== void 0) config.panelPaddingY = panel.padding.y * ratio;
3244
+ else if (panel.paddingY !== void 0) config.panelPaddingY = panel.paddingY * ratio;
3071
3245
  if (panel.stroke !== void 0) {
3072
3246
  config.panelStrokeEnabled = !!panel.stroke;
3073
3247
  if (panel.stroke.color !== void 0) config.panelStrokeColor = panel.stroke.color;
@@ -3088,23 +3262,7 @@ function _buildConfig(effect, text, fontSize, canvasWidth, canvasHeight, time, c
3088
3262
  return mappedGlow;
3089
3263
  });
3090
3264
  }
3091
- const standardKeys = /* @__PURE__ */ new Set([
3092
- "id",
3093
- "name",
3094
- "category",
3095
- "description",
3096
- "tags",
3097
- "font",
3098
- "fills",
3099
- "strokes",
3100
- "shadows",
3101
- "glows",
3102
- "bevel",
3103
- "panel",
3104
- "text",
3105
- "animation",
3106
- "stack"
3107
- ]);
3265
+ const standardKeys = /* @__PURE__ */ new Set(["id", "name", "category", "description", "tags", "font", "fills", "strokes", "shadows", "glows", "bevel", "panel", "text", "animation", "stack"]);
3108
3266
  for (const key of Object.keys(effect)) {
3109
3267
  if (!standardKeys.has(key)) {
3110
3268
  config[key] = effect[key];
@@ -4157,8 +4315,8 @@ function applyToLayerTransform(layer2, override) {
4157
4315
  ks.s.k = [override.scaleX, override.scaleY, 100];
4158
4316
  }
4159
4317
  if (override.posX !== void 0 && override.posY !== void 0 && ks.p?.a === 0) {
4160
- const z = Array.isArray(ks.p.k) ? ks.p.k[2] ?? 0 : 0;
4161
- ks.p.k = [override.posX, override.posY, z];
4318
+ const z2 = Array.isArray(ks.p.k) ? ks.p.k[2] ?? 0 : 0;
4319
+ ks.p.k = [override.posX, override.posY, z2];
4162
4320
  }
4163
4321
  }
4164
4322
  function mutateTextLayer(layer2, override) {
@@ -6442,7 +6600,823 @@ function duplicateTrackAtPlayhead(doc, trackIndex, previewTime) {
6442
6600
  const value = layer2 ? readLayerScalar(layer2, track.paramPath) : 0;
6443
6601
  return addKeyframeAtTime(doc, trackIndex, previewTime, value);
6444
6602
  }
6603
+
6604
+ // src/engine/api.ts
6605
+ function updateSceneText(doc, patch) {
6606
+ const nextText = { ...doc.text };
6607
+ if (patch.content !== void 0) nextText.content = patch.content;
6608
+ if (patch.fontFamily !== void 0) nextText.fontFamily = patch.fontFamily;
6609
+ if (patch.fontWeight !== void 0) nextText.fontWeight = patch.fontWeight;
6610
+ if (patch.fontStyle !== void 0) nextText.fontStyle = patch.fontStyle;
6611
+ if (patch.fontSize !== void 0) nextText.fontSize = patch.fontSize;
6612
+ if (patch.letterSpacing !== void 0) nextText.letterSpacing = patch.letterSpacing;
6613
+ if (patch.lineHeight !== void 0) nextText.lineHeight = patch.lineHeight;
6614
+ if (patch.textPosX !== void 0) nextText.textPosX = patch.textPosX;
6615
+ if (patch.textPosY !== void 0) nextText.textPosY = patch.textPosY;
6616
+ if (patch.wrapText !== void 0) nextText.wrapText = patch.wrapText;
6617
+ if (patch.autoFitText !== void 0) nextText.autoFitText = patch.autoFitText;
6618
+ if (patch.perCharFillEnabled !== void 0) nextText.perCharFillEnabled = patch.perCharFillEnabled;
6619
+ if (patch.charFillColors !== void 0) nextText.charFillColors = patch.charFillColors;
6620
+ const nextLegacyConfig = doc.legacyConfig ? { ...doc.legacyConfig } : void 0;
6621
+ if (nextLegacyConfig) {
6622
+ if (patch.content !== void 0) nextLegacyConfig.text = patch.content;
6623
+ if (patch.fontFamily !== void 0) nextLegacyConfig.fontFamily = patch.fontFamily;
6624
+ if (patch.fontWeight !== void 0) nextLegacyConfig.fontWeight = patch.fontWeight;
6625
+ if (patch.fontStyle !== void 0) nextLegacyConfig.fontStyle = patch.fontStyle;
6626
+ if (patch.fontSize !== void 0) nextLegacyConfig.fontSize = patch.fontSize;
6627
+ if (patch.letterSpacing !== void 0) nextLegacyConfig.letterSpacing = patch.letterSpacing;
6628
+ if (patch.lineHeight !== void 0) nextLegacyConfig.lineHeight = patch.lineHeight;
6629
+ if (patch.textPosX !== void 0) nextLegacyConfig.textPosX = patch.textPosX;
6630
+ if (patch.textPosY !== void 0) nextLegacyConfig.textPosY = patch.textPosY;
6631
+ if (patch.wrapText !== void 0) nextLegacyConfig.wrapText = patch.wrapText;
6632
+ if (patch.autoFitText !== void 0) nextLegacyConfig.autoFitText = patch.autoFitText;
6633
+ if (patch.perCharFillEnabled !== void 0) nextLegacyConfig.perCharFillEnabled = patch.perCharFillEnabled;
6634
+ if (patch.charFillColors !== void 0) nextLegacyConfig.charFillColors = patch.charFillColors;
6635
+ }
6636
+ return {
6637
+ ...doc,
6638
+ text: nextText,
6639
+ legacyConfig: nextLegacyConfig
6640
+ };
6641
+ }
6642
+ function updateScenePanel(doc, patch) {
6643
+ let panelFound = false;
6644
+ const nextLayers = doc.effectLayers.map((layer2) => {
6645
+ if (layer2.type === "panel") {
6646
+ panelFound = true;
6647
+ const nextParams = { ...layer2.params };
6648
+ if (patch.color !== void 0) nextParams.panelColor = patch.color;
6649
+ if (patch.opacity !== void 0) nextParams.panelOpacity = patch.opacity;
6650
+ if (patch.radius !== void 0) nextParams.panelRadius = patch.radius;
6651
+ if (patch.paddingX !== void 0) nextParams.panelPaddingX = patch.paddingX;
6652
+ if (patch.paddingY !== void 0) nextParams.panelPaddingY = patch.paddingY;
6653
+ if (patch.strokeEnabled !== void 0) nextParams.panelStrokeEnabled = patch.strokeEnabled;
6654
+ if (patch.strokeColor !== void 0) nextParams.panelStrokeColor = patch.strokeColor;
6655
+ if (patch.strokeWidth !== void 0) nextParams.panelStrokeWidth = patch.strokeWidth;
6656
+ const enabled = patch.enabled !== void 0 ? patch.enabled : layer2.enabled;
6657
+ if (patch.enabled !== void 0) {
6658
+ nextParams.panelEnabled = patch.enabled;
6659
+ }
6660
+ return {
6661
+ ...layer2,
6662
+ enabled,
6663
+ params: nextParams
6664
+ };
6665
+ }
6666
+ return layer2;
6667
+ });
6668
+ const layers = [...nextLayers];
6669
+ if (!panelFound) {
6670
+ const defaultParams = {
6671
+ panelEnabled: patch.enabled ?? true,
6672
+ panelColor: patch.color ?? "#1E1E26",
6673
+ panelOpacity: patch.opacity ?? 80,
6674
+ panelRadius: patch.radius ?? 12,
6675
+ panelPaddingX: patch.paddingX ?? 40,
6676
+ panelPaddingY: patch.paddingY ?? 20,
6677
+ panelStrokeEnabled: patch.strokeEnabled ?? false,
6678
+ panelStrokeColor: patch.strokeColor ?? "#2A2A38",
6679
+ panelStrokeWidth: patch.strokeWidth ?? 2
6680
+ };
6681
+ const newL = {
6682
+ id: newLayerId(),
6683
+ type: "panel",
6684
+ name: "Background Panel",
6685
+ enabled: patch.enabled ?? true,
6686
+ opacity: 1,
6687
+ blendMode: "source-over",
6688
+ target: "scene",
6689
+ params: defaultParams
6690
+ };
6691
+ layers.unshift(newL);
6692
+ }
6693
+ const nextLegacyConfig = doc.legacyConfig ? { ...doc.legacyConfig } : void 0;
6694
+ if (nextLegacyConfig) {
6695
+ if (patch.enabled !== void 0) nextLegacyConfig.panelEnabled = patch.enabled;
6696
+ if (patch.color !== void 0) nextLegacyConfig.panelColor = patch.color;
6697
+ if (patch.opacity !== void 0) nextLegacyConfig.panelOpacity = patch.opacity;
6698
+ if (patch.radius !== void 0) nextLegacyConfig.panelRadius = patch.radius;
6699
+ if (patch.paddingX !== void 0) nextLegacyConfig.panelPaddingX = patch.paddingX;
6700
+ if (patch.paddingY !== void 0) nextLegacyConfig.panelPaddingY = patch.paddingY;
6701
+ if (patch.strokeEnabled !== void 0) nextLegacyConfig.panelStrokeEnabled = patch.strokeEnabled;
6702
+ if (patch.strokeColor !== void 0) nextLegacyConfig.panelStrokeColor = patch.strokeColor;
6703
+ if (patch.strokeWidth !== void 0) nextLegacyConfig.panelStrokeWidth = patch.strokeWidth;
6704
+ }
6705
+ return {
6706
+ ...doc,
6707
+ effectLayers: layers,
6708
+ legacyConfig: nextLegacyConfig
6709
+ };
6710
+ }
6711
+ function updateSceneStroke(doc, patch) {
6712
+ let found = false;
6713
+ const nextLayers = doc.effectLayers.map((layer2) => {
6714
+ if (layer2.type === "stroke") {
6715
+ found = true;
6716
+ const nextParams = { ...layer2.params };
6717
+ if (patch.strokeColor !== void 0) nextParams.strokeColor = patch.strokeColor;
6718
+ if (patch.strokeWidth !== void 0) nextParams.strokeWidth = patch.strokeWidth;
6719
+ if (patch.strokePosition !== void 0) nextParams.strokePosition = patch.strokePosition;
6720
+ if (patch.strokeOpacity !== void 0) nextParams.strokeOpacity = patch.strokeOpacity;
6721
+ if (patch.strokeLineJoin !== void 0) nextParams.strokeLineJoin = patch.strokeLineJoin;
6722
+ if (patch.strokeBlur !== void 0) nextParams.strokeBlur = patch.strokeBlur;
6723
+ if (patch.strokeType !== void 0) nextParams.strokeType = patch.strokeType;
6724
+ if (patch.strokeColorSecondary !== void 0) nextParams.strokeColorSecondary = patch.strokeColorSecondary;
6725
+ if (patch.strokeWidthSecondary !== void 0) nextParams.strokeWidthSecondary = patch.strokeWidthSecondary;
6726
+ if (patch.strokeFadeRange !== void 0) nextParams.strokeFadeRange = patch.strokeFadeRange;
6727
+ const enabled = patch.enabled !== void 0 ? patch.enabled : layer2.enabled;
6728
+ if (patch.enabled !== void 0) {
6729
+ nextParams.strokeEnabled = patch.enabled;
6730
+ }
6731
+ return {
6732
+ ...layer2,
6733
+ enabled,
6734
+ params: nextParams
6735
+ };
6736
+ }
6737
+ return layer2;
6738
+ });
6739
+ const layers = [...nextLayers];
6740
+ if (!found) {
6741
+ const defaultParams = {
6742
+ strokeEnabled: patch.enabled ?? true,
6743
+ strokeColor: patch.strokeColor ?? "#7C6FFF",
6744
+ strokeWidth: patch.strokeWidth ?? 4,
6745
+ strokePosition: patch.strokePosition ?? "outside",
6746
+ strokeOpacity: patch.strokeOpacity ?? 100,
6747
+ strokeLineJoin: patch.strokeLineJoin ?? "round",
6748
+ strokeBlur: patch.strokeBlur ?? 0,
6749
+ strokeType: patch.strokeType ?? "single",
6750
+ strokeColorSecondary: patch.strokeColorSecondary ?? "#FFFFFF",
6751
+ strokeWidthSecondary: patch.strokeWidthSecondary ?? 4,
6752
+ strokeFadeRange: patch.strokeFadeRange ?? 0
6753
+ };
6754
+ const newL = {
6755
+ id: newLayerId(),
6756
+ type: "stroke",
6757
+ name: "Stroke",
6758
+ enabled: patch.enabled ?? true,
6759
+ opacity: 1,
6760
+ blendMode: "source-over",
6761
+ target: "text",
6762
+ params: defaultParams
6763
+ };
6764
+ const fillIdx = layers.findIndex((l) => l.type === "fill");
6765
+ if (fillIdx >= 0) {
6766
+ layers.splice(fillIdx, 0, newL);
6767
+ } else {
6768
+ const maskIdx = layers.findIndex((l) => l.type === "mask" || l.type === "filter");
6769
+ if (maskIdx >= 0) {
6770
+ layers.splice(maskIdx, 0, newL);
6771
+ } else {
6772
+ layers.push(newL);
6773
+ }
6774
+ }
6775
+ }
6776
+ const nextLegacyConfig = doc.legacyConfig ? { ...doc.legacyConfig } : void 0;
6777
+ if (nextLegacyConfig) {
6778
+ if (patch.enabled !== void 0) nextLegacyConfig.strokeEnabled = patch.enabled;
6779
+ if (patch.strokeColor !== void 0) nextLegacyConfig.strokeColor = patch.strokeColor;
6780
+ if (patch.strokeWidth !== void 0) nextLegacyConfig.strokeWidth = patch.strokeWidth;
6781
+ if (patch.strokePosition !== void 0) nextLegacyConfig.strokePosition = patch.strokePosition;
6782
+ if (patch.strokeOpacity !== void 0) nextLegacyConfig.strokeOpacity = patch.strokeOpacity;
6783
+ if (patch.strokeLineJoin !== void 0) nextLegacyConfig.strokeLineJoin = patch.strokeLineJoin;
6784
+ if (patch.strokeBlur !== void 0) nextLegacyConfig.strokeBlur = patch.strokeBlur;
6785
+ if (patch.strokeType !== void 0) nextLegacyConfig.strokeType = patch.strokeType;
6786
+ if (patch.strokeColorSecondary !== void 0) nextLegacyConfig.strokeColorSecondary = patch.strokeColorSecondary;
6787
+ if (patch.strokeWidthSecondary !== void 0) nextLegacyConfig.strokeWidthSecondary = patch.strokeWidthSecondary;
6788
+ if (patch.strokeFadeRange !== void 0) nextLegacyConfig.strokeFadeRange = patch.strokeFadeRange;
6789
+ }
6790
+ return {
6791
+ ...doc,
6792
+ effectLayers: layers,
6793
+ legacyConfig: nextLegacyConfig
6794
+ };
6795
+ }
6796
+ function updateSceneShadow(doc, patch) {
6797
+ let found = false;
6798
+ const nextLayers = doc.effectLayers.map((layer2) => {
6799
+ if (layer2.type === "shadow") {
6800
+ found = true;
6801
+ const nextParams = { ...layer2.params };
6802
+ if (patch.shadowColor !== void 0) nextParams.shadowColor = patch.shadowColor;
6803
+ if (patch.shadowBlur !== void 0) nextParams.shadowBlur = patch.shadowBlur;
6804
+ if (patch.shadowOffsetX !== void 0) nextParams.shadowOffsetX = patch.shadowOffsetX;
6805
+ if (patch.shadowOffsetY !== void 0) nextParams.shadowOffsetY = patch.shadowOffsetY;
6806
+ if (patch.shadowOpacity !== void 0) nextParams.shadowOpacity = patch.shadowOpacity;
6807
+ if (patch.shadowType !== void 0) nextParams.shadowType = patch.shadowType;
6808
+ const enabled = patch.enabled !== void 0 ? patch.enabled : layer2.enabled;
6809
+ if (patch.enabled !== void 0) {
6810
+ nextParams.shadowEnabled = patch.enabled;
6811
+ }
6812
+ return {
6813
+ ...layer2,
6814
+ enabled,
6815
+ params: nextParams
6816
+ };
6817
+ }
6818
+ return layer2;
6819
+ });
6820
+ const layers = [...nextLayers];
6821
+ if (!found) {
6822
+ const defaultParams = {
6823
+ shadowEnabled: patch.enabled ?? true,
6824
+ shadowColor: patch.shadowColor ?? "#000000",
6825
+ shadowBlur: patch.shadowBlur ?? 10,
6826
+ shadowOffsetX: patch.shadowOffsetX ?? 5,
6827
+ shadowOffsetY: patch.shadowOffsetY ?? 5,
6828
+ shadowOpacity: patch.shadowOpacity ?? 80,
6829
+ shadowType: patch.shadowType ?? "drop"
6830
+ };
6831
+ const newL = {
6832
+ id: newLayerId(),
6833
+ type: "shadow",
6834
+ name: "Shadow",
6835
+ enabled: patch.enabled ?? true,
6836
+ opacity: 1,
6837
+ blendMode: "source-over",
6838
+ target: "text",
6839
+ params: defaultParams
6840
+ };
6841
+ const panelIdx = layers.findIndex((l) => l.type === "panel");
6842
+ if (panelIdx >= 0) {
6843
+ layers.splice(panelIdx + 1, 0, newL);
6844
+ } else {
6845
+ layers.unshift(newL);
6846
+ }
6847
+ }
6848
+ const nextLegacyConfig = doc.legacyConfig ? { ...doc.legacyConfig } : void 0;
6849
+ if (nextLegacyConfig) {
6850
+ if (patch.enabled !== void 0) nextLegacyConfig.shadowEnabled = patch.enabled;
6851
+ if (patch.shadowColor !== void 0) nextLegacyConfig.shadowColor = patch.shadowColor;
6852
+ if (patch.shadowBlur !== void 0) nextLegacyConfig.shadowBlur = patch.shadowBlur;
6853
+ if (patch.shadowOffsetX !== void 0) nextLegacyConfig.shadowOffsetX = patch.shadowOffsetX;
6854
+ if (patch.shadowOffsetY !== void 0) nextLegacyConfig.shadowOffsetY = patch.shadowOffsetY;
6855
+ if (patch.shadowOpacity !== void 0) nextLegacyConfig.shadowOpacity = patch.shadowOpacity;
6856
+ if (patch.shadowType !== void 0) nextLegacyConfig.shadowType = patch.shadowType;
6857
+ }
6858
+ return {
6859
+ ...doc,
6860
+ effectLayers: layers,
6861
+ legacyConfig: nextLegacyConfig
6862
+ };
6863
+ }
6864
+ function updateSceneBevel(doc, patch) {
6865
+ let found = false;
6866
+ const nextLayers = doc.effectLayers.map((layer2) => {
6867
+ if (layer2.type === "extrusion") {
6868
+ found = true;
6869
+ const nextParams = { ...layer2.params };
6870
+ if (patch.bevelDepth !== void 0) nextParams.bevelDepth = patch.bevelDepth;
6871
+ if (patch.bevelHighlight !== void 0) nextParams.bevelHighlight = patch.bevelHighlight;
6872
+ if (patch.bevelShadow !== void 0) nextParams.bevelShadow = patch.bevelShadow;
6873
+ if (patch.bevelDirection !== void 0) nextParams.bevelDirection = patch.bevelDirection;
6874
+ if (patch.bevelCoreColor !== void 0) nextParams.bevelCoreColor = patch.bevelCoreColor;
6875
+ if (patch.bevelEdgeColor !== void 0) nextParams.bevelEdgeColor = patch.bevelEdgeColor;
6876
+ if (patch.bevelEdgeWidth !== void 0) nextParams.bevelEdgeWidth = patch.bevelEdgeWidth;
6877
+ if (patch.bevelBlur !== void 0) nextParams.bevelBlur = patch.bevelBlur;
6878
+ if (patch.bevelBlurColor !== void 0) nextParams.bevelBlurColor = patch.bevelBlurColor;
6879
+ if (patch.bevelPerspectiveEnabled !== void 0) nextParams.bevelPerspectiveEnabled = patch.bevelPerspectiveEnabled;
6880
+ if (patch.bevelVanishingPointX !== void 0) nextParams.bevelVanishingPointX = patch.bevelVanishingPointX;
6881
+ if (patch.bevelVanishingPointY !== void 0) nextParams.bevelVanishingPointY = patch.bevelVanishingPointY;
6882
+ if (patch.bevelFocalLength !== void 0) nextParams.bevelFocalLength = patch.bevelFocalLength;
6883
+ const enabled = patch.enabled !== void 0 ? patch.enabled : layer2.enabled;
6884
+ if (patch.enabled !== void 0) {
6885
+ nextParams.bevelEnabled = patch.enabled;
6886
+ }
6887
+ return {
6888
+ ...layer2,
6889
+ enabled,
6890
+ params: nextParams
6891
+ };
6892
+ }
6893
+ return layer2;
6894
+ });
6895
+ const layers = [...nextLayers];
6896
+ if (!found) {
6897
+ const defaultParams = {
6898
+ bevelEnabled: patch.enabled ?? true,
6899
+ bevelDepth: patch.bevelDepth ?? 5,
6900
+ bevelHighlight: patch.bevelHighlight ?? "#FFFFFF",
6901
+ bevelShadow: patch.bevelShadow ?? "#000000",
6902
+ bevelDirection: patch.bevelDirection ?? "bottom-right",
6903
+ bevelCoreColor: patch.bevelCoreColor ?? "#000000",
6904
+ bevelEdgeColor: patch.bevelEdgeColor ?? "#2A2A38",
6905
+ bevelEdgeWidth: patch.bevelEdgeWidth ?? 0,
6906
+ bevelBlur: patch.bevelBlur ?? 0,
6907
+ bevelBlurColor: patch.bevelBlurColor ?? "#000000",
6908
+ bevelPerspectiveEnabled: patch.bevelPerspectiveEnabled ?? false,
6909
+ bevelVanishingPointX: patch.bevelVanishingPointX ?? 40,
6910
+ bevelVanishingPointY: patch.bevelVanishingPointY ?? 80,
6911
+ bevelFocalLength: patch.bevelFocalLength ?? 400
6912
+ };
6913
+ const newL = {
6914
+ id: newLayerId(),
6915
+ type: "extrusion",
6916
+ name: "Bevel / Extrusion",
6917
+ enabled: patch.enabled ?? true,
6918
+ opacity: 1,
6919
+ blendMode: "source-over",
6920
+ target: "text",
6921
+ params: defaultParams
6922
+ };
6923
+ const stackIdx = layers.findIndex((l) => l.type === "duplicateStack");
6924
+ if (stackIdx >= 0) {
6925
+ layers.splice(stackIdx, 0, newL);
6926
+ } else {
6927
+ const strokeIdx = layers.findIndex((l) => l.type === "stroke");
6928
+ if (strokeIdx >= 0) {
6929
+ layers.splice(strokeIdx, 0, newL);
6930
+ } else {
6931
+ const maskIdx = layers.findIndex((l) => l.type === "mask" || l.type === "filter");
6932
+ if (maskIdx >= 0) {
6933
+ layers.splice(maskIdx, 0, newL);
6934
+ } else {
6935
+ layers.push(newL);
6936
+ }
6937
+ }
6938
+ }
6939
+ }
6940
+ const nextLegacyConfig = doc.legacyConfig ? { ...doc.legacyConfig } : void 0;
6941
+ if (nextLegacyConfig) {
6942
+ if (patch.enabled !== void 0) nextLegacyConfig.bevelEnabled = patch.enabled;
6943
+ if (patch.bevelDepth !== void 0) nextLegacyConfig.bevelDepth = patch.bevelDepth;
6944
+ if (patch.bevelHighlight !== void 0) nextLegacyConfig.bevelHighlight = patch.bevelHighlight;
6945
+ if (patch.bevelShadow !== void 0) nextLegacyConfig.bevelShadow = patch.bevelShadow;
6946
+ if (patch.bevelDirection !== void 0) nextLegacyConfig.bevelDirection = patch.bevelDirection;
6947
+ if (patch.bevelCoreColor !== void 0) nextLegacyConfig.bevelCoreColor = patch.bevelCoreColor;
6948
+ if (patch.bevelEdgeColor !== void 0) nextLegacyConfig.bevelEdgeColor = patch.bevelEdgeColor;
6949
+ if (patch.bevelEdgeWidth !== void 0) nextLegacyConfig.bevelEdgeWidth = patch.bevelEdgeWidth;
6950
+ if (patch.bevelBlur !== void 0) nextLegacyConfig.bevelBlur = patch.bevelBlur;
6951
+ if (patch.bevelBlurColor !== void 0) nextLegacyConfig.bevelBlurColor = patch.bevelBlurColor;
6952
+ if (patch.bevelPerspectiveEnabled !== void 0) nextLegacyConfig.bevelPerspectiveEnabled = patch.bevelPerspectiveEnabled;
6953
+ if (patch.bevelVanishingPointX !== void 0) nextLegacyConfig.bevelVanishingPointX = patch.bevelVanishingPointX;
6954
+ if (patch.bevelVanishingPointY !== void 0) nextLegacyConfig.bevelVanishingPointY = patch.bevelVanishingPointY;
6955
+ if (patch.bevelFocalLength !== void 0) nextLegacyConfig.bevelFocalLength = patch.bevelFocalLength;
6956
+ }
6957
+ return {
6958
+ ...doc,
6959
+ effectLayers: layers,
6960
+ legacyConfig: nextLegacyConfig
6961
+ };
6962
+ }
6963
+ function updateSceneStack(doc, patch) {
6964
+ let found = false;
6965
+ const nextLayers = doc.effectLayers.map((layer2) => {
6966
+ if (layer2.type === "duplicateStack") {
6967
+ found = true;
6968
+ const nextParams = { ...layer2.params };
6969
+ if (patch.stackCount !== void 0) nextParams.stackCount = patch.stackCount;
6970
+ if (patch.stackOffsetX !== void 0) nextParams.stackOffsetX = patch.stackOffsetX;
6971
+ if (patch.stackOffsetY !== void 0) nextParams.stackOffsetY = patch.stackOffsetY;
6972
+ if (patch.stackOpacityDecay !== void 0) nextParams.stackOpacityDecay = patch.stackOpacityDecay;
6973
+ if (patch.stackColor1 !== void 0) nextParams.stackColor1 = patch.stackColor1;
6974
+ if (patch.stackColor2 !== void 0) nextParams.stackColor2 = patch.stackColor2;
6975
+ if (patch.stackColor3 !== void 0) nextParams.stackColor3 = patch.stackColor3;
6976
+ if (patch.stackColor4 !== void 0) nextParams.stackColor4 = patch.stackColor4;
6977
+ const enabled = patch.enabled !== void 0 ? patch.enabled : layer2.enabled;
6978
+ if (patch.enabled !== void 0) {
6979
+ nextParams.stackEnabled = patch.enabled;
6980
+ }
6981
+ return {
6982
+ ...layer2,
6983
+ enabled,
6984
+ params: nextParams
6985
+ };
6986
+ }
6987
+ return layer2;
6988
+ });
6989
+ const layers = [...nextLayers];
6990
+ if (!found) {
6991
+ const defaultParams = {
6992
+ stackEnabled: patch.enabled ?? true,
6993
+ stackCount: patch.stackCount ?? 3,
6994
+ stackOffsetX: patch.stackOffsetX ?? 10,
6995
+ stackOffsetY: patch.stackOffsetY ?? -10,
6996
+ stackOpacityDecay: patch.stackOpacityDecay ?? 20,
6997
+ stackColor1: patch.stackColor1 ?? "#FF7C00",
6998
+ stackColor2: patch.stackColor2 ?? "#00FFDD",
6999
+ stackColor3: patch.stackColor3 ?? "#FF00AA",
7000
+ stackColor4: patch.stackColor4 ?? "#AA00FF"
7001
+ };
7002
+ const newL = {
7003
+ id: newLayerId(),
7004
+ type: "duplicateStack",
7005
+ name: "Stack Extrusion",
7006
+ enabled: patch.enabled ?? true,
7007
+ opacity: 1,
7008
+ blendMode: "source-over",
7009
+ target: "text",
7010
+ params: defaultParams
7011
+ };
7012
+ const strokeIdx = layers.findIndex((l) => l.type === "stroke");
7013
+ if (strokeIdx >= 0) {
7014
+ layers.splice(strokeIdx, 0, newL);
7015
+ } else {
7016
+ const maskIdx = layers.findIndex((l) => l.type === "mask" || l.type === "filter");
7017
+ if (maskIdx >= 0) {
7018
+ layers.splice(maskIdx, 0, newL);
7019
+ } else {
7020
+ layers.push(newL);
7021
+ }
7022
+ }
7023
+ }
7024
+ const nextLegacyConfig = doc.legacyConfig ? { ...doc.legacyConfig } : void 0;
7025
+ if (nextLegacyConfig) {
7026
+ if (patch.enabled !== void 0) nextLegacyConfig.stackEnabled = patch.enabled;
7027
+ if (patch.stackCount !== void 0) nextLegacyConfig.stackCount = patch.stackCount;
7028
+ if (patch.stackOffsetX !== void 0) nextLegacyConfig.stackOffsetX = patch.stackOffsetX;
7029
+ if (patch.stackOffsetY !== void 0) nextLegacyConfig.stackOffsetY = patch.stackOffsetY;
7030
+ if (patch.stackOpacityDecay !== void 0) nextLegacyConfig.stackOpacityDecay = patch.stackOpacityDecay;
7031
+ if (patch.stackColor1 !== void 0) nextLegacyConfig.stackColor1 = patch.stackColor1;
7032
+ if (patch.stackColor2 !== void 0) nextLegacyConfig.stackColor2 = patch.stackColor2;
7033
+ if (patch.stackColor3 !== void 0) nextLegacyConfig.stackColor3 = patch.stackColor3;
7034
+ if (patch.stackColor4 !== void 0) nextLegacyConfig.stackColor4 = patch.stackColor4;
7035
+ }
7036
+ return {
7037
+ ...doc,
7038
+ effectLayers: layers,
7039
+ legacyConfig: nextLegacyConfig
7040
+ };
7041
+ }
7042
+ function updateSceneFill(doc, patch) {
7043
+ let found = false;
7044
+ const nextLayers = doc.effectLayers.map((layer2) => {
7045
+ if (layer2.type === "fill") {
7046
+ found = true;
7047
+ const nextParams = { ...layer2.params };
7048
+ if (patch.fillType !== void 0) nextParams.fillType = patch.fillType;
7049
+ if (patch.fillColor !== void 0) nextParams.fillColor = patch.fillColor;
7050
+ if (patch.fillGradientAngle !== void 0) nextParams.fillGradientAngle = patch.fillGradientAngle;
7051
+ if (patch.fillGradientStops !== void 0) nextParams.fillGradientStops = patch.fillGradientStops;
7052
+ if (patch.patternType !== void 0) nextParams.patternType = patch.patternType;
7053
+ if (patch.perCharFillEnabled !== void 0) nextParams.perCharFillEnabled = patch.perCharFillEnabled;
7054
+ if (patch.charFillColors !== void 0) nextParams.charFillColors = patch.charFillColors;
7055
+ const enabled = patch.fillType !== void 0 ? patch.fillType !== "none" : layer2.enabled;
7056
+ return {
7057
+ ...layer2,
7058
+ enabled,
7059
+ params: nextParams
7060
+ };
7061
+ }
7062
+ return layer2;
7063
+ });
7064
+ const layers = [...nextLayers];
7065
+ if (!found) {
7066
+ const defaultParams = {
7067
+ fillType: patch.fillType ?? "solid",
7068
+ fillColor: patch.fillColor ?? "#FFFFFF",
7069
+ fillGradientAngle: patch.fillGradientAngle ?? 90,
7070
+ fillGradientStops: patch.fillGradientStops ?? [
7071
+ { color: "#FFFFFF", offset: 0 },
7072
+ { color: "#E0E0E0", offset: 100 }
7073
+ ],
7074
+ patternType: patch.patternType ?? "chalk",
7075
+ perCharFillEnabled: patch.perCharFillEnabled ?? false,
7076
+ charFillColors: patch.charFillColors ?? []
7077
+ };
7078
+ const newL = {
7079
+ id: newLayerId(),
7080
+ type: "fill",
7081
+ name: "Fill",
7082
+ enabled: patch.fillType !== "none",
7083
+ opacity: 1,
7084
+ blendMode: "source-over",
7085
+ target: "text",
7086
+ params: defaultParams
7087
+ };
7088
+ const maskIdx = layers.findIndex((l) => l.type === "mask" || l.type === "filter");
7089
+ if (maskIdx >= 0) {
7090
+ layers.splice(maskIdx, 0, newL);
7091
+ } else {
7092
+ layers.push(newL);
7093
+ }
7094
+ }
7095
+ const nextLegacyConfig = doc.legacyConfig ? { ...doc.legacyConfig } : void 0;
7096
+ if (nextLegacyConfig) {
7097
+ if (patch.fillType !== void 0) nextLegacyConfig.fillType = patch.fillType;
7098
+ if (patch.fillColor !== void 0) nextLegacyConfig.fillColor = patch.fillColor;
7099
+ if (patch.fillGradientAngle !== void 0) nextLegacyConfig.fillGradientAngle = patch.fillGradientAngle;
7100
+ if (patch.fillGradientStops !== void 0) nextLegacyConfig.fillGradientStops = patch.fillGradientStops;
7101
+ if (patch.patternType !== void 0) nextLegacyConfig.patternType = patch.patternType;
7102
+ if (patch.perCharFillEnabled !== void 0) nextLegacyConfig.perCharFillEnabled = patch.perCharFillEnabled;
7103
+ if (patch.charFillColors !== void 0) nextLegacyConfig.charFillColors = patch.charFillColors;
7104
+ }
7105
+ return {
7106
+ ...doc,
7107
+ effectLayers: layers,
7108
+ legacyConfig: nextLegacyConfig
7109
+ };
7110
+ }
7111
+ function updateSceneGlow(doc, index, patch) {
7112
+ const currentGlowLayers = doc.effectLayers.filter((l) => l.type === "glow");
7113
+ const layers = [...doc.effectLayers];
7114
+ if (index >= currentGlowLayers.length) {
7115
+ const needed = index - currentGlowLayers.length + 1;
7116
+ for (let i = 0; i < needed; i++) {
7117
+ const isTarget = i === needed - 1;
7118
+ const defaultGlow = {
7119
+ enabled: isTarget ? patch.enabled ?? false : false,
7120
+ color: isTarget ? patch.color ?? "#7C6FFF" : "#7C6FFF",
7121
+ blur: isTarget ? patch.blur ?? 20 : 20,
7122
+ opacity: isTarget ? patch.opacity ?? 80 : 80,
7123
+ type: isTarget ? patch.type ?? "outer" : "outer",
7124
+ strength: isTarget ? patch.strength : void 0,
7125
+ spread: isTarget ? patch.spread : void 0
7126
+ };
7127
+ const newL = {
7128
+ id: newLayerId(),
7129
+ type: "glow",
7130
+ name: `Glow ${currentGlowLayers.length + i + 1}`,
7131
+ enabled: defaultGlow.enabled,
7132
+ opacity: defaultGlow.opacity / 100,
7133
+ blendMode: "source-over",
7134
+ target: "text",
7135
+ params: defaultGlow
7136
+ };
7137
+ const lastGlowIdx = layers.map((l) => l.type).lastIndexOf("glow");
7138
+ if (lastGlowIdx >= 0) {
7139
+ layers.splice(lastGlowIdx + 1 + i, 0, newL);
7140
+ } else {
7141
+ const insertIdx = layers.findIndex((l) => l.type === "mask" || l.type === "filter");
7142
+ if (insertIdx >= 0) {
7143
+ layers.splice(insertIdx + i, 0, newL);
7144
+ } else {
7145
+ layers.push(newL);
7146
+ }
7147
+ }
7148
+ }
7149
+ } else {
7150
+ let glowCount = 0;
7151
+ for (let i = 0; i < layers.length; i++) {
7152
+ if (layers[i].type === "glow") {
7153
+ if (glowCount === index) {
7154
+ const layer2 = layers[i];
7155
+ const nextParams = { ...layer2.params, ...patch };
7156
+ const enabled = patch.enabled !== void 0 ? patch.enabled : layer2.enabled;
7157
+ const opacity = patch.opacity !== void 0 ? patch.opacity / 100 : layer2.opacity;
7158
+ layers[i] = {
7159
+ ...layer2,
7160
+ enabled,
7161
+ opacity,
7162
+ params: nextParams
7163
+ };
7164
+ break;
7165
+ }
7166
+ glowCount++;
7167
+ }
7168
+ }
7169
+ }
7170
+ const nextLegacyConfig = doc.legacyConfig ? { ...doc.legacyConfig } : void 0;
7171
+ if (nextLegacyConfig) {
7172
+ if (!nextLegacyConfig.glowLayers) nextLegacyConfig.glowLayers = [];
7173
+ while (nextLegacyConfig.glowLayers.length <= index) {
7174
+ nextLegacyConfig.glowLayers.push({
7175
+ enabled: false,
7176
+ color: "#7C6FFF",
7177
+ blur: 20,
7178
+ opacity: 80,
7179
+ type: "outer"
7180
+ });
7181
+ }
7182
+ nextLegacyConfig.glowLayers[index] = { ...nextLegacyConfig.glowLayers[index], ...patch };
7183
+ }
7184
+ return {
7185
+ ...doc,
7186
+ effectLayers: layers,
7187
+ legacyConfig: nextLegacyConfig
7188
+ };
7189
+ }
7190
+ function updateSceneCanvas(doc, patch) {
7191
+ const nextCanvas = { ...doc.canvas };
7192
+ if (patch.width !== void 0) nextCanvas.width = patch.width;
7193
+ if (patch.height !== void 0) nextCanvas.height = patch.height;
7194
+ if (patch.background !== void 0) nextCanvas.background = patch.background;
7195
+ const nextLegacyConfig = doc.legacyConfig ? { ...doc.legacyConfig } : void 0;
7196
+ if (nextLegacyConfig) {
7197
+ if (patch.width !== void 0) nextLegacyConfig.canvasWidth = patch.width;
7198
+ if (patch.height !== void 0) nextLegacyConfig.canvasHeight = patch.height;
7199
+ }
7200
+ return {
7201
+ ...doc,
7202
+ canvas: nextCanvas,
7203
+ legacyConfig: nextLegacyConfig
7204
+ };
7205
+ }
7206
+ function updateSceneCustomEngine(doc, patch) {
7207
+ let nextEngineId = doc.customEngineId;
7208
+ if (patch.customRenderer !== void 0) {
7209
+ nextEngineId = patch.customRenderer ? LEGACY_RENDERER_MAP[patch.customRenderer] ?? null : null;
7210
+ }
7211
+ const nextParams = { ...doc.engineParams, ...patch };
7212
+ delete nextParams.customRenderer;
7213
+ const nextLayers = doc.effectLayers.map((layer2) => {
7214
+ if (layer2.type === "customEngine") {
7215
+ if (layer2.name === "Custom Engine") {
7216
+ return {
7217
+ ...layer2,
7218
+ params: { ...layer2.params, engineId: nextEngineId }
7219
+ };
7220
+ } else if (layer2.name === "Engine Params") {
7221
+ return {
7222
+ ...layer2,
7223
+ params: { ...layer2.params, ...nextParams }
7224
+ };
7225
+ }
7226
+ }
7227
+ return layer2;
7228
+ });
7229
+ const nextLegacyConfig = doc.legacyConfig ? { ...doc.legacyConfig } : void 0;
7230
+ if (nextLegacyConfig) {
7231
+ if (patch.customRenderer !== void 0) nextLegacyConfig.customRenderer = patch.customRenderer;
7232
+ if (patch.inkColor !== void 0) nextLegacyConfig.inkColor = patch.inkColor;
7233
+ if (patch.bristleDensity !== void 0) nextLegacyConfig.bristleDensity = patch.bristleDensity;
7234
+ if (patch.bristleSkipRate !== void 0) nextLegacyConfig.bristleSkipRate = patch.bristleSkipRate;
7235
+ if (patch.dripRate !== void 0) nextLegacyConfig.dripRate = patch.dripRate;
7236
+ if (patch.dripMaxLength !== void 0) nextLegacyConfig.dripMaxLength = patch.dripMaxLength;
7237
+ if (patch.grainDensity !== void 0) nextLegacyConfig.grainDensity = patch.grainDensity;
7238
+ if (patch.skewX !== void 0) nextLegacyConfig.skewX = patch.skewX;
7239
+ }
7240
+ return {
7241
+ ...doc,
7242
+ customEngineId: nextEngineId,
7243
+ engineParams: nextParams,
7244
+ effectLayers: nextLayers,
7245
+ legacyConfig: nextLegacyConfig
7246
+ };
7247
+ }
7248
+ var TextEffectBuilder = class _TextEffectBuilder {
7249
+ config;
7250
+ constructor(initialConfig) {
7251
+ this.config = { ...defaultConfig, ...initialConfig };
7252
+ }
7253
+ /** Load builder from an existing TextEffectConfig object */
7254
+ static fromConfig(config) {
7255
+ return new _TextEffectBuilder(config);
7256
+ }
7257
+ /** Load builder from an existing SceneDocument */
7258
+ static fromScene(scene) {
7259
+ return new _TextEffectBuilder(sceneToConfig(scene));
7260
+ }
7261
+ /**
7262
+ * Load builder from a downloaded TextEffectDefinition.
7263
+ * Resolves the styling definition structure to a flat engine config.
7264
+ */
7265
+ static fromDefinition(effect, text = "CLYPRA", fontSize = 80, canvasWidth = 800, canvasHeight = 200) {
7266
+ const config = _buildConfig(effect, text, fontSize, canvasWidth, canvasHeight);
7267
+ return new _TextEffectBuilder(config);
7268
+ }
7269
+ /** Set text string content */
7270
+ setText(text) {
7271
+ this.config.text = text;
7272
+ return this;
7273
+ }
7274
+ /** Configure Font and alignment settings */
7275
+ setFont(font) {
7276
+ if (font.family !== void 0) this.config.fontFamily = font.family;
7277
+ if (font.weight !== void 0) this.config.fontWeight = font.weight;
7278
+ if (font.style !== void 0) this.config.fontStyle = font.style;
7279
+ if (font.size !== void 0) this.config.fontSize = font.size;
7280
+ if (font.letterSpacing !== void 0) this.config.letterSpacing = font.letterSpacing;
7281
+ if (font.lineHeight !== void 0) this.config.lineHeight = font.lineHeight;
7282
+ return this;
7283
+ }
7284
+ /** Configure Background Panel (bounding plate) */
7285
+ setPanel(panel) {
7286
+ if (panel.enabled !== void 0) this.config.panelEnabled = panel.enabled;
7287
+ if (panel.color !== void 0) this.config.panelColor = panel.color;
7288
+ if (panel.opacity !== void 0) this.config.panelOpacity = panel.opacity;
7289
+ if (panel.radius !== void 0) this.config.panelRadius = panel.radius;
7290
+ if (panel.paddingX !== void 0) this.config.panelPaddingX = panel.paddingX;
7291
+ if (panel.paddingY !== void 0) this.config.panelPaddingY = panel.paddingY;
7292
+ if (panel.strokeEnabled !== void 0) this.config.panelStrokeEnabled = panel.strokeEnabled;
7293
+ if (panel.strokeColor !== void 0) this.config.panelStrokeColor = panel.strokeColor;
7294
+ if (panel.strokeWidth !== void 0) this.config.panelStrokeWidth = panel.strokeWidth;
7295
+ return this;
7296
+ }
7297
+ /** Configure outline / stroke styling */
7298
+ setStroke(stroke) {
7299
+ if (stroke.enabled !== void 0) this.config.strokeEnabled = stroke.enabled;
7300
+ if (stroke.color !== void 0) this.config.strokeColor = stroke.color;
7301
+ if (stroke.width !== void 0) this.config.strokeWidth = stroke.width;
7302
+ if (stroke.position !== void 0) this.config.strokePosition = stroke.position;
7303
+ if (stroke.opacity !== void 0) this.config.strokeOpacity = stroke.opacity;
7304
+ if (stroke.lineJoin !== void 0) this.config.strokeLineJoin = stroke.lineJoin;
7305
+ if (stroke.blur !== void 0) this.config.strokeBlur = stroke.blur;
7306
+ if (stroke.type !== void 0) this.config.strokeType = stroke.type;
7307
+ if (stroke.colorSecondary !== void 0) this.config.strokeColorSecondary = stroke.colorSecondary;
7308
+ if (stroke.widthSecondary !== void 0) this.config.strokeWidthSecondary = stroke.widthSecondary;
7309
+ if (stroke.fadeRange !== void 0) this.config.strokeFadeRange = stroke.fadeRange;
7310
+ return this;
7311
+ }
7312
+ /** Configure drop shadow / inner shadow styling */
7313
+ setShadow(shadow) {
7314
+ if (shadow.enabled !== void 0) this.config.shadowEnabled = shadow.enabled;
7315
+ if (shadow.color !== void 0) this.config.shadowColor = shadow.color;
7316
+ if (shadow.blur !== void 0) this.config.shadowBlur = shadow.blur;
7317
+ if (shadow.offsetX !== void 0) this.config.shadowOffsetX = shadow.offsetX;
7318
+ if (shadow.offsetY !== void 0) this.config.shadowOffsetY = shadow.offsetY;
7319
+ if (shadow.opacity !== void 0) this.config.shadowOpacity = shadow.opacity;
7320
+ if (shadow.type !== void 0) this.config.shadowType = shadow.type;
7321
+ return this;
7322
+ }
7323
+ /** Configure a specific glow layer by index */
7324
+ setGlow(index, glow) {
7325
+ if (!this.config.glowLayers) this.config.glowLayers = [];
7326
+ while (this.config.glowLayers.length <= index) {
7327
+ this.config.glowLayers.push({ enabled: false, color: "#7C6FFF", blur: 20, opacity: 80, type: "outer" });
7328
+ }
7329
+ this.config.glowLayers[index] = { ...this.config.glowLayers[index], ...glow };
7330
+ return this;
7331
+ }
7332
+ /** Configure solid color fill */
7333
+ setFillColor(color) {
7334
+ this.config.fillType = "solid";
7335
+ this.config.fillColor = color;
7336
+ return this;
7337
+ }
7338
+ /** Configure linear gradient fill */
7339
+ setFillGradient(angle, stops) {
7340
+ this.config.fillType = "linear";
7341
+ this.config.fillGradientAngle = angle;
7342
+ this.config.fillGradientStops = stops;
7343
+ return this;
7344
+ }
7345
+ /** Configure texture pattern fill */
7346
+ setFillPattern(patternType) {
7347
+ this.config.fillType = "pattern";
7348
+ this.config.patternType = patternType;
7349
+ return this;
7350
+ }
7351
+ /** Configure per-character solid color fill overrides */
7352
+ setPerCharFill(enabled, colors) {
7353
+ this.config.perCharFillEnabled = enabled;
7354
+ this.config.charFillColors = colors;
7355
+ return this;
7356
+ }
7357
+ /** Configure 3D extrusion/bevel settings */
7358
+ setBevel(bevel) {
7359
+ if (bevel.enabled !== void 0) this.config.bevelEnabled = bevel.enabled;
7360
+ if (bevel.depth !== void 0) this.config.bevelDepth = bevel.depth;
7361
+ if (bevel.highlight !== void 0) this.config.bevelHighlight = bevel.highlight;
7362
+ if (bevel.bevelShadow !== void 0) this.config.bevelShadow = bevel.bevelShadow;
7363
+ if (bevel.direction !== void 0) this.config.bevelDirection = bevel.direction;
7364
+ if (bevel.coreColor !== void 0) this.config.bevelCoreColor = bevel.coreColor;
7365
+ if (bevel.edgeColor !== void 0) this.config.bevelEdgeColor = bevel.edgeColor;
7366
+ if (bevel.edgeWidth !== void 0) this.config.bevelEdgeWidth = bevel.edgeWidth;
7367
+ if (bevel.blur !== void 0) this.config.bevelBlur = bevel.blur;
7368
+ if (bevel.blurColor !== void 0) this.config.bevelBlurColor = bevel.blurColor;
7369
+ if (bevel.perspectiveEnabled !== void 0) this.config.bevelPerspectiveEnabled = bevel.perspectiveEnabled;
7370
+ if (bevel.vanishingPointX !== void 0) this.config.bevelVanishingPointX = bevel.vanishingPointX;
7371
+ if (bevel.vanishingPointY !== void 0) this.config.bevelVanishingPointY = bevel.vanishingPointY;
7372
+ if (bevel.focalLength !== void 0) this.config.bevelFocalLength = bevel.focalLength;
7373
+ return this;
7374
+ }
7375
+ /** Configure multi-stack duplicate extrusion */
7376
+ setStack(stack) {
7377
+ if (stack.enabled !== void 0) this.config.stackEnabled = stack.enabled;
7378
+ if (stack.count !== void 0) this.config.stackCount = stack.count;
7379
+ if (stack.offsetX !== void 0) this.config.stackOffsetX = stack.offsetX;
7380
+ if (stack.offsetY !== void 0) this.config.stackOffsetY = stack.offsetY;
7381
+ if (stack.opacityDecay !== void 0) this.config.stackOpacityDecay = stack.opacityDecay;
7382
+ if (stack.color1 !== void 0) this.config.stackColor1 = stack.color1;
7383
+ if (stack.color2 !== void 0) this.config.stackColor2 = stack.color2;
7384
+ if (stack.color3 !== void 0) this.config.stackColor3 = stack.color3;
7385
+ if (stack.color4 !== void 0) this.config.stackColor4 = stack.color4;
7386
+ return this;
7387
+ }
7388
+ /** Configure canvas viewport size, alignment positioning, and wrapping behavior */
7389
+ setCanvas(canvas) {
7390
+ if (canvas.width !== void 0) this.config.canvasWidth = canvas.width;
7391
+ if (canvas.height !== void 0) this.config.canvasHeight = canvas.height;
7392
+ if (canvas.posX !== void 0) this.config.textPosX = canvas.posX;
7393
+ if (canvas.posY !== void 0) this.config.textPosY = canvas.posY;
7394
+ if (canvas.wrapText !== void 0) this.config.wrapText = canvas.wrapText;
7395
+ if (canvas.autoFitText !== void 0) this.config.autoFitText = canvas.autoFitText;
7396
+ return this;
7397
+ }
7398
+ /** Configure procedural InkBrushEngine variables (when customRenderer = InkBrushEngine) */
7399
+ setInkBrush(ink) {
7400
+ if (ink.inkColor !== void 0) this.config.inkColor = ink.inkColor;
7401
+ if (ink.bristleDensity !== void 0) this.config.bristleDensity = ink.bristleDensity;
7402
+ if (ink.bristleSkipRate !== void 0) this.config.bristleSkipRate = ink.bristleSkipRate;
7403
+ if (ink.dripRate !== void 0) this.config.dripRate = ink.dripRate;
7404
+ if (ink.dripMaxLength !== void 0) this.config.dripMaxLength = ink.dripMaxLength;
7405
+ if (ink.grainDensity !== void 0) this.config.grainDensity = ink.grainDensity;
7406
+ if (ink.skewX !== void 0) this.config.skewX = ink.skewX;
7407
+ return this;
7408
+ }
7409
+ /** Build and return a copy of the updated TextEffectConfig */
7410
+ buildConfig() {
7411
+ return { ...this.config };
7412
+ }
7413
+ /** Build and return a SceneDocument prepared for rendering with evaluateScene */
7414
+ buildScene() {
7415
+ return textEffectConfigToScene(this.config);
7416
+ }
7417
+ };
6445
7418
  export {
7419
+ AnimationSchema,
6446
7420
  COMPOSITION_PRESETS,
6447
7421
  CUSTOM_ENGINE_IDS,
6448
7422
  CanvasDevice,
@@ -6456,8 +7430,19 @@ export {
6456
7430
  ENGINE_ID_TO_LEGACY,
6457
7431
  ENTRANCE_PRESETS,
6458
7432
  EXIT_PRESETS,
7433
+ EffectBevelSchema,
7434
+ EffectFillSchema,
7435
+ EffectFullDefinitionSchema,
7436
+ EffectGlowSchema,
7437
+ EffectIndexItemSchema,
7438
+ EffectPanelSchema,
7439
+ EffectShadowSchema,
7440
+ EffectStackSchema,
7441
+ EffectStrokeSchema,
6459
7442
  FONT_WEIGHT_OPTIONS,
6460
7443
  FontLoader,
7444
+ FontSchema,
7445
+ GradientStopSchema,
6461
7446
  InkBrushEngine,
6462
7447
  LEGACY_RENDERER_MAP,
6463
7448
  LOOP_PRESETS,
@@ -6466,6 +7451,8 @@ export {
6466
7451
  SCENE_VERSION,
6467
7452
  SUPPORTED_FONT_FAMILIES,
6468
7453
  TEMPLATE_CATEGORIES,
7454
+ TextEffectBuilder,
7455
+ TextEffectDefinitionSchema,
6469
7456
  TextEffectRenderer,
6470
7457
  WEBM_EXPORT_MAX_FRAMES,
6471
7458
  WebGLCompositor,
@@ -6531,6 +7518,7 @@ export {
6531
7518
  evaluateConfig,
6532
7519
  evaluateScene,
6533
7520
  findTrackIndex,
7521
+ formatValidationErrors,
6534
7522
  getAnimPreset,
6535
7523
  getAnimatableParamDef,
6536
7524
  getAnimatableParamsForLayer,
@@ -6602,11 +7590,25 @@ export {
6602
7590
  textEffectConfigToScene,
6603
7591
  trackId,
6604
7592
  updateKeyframe,
7593
+ updateSceneBevel,
7594
+ updateSceneCanvas,
7595
+ updateSceneCustomEngine,
7596
+ updateSceneFill,
7597
+ updateSceneGlow,
7598
+ updateScenePanel,
7599
+ updateSceneShadow,
7600
+ updateSceneStack,
7601
+ updateSceneStroke,
7602
+ updateSceneText,
6605
7603
  updateStaticProperty,
6606
7604
  updateTimeline,
6607
7605
  updateTrack,
6608
7606
  updateTrackMatte,
6609
7607
  upsertKeyframe,
7608
+ validateEffectDefinition,
7609
+ validateEffectDefinitionStrict,
7610
+ validateTextEffectDefinition,
7611
+ validateTextEffectDefinitionStrict,
6610
7612
  waitForFontsReady,
6611
7613
  wrapTextToWidth
6612
7614
  };