@clypra/engine 1.2.0 → 1.3.0

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
@@ -42,6 +42,7 @@ __export(index_exports, {
42
42
  SCENE_VERSION: () => SCENE_VERSION,
43
43
  SUPPORTED_FONT_FAMILIES: () => SUPPORTED_FONT_FAMILIES,
44
44
  TEMPLATE_CATEGORIES: () => TEMPLATE_CATEGORIES,
45
+ TextEffectBuilder: () => TextEffectBuilder,
45
46
  TextEffectRenderer: () => TextEffectRenderer,
46
47
  WEBM_EXPORT_MAX_FRAMES: () => WEBM_EXPORT_MAX_FRAMES,
47
48
  WebGLCompositor: () => WebGLCompositor,
@@ -178,6 +179,16 @@ __export(index_exports, {
178
179
  textEffectConfigToScene: () => textEffectConfigToScene,
179
180
  trackId: () => trackId,
180
181
  updateKeyframe: () => updateKeyframe,
182
+ updateSceneBevel: () => updateSceneBevel,
183
+ updateSceneCanvas: () => updateSceneCanvas,
184
+ updateSceneCustomEngine: () => updateSceneCustomEngine,
185
+ updateSceneFill: () => updateSceneFill,
186
+ updateSceneGlow: () => updateSceneGlow,
187
+ updateScenePanel: () => updateScenePanel,
188
+ updateSceneShadow: () => updateSceneShadow,
189
+ updateSceneStack: () => updateSceneStack,
190
+ updateSceneStroke: () => updateSceneStroke,
191
+ updateSceneText: () => updateSceneText,
181
192
  updateStaticProperty: () => updateStaticProperty,
182
193
  updateTimeline: () => updateTimeline,
183
194
  updateTrack: () => updateTrack,
@@ -263,35 +274,26 @@ function wrapTextToWidth(ctx, text, maxWidth, letterSpacing) {
263
274
  const paragraphs = text.split("\n");
264
275
  const lines = [];
265
276
  for (const para of paragraphs) {
266
- if (!para.trim()) {
277
+ if (para === "") {
267
278
  lines.push("");
268
279
  continue;
269
280
  }
270
- const words = para.split(/\s+/).filter(Boolean);
271
281
  let current = "";
272
- for (const word of words) {
273
- const candidate = current ? `${current} ${word}` : word;
274
- if (measureLine(ctx, candidate, letterSpacing) <= maxWidth) {
275
- current = candidate;
282
+ for (let i = 0; i < para.length; i++) {
283
+ const char = para[i];
284
+ const tryLine = current + char;
285
+ if (measureLine(ctx, tryLine, letterSpacing) <= maxWidth) {
286
+ current = tryLine;
276
287
  } else {
277
- if (current) lines.push(current);
278
- if (measureLine(ctx, word, letterSpacing) > maxWidth) {
279
- let chunk = "";
280
- for (const ch of word) {
281
- const tryChunk = chunk + ch;
282
- if (measureLine(ctx, tryChunk, letterSpacing) <= maxWidth) chunk = tryChunk;
283
- else {
284
- if (chunk) lines.push(chunk);
285
- chunk = ch;
286
- }
287
- }
288
- current = chunk;
289
- } else {
290
- current = word;
288
+ if (current) {
289
+ lines.push(current);
291
290
  }
291
+ current = char;
292
292
  }
293
293
  }
294
- if (current) lines.push(current);
294
+ if (current) {
295
+ lines.push(current);
296
+ }
295
297
  }
296
298
  return lines.length > 0 ? lines : [""];
297
299
  }
@@ -317,17 +319,17 @@ function layoutWithFontSize(ctx, cfg, fontSize, lines) {
317
319
  } else {
318
320
  startX = safe.x + safe.width / 2;
319
321
  }
320
- let startY = safe.y + (safe.height - textBlockHeight) / 2 + fontSize * 0.82;
322
+ let startY = safe.y + (safe.height - textBlockHeight) / 2 + fontSize * 0.85;
321
323
  if (cfg.textPosY === "top") {
322
- startY = safe.y + fontSize * 0.82;
324
+ startY = safe.y + fontSize * 0.85;
323
325
  } else if (cfg.textPosY === "bottom") {
324
- startY = safe.y + safe.height - textBlockHeight + fontSize * 0.82;
326
+ startY = safe.y + safe.height - textBlockHeight + fontSize * 0.85;
325
327
  }
326
328
  let xMin = startX;
327
329
  if (align === "center") xMin = startX - maxLineWidth / 2;
328
330
  else if (align === "right") xMin = startX - maxLineWidth;
329
331
  const yMin = startY - fontSize * 0.85;
330
- const yMax = startY + (lines.length - 1) * fontSize * lineHeight + fontSize * 0.25;
332
+ const yMax = startY + (lines.length - 1) * fontSize * lineHeight + fontSize * 0.15;
331
333
  return {
332
334
  lines,
333
335
  fontSize,
@@ -766,11 +768,11 @@ var InkBrushEngine = class {
766
768
  if (letterSpacing !== 0) {
767
769
  ctx.letterSpacing = `${letterSpacing}px`;
768
770
  }
769
- let startY = (height - textBlockHeight) / 2 + fontSize * 0.8;
771
+ let startY = (height - textBlockHeight) / 2 + fontSize * 0.85;
770
772
  if (textPosY === "top") {
771
- startY = 40 + fontSize * 0.8;
773
+ startY = 40 + fontSize * 0.85;
772
774
  } else if (textPosY === "bottom") {
773
- startY = height - 40 - textBlockHeight + fontSize * 0.8;
775
+ startY = height - 40 - textBlockHeight + fontSize * 0.85;
774
776
  }
775
777
  ctx.save();
776
778
  if (skewX !== 0) {
@@ -918,11 +920,11 @@ var InkBrushEngine = class {
918
920
  if (letterSpacing !== 0) {
919
921
  ctx.letterSpacing = `${letterSpacing}px`;
920
922
  }
921
- let startY = (height - textBlockHeight) / 2 + fontSize * 0.8;
923
+ let startY = (height - textBlockHeight) / 2 + fontSize * 0.85;
922
924
  if (textPosY === "top") {
923
- startY = 40 + fontSize * 0.8;
925
+ startY = 40 + fontSize * 0.85;
924
926
  } else if (textPosY === "bottom") {
925
- startY = height - 40 - textBlockHeight + fontSize * 0.8;
927
+ startY = height - 40 - textBlockHeight + fontSize * 0.85;
926
928
  }
927
929
  ctx.save();
928
930
  if (skewX !== 0) {
@@ -6641,6 +6643,821 @@ function duplicateTrackAtPlayhead(doc, trackIndex, previewTime) {
6641
6643
  const value = layer2 ? readLayerScalar(layer2, track.paramPath) : 0;
6642
6644
  return addKeyframeAtTime(doc, trackIndex, previewTime, value);
6643
6645
  }
6646
+
6647
+ // src/engine/api.ts
6648
+ function updateSceneText(doc, patch) {
6649
+ const nextText = { ...doc.text };
6650
+ if (patch.content !== void 0) nextText.content = patch.content;
6651
+ if (patch.fontFamily !== void 0) nextText.fontFamily = patch.fontFamily;
6652
+ if (patch.fontWeight !== void 0) nextText.fontWeight = patch.fontWeight;
6653
+ if (patch.fontStyle !== void 0) nextText.fontStyle = patch.fontStyle;
6654
+ if (patch.fontSize !== void 0) nextText.fontSize = patch.fontSize;
6655
+ if (patch.letterSpacing !== void 0) nextText.letterSpacing = patch.letterSpacing;
6656
+ if (patch.lineHeight !== void 0) nextText.lineHeight = patch.lineHeight;
6657
+ if (patch.textPosX !== void 0) nextText.textPosX = patch.textPosX;
6658
+ if (patch.textPosY !== void 0) nextText.textPosY = patch.textPosY;
6659
+ if (patch.wrapText !== void 0) nextText.wrapText = patch.wrapText;
6660
+ if (patch.autoFitText !== void 0) nextText.autoFitText = patch.autoFitText;
6661
+ if (patch.perCharFillEnabled !== void 0) nextText.perCharFillEnabled = patch.perCharFillEnabled;
6662
+ if (patch.charFillColors !== void 0) nextText.charFillColors = patch.charFillColors;
6663
+ const nextLegacyConfig = doc.legacyConfig ? { ...doc.legacyConfig } : void 0;
6664
+ if (nextLegacyConfig) {
6665
+ if (patch.content !== void 0) nextLegacyConfig.text = patch.content;
6666
+ if (patch.fontFamily !== void 0) nextLegacyConfig.fontFamily = patch.fontFamily;
6667
+ if (patch.fontWeight !== void 0) nextLegacyConfig.fontWeight = patch.fontWeight;
6668
+ if (patch.fontStyle !== void 0) nextLegacyConfig.fontStyle = patch.fontStyle;
6669
+ if (patch.fontSize !== void 0) nextLegacyConfig.fontSize = patch.fontSize;
6670
+ if (patch.letterSpacing !== void 0) nextLegacyConfig.letterSpacing = patch.letterSpacing;
6671
+ if (patch.lineHeight !== void 0) nextLegacyConfig.lineHeight = patch.lineHeight;
6672
+ if (patch.textPosX !== void 0) nextLegacyConfig.textPosX = patch.textPosX;
6673
+ if (patch.textPosY !== void 0) nextLegacyConfig.textPosY = patch.textPosY;
6674
+ if (patch.wrapText !== void 0) nextLegacyConfig.wrapText = patch.wrapText;
6675
+ if (patch.autoFitText !== void 0) nextLegacyConfig.autoFitText = patch.autoFitText;
6676
+ if (patch.perCharFillEnabled !== void 0) nextLegacyConfig.perCharFillEnabled = patch.perCharFillEnabled;
6677
+ if (patch.charFillColors !== void 0) nextLegacyConfig.charFillColors = patch.charFillColors;
6678
+ }
6679
+ return {
6680
+ ...doc,
6681
+ text: nextText,
6682
+ legacyConfig: nextLegacyConfig
6683
+ };
6684
+ }
6685
+ function updateScenePanel(doc, patch) {
6686
+ let panelFound = false;
6687
+ const nextLayers = doc.effectLayers.map((layer2) => {
6688
+ if (layer2.type === "panel") {
6689
+ panelFound = true;
6690
+ const nextParams = { ...layer2.params };
6691
+ if (patch.color !== void 0) nextParams.panelColor = patch.color;
6692
+ if (patch.opacity !== void 0) nextParams.panelOpacity = patch.opacity;
6693
+ if (patch.radius !== void 0) nextParams.panelRadius = patch.radius;
6694
+ if (patch.paddingX !== void 0) nextParams.panelPaddingX = patch.paddingX;
6695
+ if (patch.paddingY !== void 0) nextParams.panelPaddingY = patch.paddingY;
6696
+ if (patch.strokeEnabled !== void 0) nextParams.panelStrokeEnabled = patch.strokeEnabled;
6697
+ if (patch.strokeColor !== void 0) nextParams.panelStrokeColor = patch.strokeColor;
6698
+ if (patch.strokeWidth !== void 0) nextParams.panelStrokeWidth = patch.strokeWidth;
6699
+ const enabled = patch.enabled !== void 0 ? patch.enabled : layer2.enabled;
6700
+ if (patch.enabled !== void 0) {
6701
+ nextParams.panelEnabled = patch.enabled;
6702
+ }
6703
+ return {
6704
+ ...layer2,
6705
+ enabled,
6706
+ params: nextParams
6707
+ };
6708
+ }
6709
+ return layer2;
6710
+ });
6711
+ const layers = [...nextLayers];
6712
+ if (!panelFound) {
6713
+ const defaultParams = {
6714
+ panelEnabled: patch.enabled ?? true,
6715
+ panelColor: patch.color ?? "#1E1E26",
6716
+ panelOpacity: patch.opacity ?? 80,
6717
+ panelRadius: patch.radius ?? 12,
6718
+ panelPaddingX: patch.paddingX ?? 40,
6719
+ panelPaddingY: patch.paddingY ?? 20,
6720
+ panelStrokeEnabled: patch.strokeEnabled ?? false,
6721
+ panelStrokeColor: patch.strokeColor ?? "#2A2A38",
6722
+ panelStrokeWidth: patch.strokeWidth ?? 2
6723
+ };
6724
+ const newL = {
6725
+ id: newLayerId(),
6726
+ type: "panel",
6727
+ name: "Background Panel",
6728
+ enabled: patch.enabled ?? true,
6729
+ opacity: 1,
6730
+ blendMode: "source-over",
6731
+ target: "scene",
6732
+ params: defaultParams
6733
+ };
6734
+ layers.unshift(newL);
6735
+ }
6736
+ const nextLegacyConfig = doc.legacyConfig ? { ...doc.legacyConfig } : void 0;
6737
+ if (nextLegacyConfig) {
6738
+ if (patch.enabled !== void 0) nextLegacyConfig.panelEnabled = patch.enabled;
6739
+ if (patch.color !== void 0) nextLegacyConfig.panelColor = patch.color;
6740
+ if (patch.opacity !== void 0) nextLegacyConfig.panelOpacity = patch.opacity;
6741
+ if (patch.radius !== void 0) nextLegacyConfig.panelRadius = patch.radius;
6742
+ if (patch.paddingX !== void 0) nextLegacyConfig.panelPaddingX = patch.paddingX;
6743
+ if (patch.paddingY !== void 0) nextLegacyConfig.panelPaddingY = patch.paddingY;
6744
+ if (patch.strokeEnabled !== void 0) nextLegacyConfig.panelStrokeEnabled = patch.strokeEnabled;
6745
+ if (patch.strokeColor !== void 0) nextLegacyConfig.panelStrokeColor = patch.strokeColor;
6746
+ if (patch.strokeWidth !== void 0) nextLegacyConfig.panelStrokeWidth = patch.strokeWidth;
6747
+ }
6748
+ return {
6749
+ ...doc,
6750
+ effectLayers: layers,
6751
+ legacyConfig: nextLegacyConfig
6752
+ };
6753
+ }
6754
+ function updateSceneStroke(doc, patch) {
6755
+ let found = false;
6756
+ const nextLayers = doc.effectLayers.map((layer2) => {
6757
+ if (layer2.type === "stroke") {
6758
+ found = true;
6759
+ const nextParams = { ...layer2.params };
6760
+ if (patch.strokeColor !== void 0) nextParams.strokeColor = patch.strokeColor;
6761
+ if (patch.strokeWidth !== void 0) nextParams.strokeWidth = patch.strokeWidth;
6762
+ if (patch.strokePosition !== void 0) nextParams.strokePosition = patch.strokePosition;
6763
+ if (patch.strokeOpacity !== void 0) nextParams.strokeOpacity = patch.strokeOpacity;
6764
+ if (patch.strokeLineJoin !== void 0) nextParams.strokeLineJoin = patch.strokeLineJoin;
6765
+ if (patch.strokeBlur !== void 0) nextParams.strokeBlur = patch.strokeBlur;
6766
+ if (patch.strokeType !== void 0) nextParams.strokeType = patch.strokeType;
6767
+ if (patch.strokeColorSecondary !== void 0) nextParams.strokeColorSecondary = patch.strokeColorSecondary;
6768
+ if (patch.strokeWidthSecondary !== void 0) nextParams.strokeWidthSecondary = patch.strokeWidthSecondary;
6769
+ if (patch.strokeFadeRange !== void 0) nextParams.strokeFadeRange = patch.strokeFadeRange;
6770
+ const enabled = patch.enabled !== void 0 ? patch.enabled : layer2.enabled;
6771
+ if (patch.enabled !== void 0) {
6772
+ nextParams.strokeEnabled = patch.enabled;
6773
+ }
6774
+ return {
6775
+ ...layer2,
6776
+ enabled,
6777
+ params: nextParams
6778
+ };
6779
+ }
6780
+ return layer2;
6781
+ });
6782
+ const layers = [...nextLayers];
6783
+ if (!found) {
6784
+ const defaultParams = {
6785
+ strokeEnabled: patch.enabled ?? true,
6786
+ strokeColor: patch.strokeColor ?? "#7C6FFF",
6787
+ strokeWidth: patch.strokeWidth ?? 4,
6788
+ strokePosition: patch.strokePosition ?? "outside",
6789
+ strokeOpacity: patch.strokeOpacity ?? 100,
6790
+ strokeLineJoin: patch.strokeLineJoin ?? "round",
6791
+ strokeBlur: patch.strokeBlur ?? 0,
6792
+ strokeType: patch.strokeType ?? "single",
6793
+ strokeColorSecondary: patch.strokeColorSecondary ?? "#FFFFFF",
6794
+ strokeWidthSecondary: patch.strokeWidthSecondary ?? 4,
6795
+ strokeFadeRange: patch.strokeFadeRange ?? 0
6796
+ };
6797
+ const newL = {
6798
+ id: newLayerId(),
6799
+ type: "stroke",
6800
+ name: "Stroke",
6801
+ enabled: patch.enabled ?? true,
6802
+ opacity: 1,
6803
+ blendMode: "source-over",
6804
+ target: "text",
6805
+ params: defaultParams
6806
+ };
6807
+ const fillIdx = layers.findIndex((l) => l.type === "fill");
6808
+ if (fillIdx >= 0) {
6809
+ layers.splice(fillIdx, 0, newL);
6810
+ } else {
6811
+ const maskIdx = layers.findIndex((l) => l.type === "mask" || l.type === "filter");
6812
+ if (maskIdx >= 0) {
6813
+ layers.splice(maskIdx, 0, newL);
6814
+ } else {
6815
+ layers.push(newL);
6816
+ }
6817
+ }
6818
+ }
6819
+ const nextLegacyConfig = doc.legacyConfig ? { ...doc.legacyConfig } : void 0;
6820
+ if (nextLegacyConfig) {
6821
+ if (patch.enabled !== void 0) nextLegacyConfig.strokeEnabled = patch.enabled;
6822
+ if (patch.strokeColor !== void 0) nextLegacyConfig.strokeColor = patch.strokeColor;
6823
+ if (patch.strokeWidth !== void 0) nextLegacyConfig.strokeWidth = patch.strokeWidth;
6824
+ if (patch.strokePosition !== void 0) nextLegacyConfig.strokePosition = patch.strokePosition;
6825
+ if (patch.strokeOpacity !== void 0) nextLegacyConfig.strokeOpacity = patch.strokeOpacity;
6826
+ if (patch.strokeLineJoin !== void 0) nextLegacyConfig.strokeLineJoin = patch.strokeLineJoin;
6827
+ if (patch.strokeBlur !== void 0) nextLegacyConfig.strokeBlur = patch.strokeBlur;
6828
+ if (patch.strokeType !== void 0) nextLegacyConfig.strokeType = patch.strokeType;
6829
+ if (patch.strokeColorSecondary !== void 0) nextLegacyConfig.strokeColorSecondary = patch.strokeColorSecondary;
6830
+ if (patch.strokeWidthSecondary !== void 0) nextLegacyConfig.strokeWidthSecondary = patch.strokeWidthSecondary;
6831
+ if (patch.strokeFadeRange !== void 0) nextLegacyConfig.strokeFadeRange = patch.strokeFadeRange;
6832
+ }
6833
+ return {
6834
+ ...doc,
6835
+ effectLayers: layers,
6836
+ legacyConfig: nextLegacyConfig
6837
+ };
6838
+ }
6839
+ function updateSceneShadow(doc, patch) {
6840
+ let found = false;
6841
+ const nextLayers = doc.effectLayers.map((layer2) => {
6842
+ if (layer2.type === "shadow") {
6843
+ found = true;
6844
+ const nextParams = { ...layer2.params };
6845
+ if (patch.shadowColor !== void 0) nextParams.shadowColor = patch.shadowColor;
6846
+ if (patch.shadowBlur !== void 0) nextParams.shadowBlur = patch.shadowBlur;
6847
+ if (patch.shadowOffsetX !== void 0) nextParams.shadowOffsetX = patch.shadowOffsetX;
6848
+ if (patch.shadowOffsetY !== void 0) nextParams.shadowOffsetY = patch.shadowOffsetY;
6849
+ if (patch.shadowOpacity !== void 0) nextParams.shadowOpacity = patch.shadowOpacity;
6850
+ if (patch.shadowType !== void 0) nextParams.shadowType = patch.shadowType;
6851
+ const enabled = patch.enabled !== void 0 ? patch.enabled : layer2.enabled;
6852
+ if (patch.enabled !== void 0) {
6853
+ nextParams.shadowEnabled = patch.enabled;
6854
+ }
6855
+ return {
6856
+ ...layer2,
6857
+ enabled,
6858
+ params: nextParams
6859
+ };
6860
+ }
6861
+ return layer2;
6862
+ });
6863
+ const layers = [...nextLayers];
6864
+ if (!found) {
6865
+ const defaultParams = {
6866
+ shadowEnabled: patch.enabled ?? true,
6867
+ shadowColor: patch.shadowColor ?? "#000000",
6868
+ shadowBlur: patch.shadowBlur ?? 10,
6869
+ shadowOffsetX: patch.shadowOffsetX ?? 5,
6870
+ shadowOffsetY: patch.shadowOffsetY ?? 5,
6871
+ shadowOpacity: patch.shadowOpacity ?? 80,
6872
+ shadowType: patch.shadowType ?? "drop"
6873
+ };
6874
+ const newL = {
6875
+ id: newLayerId(),
6876
+ type: "shadow",
6877
+ name: "Shadow",
6878
+ enabled: patch.enabled ?? true,
6879
+ opacity: 1,
6880
+ blendMode: "source-over",
6881
+ target: "text",
6882
+ params: defaultParams
6883
+ };
6884
+ const panelIdx = layers.findIndex((l) => l.type === "panel");
6885
+ if (panelIdx >= 0) {
6886
+ layers.splice(panelIdx + 1, 0, newL);
6887
+ } else {
6888
+ layers.unshift(newL);
6889
+ }
6890
+ }
6891
+ const nextLegacyConfig = doc.legacyConfig ? { ...doc.legacyConfig } : void 0;
6892
+ if (nextLegacyConfig) {
6893
+ if (patch.enabled !== void 0) nextLegacyConfig.shadowEnabled = patch.enabled;
6894
+ if (patch.shadowColor !== void 0) nextLegacyConfig.shadowColor = patch.shadowColor;
6895
+ if (patch.shadowBlur !== void 0) nextLegacyConfig.shadowBlur = patch.shadowBlur;
6896
+ if (patch.shadowOffsetX !== void 0) nextLegacyConfig.shadowOffsetX = patch.shadowOffsetX;
6897
+ if (patch.shadowOffsetY !== void 0) nextLegacyConfig.shadowOffsetY = patch.shadowOffsetY;
6898
+ if (patch.shadowOpacity !== void 0) nextLegacyConfig.shadowOpacity = patch.shadowOpacity;
6899
+ if (patch.shadowType !== void 0) nextLegacyConfig.shadowType = patch.shadowType;
6900
+ }
6901
+ return {
6902
+ ...doc,
6903
+ effectLayers: layers,
6904
+ legacyConfig: nextLegacyConfig
6905
+ };
6906
+ }
6907
+ function updateSceneBevel(doc, patch) {
6908
+ let found = false;
6909
+ const nextLayers = doc.effectLayers.map((layer2) => {
6910
+ if (layer2.type === "extrusion") {
6911
+ found = true;
6912
+ const nextParams = { ...layer2.params };
6913
+ if (patch.bevelDepth !== void 0) nextParams.bevelDepth = patch.bevelDepth;
6914
+ if (patch.bevelHighlight !== void 0) nextParams.bevelHighlight = patch.bevelHighlight;
6915
+ if (patch.bevelShadow !== void 0) nextParams.bevelShadow = patch.bevelShadow;
6916
+ if (patch.bevelDirection !== void 0) nextParams.bevelDirection = patch.bevelDirection;
6917
+ if (patch.bevelCoreColor !== void 0) nextParams.bevelCoreColor = patch.bevelCoreColor;
6918
+ if (patch.bevelEdgeColor !== void 0) nextParams.bevelEdgeColor = patch.bevelEdgeColor;
6919
+ if (patch.bevelEdgeWidth !== void 0) nextParams.bevelEdgeWidth = patch.bevelEdgeWidth;
6920
+ if (patch.bevelBlur !== void 0) nextParams.bevelBlur = patch.bevelBlur;
6921
+ if (patch.bevelBlurColor !== void 0) nextParams.bevelBlurColor = patch.bevelBlurColor;
6922
+ if (patch.bevelPerspectiveEnabled !== void 0) nextParams.bevelPerspectiveEnabled = patch.bevelPerspectiveEnabled;
6923
+ if (patch.bevelVanishingPointX !== void 0) nextParams.bevelVanishingPointX = patch.bevelVanishingPointX;
6924
+ if (patch.bevelVanishingPointY !== void 0) nextParams.bevelVanishingPointY = patch.bevelVanishingPointY;
6925
+ if (patch.bevelFocalLength !== void 0) nextParams.bevelFocalLength = patch.bevelFocalLength;
6926
+ const enabled = patch.enabled !== void 0 ? patch.enabled : layer2.enabled;
6927
+ if (patch.enabled !== void 0) {
6928
+ nextParams.bevelEnabled = patch.enabled;
6929
+ }
6930
+ return {
6931
+ ...layer2,
6932
+ enabled,
6933
+ params: nextParams
6934
+ };
6935
+ }
6936
+ return layer2;
6937
+ });
6938
+ const layers = [...nextLayers];
6939
+ if (!found) {
6940
+ const defaultParams = {
6941
+ bevelEnabled: patch.enabled ?? true,
6942
+ bevelDepth: patch.bevelDepth ?? 5,
6943
+ bevelHighlight: patch.bevelHighlight ?? "#FFFFFF",
6944
+ bevelShadow: patch.bevelShadow ?? "#000000",
6945
+ bevelDirection: patch.bevelDirection ?? "bottom-right",
6946
+ bevelCoreColor: patch.bevelCoreColor ?? "#000000",
6947
+ bevelEdgeColor: patch.bevelEdgeColor ?? "#2A2A38",
6948
+ bevelEdgeWidth: patch.bevelEdgeWidth ?? 0,
6949
+ bevelBlur: patch.bevelBlur ?? 0,
6950
+ bevelBlurColor: patch.bevelBlurColor ?? "#000000",
6951
+ bevelPerspectiveEnabled: patch.bevelPerspectiveEnabled ?? false,
6952
+ bevelVanishingPointX: patch.bevelVanishingPointX ?? 40,
6953
+ bevelVanishingPointY: patch.bevelVanishingPointY ?? 80,
6954
+ bevelFocalLength: patch.bevelFocalLength ?? 400
6955
+ };
6956
+ const newL = {
6957
+ id: newLayerId(),
6958
+ type: "extrusion",
6959
+ name: "Bevel / Extrusion",
6960
+ enabled: patch.enabled ?? true,
6961
+ opacity: 1,
6962
+ blendMode: "source-over",
6963
+ target: "text",
6964
+ params: defaultParams
6965
+ };
6966
+ const stackIdx = layers.findIndex((l) => l.type === "duplicateStack");
6967
+ if (stackIdx >= 0) {
6968
+ layers.splice(stackIdx, 0, newL);
6969
+ } else {
6970
+ const strokeIdx = layers.findIndex((l) => l.type === "stroke");
6971
+ if (strokeIdx >= 0) {
6972
+ layers.splice(strokeIdx, 0, newL);
6973
+ } else {
6974
+ const maskIdx = layers.findIndex((l) => l.type === "mask" || l.type === "filter");
6975
+ if (maskIdx >= 0) {
6976
+ layers.splice(maskIdx, 0, newL);
6977
+ } else {
6978
+ layers.push(newL);
6979
+ }
6980
+ }
6981
+ }
6982
+ }
6983
+ const nextLegacyConfig = doc.legacyConfig ? { ...doc.legacyConfig } : void 0;
6984
+ if (nextLegacyConfig) {
6985
+ if (patch.enabled !== void 0) nextLegacyConfig.bevelEnabled = patch.enabled;
6986
+ if (patch.bevelDepth !== void 0) nextLegacyConfig.bevelDepth = patch.bevelDepth;
6987
+ if (patch.bevelHighlight !== void 0) nextLegacyConfig.bevelHighlight = patch.bevelHighlight;
6988
+ if (patch.bevelShadow !== void 0) nextLegacyConfig.bevelShadow = patch.bevelShadow;
6989
+ if (patch.bevelDirection !== void 0) nextLegacyConfig.bevelDirection = patch.bevelDirection;
6990
+ if (patch.bevelCoreColor !== void 0) nextLegacyConfig.bevelCoreColor = patch.bevelCoreColor;
6991
+ if (patch.bevelEdgeColor !== void 0) nextLegacyConfig.bevelEdgeColor = patch.bevelEdgeColor;
6992
+ if (patch.bevelEdgeWidth !== void 0) nextLegacyConfig.bevelEdgeWidth = patch.bevelEdgeWidth;
6993
+ if (patch.bevelBlur !== void 0) nextLegacyConfig.bevelBlur = patch.bevelBlur;
6994
+ if (patch.bevelBlurColor !== void 0) nextLegacyConfig.bevelBlurColor = patch.bevelBlurColor;
6995
+ if (patch.bevelPerspectiveEnabled !== void 0) nextLegacyConfig.bevelPerspectiveEnabled = patch.bevelPerspectiveEnabled;
6996
+ if (patch.bevelVanishingPointX !== void 0) nextLegacyConfig.bevelVanishingPointX = patch.bevelVanishingPointX;
6997
+ if (patch.bevelVanishingPointY !== void 0) nextLegacyConfig.bevelVanishingPointY = patch.bevelVanishingPointY;
6998
+ if (patch.bevelFocalLength !== void 0) nextLegacyConfig.bevelFocalLength = patch.bevelFocalLength;
6999
+ }
7000
+ return {
7001
+ ...doc,
7002
+ effectLayers: layers,
7003
+ legacyConfig: nextLegacyConfig
7004
+ };
7005
+ }
7006
+ function updateSceneStack(doc, patch) {
7007
+ let found = false;
7008
+ const nextLayers = doc.effectLayers.map((layer2) => {
7009
+ if (layer2.type === "duplicateStack") {
7010
+ found = true;
7011
+ const nextParams = { ...layer2.params };
7012
+ if (patch.stackCount !== void 0) nextParams.stackCount = patch.stackCount;
7013
+ if (patch.stackOffsetX !== void 0) nextParams.stackOffsetX = patch.stackOffsetX;
7014
+ if (patch.stackOffsetY !== void 0) nextParams.stackOffsetY = patch.stackOffsetY;
7015
+ if (patch.stackOpacityDecay !== void 0) nextParams.stackOpacityDecay = patch.stackOpacityDecay;
7016
+ if (patch.stackColor1 !== void 0) nextParams.stackColor1 = patch.stackColor1;
7017
+ if (patch.stackColor2 !== void 0) nextParams.stackColor2 = patch.stackColor2;
7018
+ if (patch.stackColor3 !== void 0) nextParams.stackColor3 = patch.stackColor3;
7019
+ if (patch.stackColor4 !== void 0) nextParams.stackColor4 = patch.stackColor4;
7020
+ const enabled = patch.enabled !== void 0 ? patch.enabled : layer2.enabled;
7021
+ if (patch.enabled !== void 0) {
7022
+ nextParams.stackEnabled = patch.enabled;
7023
+ }
7024
+ return {
7025
+ ...layer2,
7026
+ enabled,
7027
+ params: nextParams
7028
+ };
7029
+ }
7030
+ return layer2;
7031
+ });
7032
+ const layers = [...nextLayers];
7033
+ if (!found) {
7034
+ const defaultParams = {
7035
+ stackEnabled: patch.enabled ?? true,
7036
+ stackCount: patch.stackCount ?? 3,
7037
+ stackOffsetX: patch.stackOffsetX ?? 10,
7038
+ stackOffsetY: patch.stackOffsetY ?? -10,
7039
+ stackOpacityDecay: patch.stackOpacityDecay ?? 20,
7040
+ stackColor1: patch.stackColor1 ?? "#FF7C00",
7041
+ stackColor2: patch.stackColor2 ?? "#00FFDD",
7042
+ stackColor3: patch.stackColor3 ?? "#FF00AA",
7043
+ stackColor4: patch.stackColor4 ?? "#AA00FF"
7044
+ };
7045
+ const newL = {
7046
+ id: newLayerId(),
7047
+ type: "duplicateStack",
7048
+ name: "Stack Extrusion",
7049
+ enabled: patch.enabled ?? true,
7050
+ opacity: 1,
7051
+ blendMode: "source-over",
7052
+ target: "text",
7053
+ params: defaultParams
7054
+ };
7055
+ const strokeIdx = layers.findIndex((l) => l.type === "stroke");
7056
+ if (strokeIdx >= 0) {
7057
+ layers.splice(strokeIdx, 0, newL);
7058
+ } else {
7059
+ const maskIdx = layers.findIndex((l) => l.type === "mask" || l.type === "filter");
7060
+ if (maskIdx >= 0) {
7061
+ layers.splice(maskIdx, 0, newL);
7062
+ } else {
7063
+ layers.push(newL);
7064
+ }
7065
+ }
7066
+ }
7067
+ const nextLegacyConfig = doc.legacyConfig ? { ...doc.legacyConfig } : void 0;
7068
+ if (nextLegacyConfig) {
7069
+ if (patch.enabled !== void 0) nextLegacyConfig.stackEnabled = patch.enabled;
7070
+ if (patch.stackCount !== void 0) nextLegacyConfig.stackCount = patch.stackCount;
7071
+ if (patch.stackOffsetX !== void 0) nextLegacyConfig.stackOffsetX = patch.stackOffsetX;
7072
+ if (patch.stackOffsetY !== void 0) nextLegacyConfig.stackOffsetY = patch.stackOffsetY;
7073
+ if (patch.stackOpacityDecay !== void 0) nextLegacyConfig.stackOpacityDecay = patch.stackOpacityDecay;
7074
+ if (patch.stackColor1 !== void 0) nextLegacyConfig.stackColor1 = patch.stackColor1;
7075
+ if (patch.stackColor2 !== void 0) nextLegacyConfig.stackColor2 = patch.stackColor2;
7076
+ if (patch.stackColor3 !== void 0) nextLegacyConfig.stackColor3 = patch.stackColor3;
7077
+ if (patch.stackColor4 !== void 0) nextLegacyConfig.stackColor4 = patch.stackColor4;
7078
+ }
7079
+ return {
7080
+ ...doc,
7081
+ effectLayers: layers,
7082
+ legacyConfig: nextLegacyConfig
7083
+ };
7084
+ }
7085
+ function updateSceneFill(doc, patch) {
7086
+ let found = false;
7087
+ const nextLayers = doc.effectLayers.map((layer2) => {
7088
+ if (layer2.type === "fill") {
7089
+ found = true;
7090
+ const nextParams = { ...layer2.params };
7091
+ if (patch.fillType !== void 0) nextParams.fillType = patch.fillType;
7092
+ if (patch.fillColor !== void 0) nextParams.fillColor = patch.fillColor;
7093
+ if (patch.fillGradientAngle !== void 0) nextParams.fillGradientAngle = patch.fillGradientAngle;
7094
+ if (patch.fillGradientStops !== void 0) nextParams.fillGradientStops = patch.fillGradientStops;
7095
+ if (patch.patternType !== void 0) nextParams.patternType = patch.patternType;
7096
+ if (patch.perCharFillEnabled !== void 0) nextParams.perCharFillEnabled = patch.perCharFillEnabled;
7097
+ if (patch.charFillColors !== void 0) nextParams.charFillColors = patch.charFillColors;
7098
+ const enabled = patch.fillType !== void 0 ? patch.fillType !== "none" : layer2.enabled;
7099
+ return {
7100
+ ...layer2,
7101
+ enabled,
7102
+ params: nextParams
7103
+ };
7104
+ }
7105
+ return layer2;
7106
+ });
7107
+ const layers = [...nextLayers];
7108
+ if (!found) {
7109
+ const defaultParams = {
7110
+ fillType: patch.fillType ?? "solid",
7111
+ fillColor: patch.fillColor ?? "#FFFFFF",
7112
+ fillGradientAngle: patch.fillGradientAngle ?? 90,
7113
+ fillGradientStops: patch.fillGradientStops ?? [
7114
+ { color: "#FFFFFF", offset: 0 },
7115
+ { color: "#E0E0E0", offset: 100 }
7116
+ ],
7117
+ patternType: patch.patternType ?? "chalk",
7118
+ perCharFillEnabled: patch.perCharFillEnabled ?? false,
7119
+ charFillColors: patch.charFillColors ?? []
7120
+ };
7121
+ const newL = {
7122
+ id: newLayerId(),
7123
+ type: "fill",
7124
+ name: "Fill",
7125
+ enabled: patch.fillType !== "none",
7126
+ opacity: 1,
7127
+ blendMode: "source-over",
7128
+ target: "text",
7129
+ params: defaultParams
7130
+ };
7131
+ const maskIdx = layers.findIndex((l) => l.type === "mask" || l.type === "filter");
7132
+ if (maskIdx >= 0) {
7133
+ layers.splice(maskIdx, 0, newL);
7134
+ } else {
7135
+ layers.push(newL);
7136
+ }
7137
+ }
7138
+ const nextLegacyConfig = doc.legacyConfig ? { ...doc.legacyConfig } : void 0;
7139
+ if (nextLegacyConfig) {
7140
+ if (patch.fillType !== void 0) nextLegacyConfig.fillType = patch.fillType;
7141
+ if (patch.fillColor !== void 0) nextLegacyConfig.fillColor = patch.fillColor;
7142
+ if (patch.fillGradientAngle !== void 0) nextLegacyConfig.fillGradientAngle = patch.fillGradientAngle;
7143
+ if (patch.fillGradientStops !== void 0) nextLegacyConfig.fillGradientStops = patch.fillGradientStops;
7144
+ if (patch.patternType !== void 0) nextLegacyConfig.patternType = patch.patternType;
7145
+ if (patch.perCharFillEnabled !== void 0) nextLegacyConfig.perCharFillEnabled = patch.perCharFillEnabled;
7146
+ if (patch.charFillColors !== void 0) nextLegacyConfig.charFillColors = patch.charFillColors;
7147
+ }
7148
+ return {
7149
+ ...doc,
7150
+ effectLayers: layers,
7151
+ legacyConfig: nextLegacyConfig
7152
+ };
7153
+ }
7154
+ function updateSceneGlow(doc, index, patch) {
7155
+ const currentGlowLayers = doc.effectLayers.filter((l) => l.type === "glow");
7156
+ const layers = [...doc.effectLayers];
7157
+ if (index >= currentGlowLayers.length) {
7158
+ const needed = index - currentGlowLayers.length + 1;
7159
+ for (let i = 0; i < needed; i++) {
7160
+ const isTarget = i === needed - 1;
7161
+ const defaultGlow = {
7162
+ enabled: isTarget ? patch.enabled ?? false : false,
7163
+ color: isTarget ? patch.color ?? "#7C6FFF" : "#7C6FFF",
7164
+ blur: isTarget ? patch.blur ?? 20 : 20,
7165
+ opacity: isTarget ? patch.opacity ?? 80 : 80,
7166
+ type: isTarget ? patch.type ?? "outer" : "outer",
7167
+ strength: isTarget ? patch.strength : void 0,
7168
+ spread: isTarget ? patch.spread : void 0
7169
+ };
7170
+ const newL = {
7171
+ id: newLayerId(),
7172
+ type: "glow",
7173
+ name: `Glow ${currentGlowLayers.length + i + 1}`,
7174
+ enabled: defaultGlow.enabled,
7175
+ opacity: defaultGlow.opacity / 100,
7176
+ blendMode: "source-over",
7177
+ target: "text",
7178
+ params: defaultGlow
7179
+ };
7180
+ const lastGlowIdx = layers.map((l) => l.type).lastIndexOf("glow");
7181
+ if (lastGlowIdx >= 0) {
7182
+ layers.splice(lastGlowIdx + 1 + i, 0, newL);
7183
+ } else {
7184
+ const insertIdx = layers.findIndex((l) => l.type === "mask" || l.type === "filter");
7185
+ if (insertIdx >= 0) {
7186
+ layers.splice(insertIdx + i, 0, newL);
7187
+ } else {
7188
+ layers.push(newL);
7189
+ }
7190
+ }
7191
+ }
7192
+ } else {
7193
+ let glowCount = 0;
7194
+ for (let i = 0; i < layers.length; i++) {
7195
+ if (layers[i].type === "glow") {
7196
+ if (glowCount === index) {
7197
+ const layer2 = layers[i];
7198
+ const nextParams = { ...layer2.params, ...patch };
7199
+ const enabled = patch.enabled !== void 0 ? patch.enabled : layer2.enabled;
7200
+ const opacity = patch.opacity !== void 0 ? patch.opacity / 100 : layer2.opacity;
7201
+ layers[i] = {
7202
+ ...layer2,
7203
+ enabled,
7204
+ opacity,
7205
+ params: nextParams
7206
+ };
7207
+ break;
7208
+ }
7209
+ glowCount++;
7210
+ }
7211
+ }
7212
+ }
7213
+ const nextLegacyConfig = doc.legacyConfig ? { ...doc.legacyConfig } : void 0;
7214
+ if (nextLegacyConfig) {
7215
+ if (!nextLegacyConfig.glowLayers) nextLegacyConfig.glowLayers = [];
7216
+ while (nextLegacyConfig.glowLayers.length <= index) {
7217
+ nextLegacyConfig.glowLayers.push({
7218
+ enabled: false,
7219
+ color: "#7C6FFF",
7220
+ blur: 20,
7221
+ opacity: 80,
7222
+ type: "outer"
7223
+ });
7224
+ }
7225
+ nextLegacyConfig.glowLayers[index] = { ...nextLegacyConfig.glowLayers[index], ...patch };
7226
+ }
7227
+ return {
7228
+ ...doc,
7229
+ effectLayers: layers,
7230
+ legacyConfig: nextLegacyConfig
7231
+ };
7232
+ }
7233
+ function updateSceneCanvas(doc, patch) {
7234
+ const nextCanvas = { ...doc.canvas };
7235
+ if (patch.width !== void 0) nextCanvas.width = patch.width;
7236
+ if (patch.height !== void 0) nextCanvas.height = patch.height;
7237
+ if (patch.background !== void 0) nextCanvas.background = patch.background;
7238
+ const nextLegacyConfig = doc.legacyConfig ? { ...doc.legacyConfig } : void 0;
7239
+ if (nextLegacyConfig) {
7240
+ if (patch.width !== void 0) nextLegacyConfig.canvasWidth = patch.width;
7241
+ if (patch.height !== void 0) nextLegacyConfig.canvasHeight = patch.height;
7242
+ }
7243
+ return {
7244
+ ...doc,
7245
+ canvas: nextCanvas,
7246
+ legacyConfig: nextLegacyConfig
7247
+ };
7248
+ }
7249
+ function updateSceneCustomEngine(doc, patch) {
7250
+ let nextEngineId = doc.customEngineId;
7251
+ if (patch.customRenderer !== void 0) {
7252
+ nextEngineId = patch.customRenderer ? LEGACY_RENDERER_MAP[patch.customRenderer] ?? null : null;
7253
+ }
7254
+ const nextParams = { ...doc.engineParams, ...patch };
7255
+ delete nextParams.customRenderer;
7256
+ const nextLayers = doc.effectLayers.map((layer2) => {
7257
+ if (layer2.type === "customEngine") {
7258
+ if (layer2.name === "Custom Engine") {
7259
+ return {
7260
+ ...layer2,
7261
+ params: { ...layer2.params, engineId: nextEngineId }
7262
+ };
7263
+ } else if (layer2.name === "Engine Params") {
7264
+ return {
7265
+ ...layer2,
7266
+ params: { ...layer2.params, ...nextParams }
7267
+ };
7268
+ }
7269
+ }
7270
+ return layer2;
7271
+ });
7272
+ const nextLegacyConfig = doc.legacyConfig ? { ...doc.legacyConfig } : void 0;
7273
+ if (nextLegacyConfig) {
7274
+ if (patch.customRenderer !== void 0) nextLegacyConfig.customRenderer = patch.customRenderer;
7275
+ if (patch.inkColor !== void 0) nextLegacyConfig.inkColor = patch.inkColor;
7276
+ if (patch.bristleDensity !== void 0) nextLegacyConfig.bristleDensity = patch.bristleDensity;
7277
+ if (patch.bristleSkipRate !== void 0) nextLegacyConfig.bristleSkipRate = patch.bristleSkipRate;
7278
+ if (patch.dripRate !== void 0) nextLegacyConfig.dripRate = patch.dripRate;
7279
+ if (patch.dripMaxLength !== void 0) nextLegacyConfig.dripMaxLength = patch.dripMaxLength;
7280
+ if (patch.grainDensity !== void 0) nextLegacyConfig.grainDensity = patch.grainDensity;
7281
+ if (patch.skewX !== void 0) nextLegacyConfig.skewX = patch.skewX;
7282
+ }
7283
+ return {
7284
+ ...doc,
7285
+ customEngineId: nextEngineId,
7286
+ engineParams: nextParams,
7287
+ effectLayers: nextLayers,
7288
+ legacyConfig: nextLegacyConfig
7289
+ };
7290
+ }
7291
+ var TextEffectBuilder = class _TextEffectBuilder {
7292
+ config;
7293
+ constructor(initialConfig) {
7294
+ this.config = { ...defaultConfig, ...initialConfig };
7295
+ }
7296
+ /** Load builder from an existing TextEffectConfig object */
7297
+ static fromConfig(config) {
7298
+ return new _TextEffectBuilder(config);
7299
+ }
7300
+ /** Load builder from an existing SceneDocument */
7301
+ static fromScene(scene) {
7302
+ return new _TextEffectBuilder(sceneToConfig(scene));
7303
+ }
7304
+ /**
7305
+ * Load builder from a downloaded TextEffectDefinition.
7306
+ * Resolves the styling definition structure to a flat engine config.
7307
+ */
7308
+ static fromDefinition(effect, text = "CLYPRA", fontSize = 80, canvasWidth = 800, canvasHeight = 200) {
7309
+ const config = _buildConfig(effect, text, fontSize, canvasWidth, canvasHeight);
7310
+ return new _TextEffectBuilder(config);
7311
+ }
7312
+ /** Set text string content */
7313
+ setText(text) {
7314
+ this.config.text = text;
7315
+ return this;
7316
+ }
7317
+ /** Configure Font and alignment settings */
7318
+ setFont(font) {
7319
+ if (font.family !== void 0) this.config.fontFamily = font.family;
7320
+ if (font.weight !== void 0) this.config.fontWeight = font.weight;
7321
+ if (font.style !== void 0) this.config.fontStyle = font.style;
7322
+ if (font.size !== void 0) this.config.fontSize = font.size;
7323
+ if (font.letterSpacing !== void 0) this.config.letterSpacing = font.letterSpacing;
7324
+ if (font.lineHeight !== void 0) this.config.lineHeight = font.lineHeight;
7325
+ return this;
7326
+ }
7327
+ /** Configure Background Panel (bounding plate) */
7328
+ setPanel(panel) {
7329
+ if (panel.enabled !== void 0) this.config.panelEnabled = panel.enabled;
7330
+ if (panel.color !== void 0) this.config.panelColor = panel.color;
7331
+ if (panel.opacity !== void 0) this.config.panelOpacity = panel.opacity;
7332
+ if (panel.radius !== void 0) this.config.panelRadius = panel.radius;
7333
+ if (panel.paddingX !== void 0) this.config.panelPaddingX = panel.paddingX;
7334
+ if (panel.paddingY !== void 0) this.config.panelPaddingY = panel.paddingY;
7335
+ if (panel.strokeEnabled !== void 0) this.config.panelStrokeEnabled = panel.strokeEnabled;
7336
+ if (panel.strokeColor !== void 0) this.config.panelStrokeColor = panel.strokeColor;
7337
+ if (panel.strokeWidth !== void 0) this.config.panelStrokeWidth = panel.strokeWidth;
7338
+ return this;
7339
+ }
7340
+ /** Configure outline / stroke styling */
7341
+ setStroke(stroke) {
7342
+ if (stroke.enabled !== void 0) this.config.strokeEnabled = stroke.enabled;
7343
+ if (stroke.color !== void 0) this.config.strokeColor = stroke.color;
7344
+ if (stroke.width !== void 0) this.config.strokeWidth = stroke.width;
7345
+ if (stroke.position !== void 0) this.config.strokePosition = stroke.position;
7346
+ if (stroke.opacity !== void 0) this.config.strokeOpacity = stroke.opacity;
7347
+ if (stroke.lineJoin !== void 0) this.config.strokeLineJoin = stroke.lineJoin;
7348
+ if (stroke.blur !== void 0) this.config.strokeBlur = stroke.blur;
7349
+ if (stroke.type !== void 0) this.config.strokeType = stroke.type;
7350
+ if (stroke.colorSecondary !== void 0) this.config.strokeColorSecondary = stroke.colorSecondary;
7351
+ if (stroke.widthSecondary !== void 0) this.config.strokeWidthSecondary = stroke.widthSecondary;
7352
+ if (stroke.fadeRange !== void 0) this.config.strokeFadeRange = stroke.fadeRange;
7353
+ return this;
7354
+ }
7355
+ /** Configure drop shadow / inner shadow styling */
7356
+ setShadow(shadow) {
7357
+ if (shadow.enabled !== void 0) this.config.shadowEnabled = shadow.enabled;
7358
+ if (shadow.color !== void 0) this.config.shadowColor = shadow.color;
7359
+ if (shadow.blur !== void 0) this.config.shadowBlur = shadow.blur;
7360
+ if (shadow.offsetX !== void 0) this.config.shadowOffsetX = shadow.offsetX;
7361
+ if (shadow.offsetY !== void 0) this.config.shadowOffsetY = shadow.offsetY;
7362
+ if (shadow.opacity !== void 0) this.config.shadowOpacity = shadow.opacity;
7363
+ if (shadow.type !== void 0) this.config.shadowType = shadow.type;
7364
+ return this;
7365
+ }
7366
+ /** Configure a specific glow layer by index */
7367
+ setGlow(index, glow) {
7368
+ if (!this.config.glowLayers) this.config.glowLayers = [];
7369
+ while (this.config.glowLayers.length <= index) {
7370
+ this.config.glowLayers.push({ enabled: false, color: "#7C6FFF", blur: 20, opacity: 80, type: "outer" });
7371
+ }
7372
+ this.config.glowLayers[index] = { ...this.config.glowLayers[index], ...glow };
7373
+ return this;
7374
+ }
7375
+ /** Configure solid color fill */
7376
+ setFillColor(color) {
7377
+ this.config.fillType = "solid";
7378
+ this.config.fillColor = color;
7379
+ return this;
7380
+ }
7381
+ /** Configure linear gradient fill */
7382
+ setFillGradient(angle, stops) {
7383
+ this.config.fillType = "linear";
7384
+ this.config.fillGradientAngle = angle;
7385
+ this.config.fillGradientStops = stops;
7386
+ return this;
7387
+ }
7388
+ /** Configure texture pattern fill */
7389
+ setFillPattern(patternType) {
7390
+ this.config.fillType = "pattern";
7391
+ this.config.patternType = patternType;
7392
+ return this;
7393
+ }
7394
+ /** Configure per-character solid color fill overrides */
7395
+ setPerCharFill(enabled, colors) {
7396
+ this.config.perCharFillEnabled = enabled;
7397
+ this.config.charFillColors = colors;
7398
+ return this;
7399
+ }
7400
+ /** Configure 3D extrusion/bevel settings */
7401
+ setBevel(bevel) {
7402
+ if (bevel.enabled !== void 0) this.config.bevelEnabled = bevel.enabled;
7403
+ if (bevel.depth !== void 0) this.config.bevelDepth = bevel.depth;
7404
+ if (bevel.highlight !== void 0) this.config.bevelHighlight = bevel.highlight;
7405
+ if (bevel.bevelShadow !== void 0) this.config.bevelShadow = bevel.bevelShadow;
7406
+ if (bevel.direction !== void 0) this.config.bevelDirection = bevel.direction;
7407
+ if (bevel.coreColor !== void 0) this.config.bevelCoreColor = bevel.coreColor;
7408
+ if (bevel.edgeColor !== void 0) this.config.bevelEdgeColor = bevel.edgeColor;
7409
+ if (bevel.edgeWidth !== void 0) this.config.bevelEdgeWidth = bevel.edgeWidth;
7410
+ if (bevel.blur !== void 0) this.config.bevelBlur = bevel.blur;
7411
+ if (bevel.blurColor !== void 0) this.config.bevelBlurColor = bevel.blurColor;
7412
+ if (bevel.perspectiveEnabled !== void 0) this.config.bevelPerspectiveEnabled = bevel.perspectiveEnabled;
7413
+ if (bevel.vanishingPointX !== void 0) this.config.bevelVanishingPointX = bevel.vanishingPointX;
7414
+ if (bevel.vanishingPointY !== void 0) this.config.bevelVanishingPointY = bevel.vanishingPointY;
7415
+ if (bevel.focalLength !== void 0) this.config.bevelFocalLength = bevel.focalLength;
7416
+ return this;
7417
+ }
7418
+ /** Configure multi-stack duplicate extrusion */
7419
+ setStack(stack) {
7420
+ if (stack.enabled !== void 0) this.config.stackEnabled = stack.enabled;
7421
+ if (stack.count !== void 0) this.config.stackCount = stack.count;
7422
+ if (stack.offsetX !== void 0) this.config.stackOffsetX = stack.offsetX;
7423
+ if (stack.offsetY !== void 0) this.config.stackOffsetY = stack.offsetY;
7424
+ if (stack.opacityDecay !== void 0) this.config.stackOpacityDecay = stack.opacityDecay;
7425
+ if (stack.color1 !== void 0) this.config.stackColor1 = stack.color1;
7426
+ if (stack.color2 !== void 0) this.config.stackColor2 = stack.color2;
7427
+ if (stack.color3 !== void 0) this.config.stackColor3 = stack.color3;
7428
+ if (stack.color4 !== void 0) this.config.stackColor4 = stack.color4;
7429
+ return this;
7430
+ }
7431
+ /** Configure canvas viewport size, alignment positioning, and wrapping behavior */
7432
+ setCanvas(canvas) {
7433
+ if (canvas.width !== void 0) this.config.canvasWidth = canvas.width;
7434
+ if (canvas.height !== void 0) this.config.canvasHeight = canvas.height;
7435
+ if (canvas.posX !== void 0) this.config.textPosX = canvas.posX;
7436
+ if (canvas.posY !== void 0) this.config.textPosY = canvas.posY;
7437
+ if (canvas.wrapText !== void 0) this.config.wrapText = canvas.wrapText;
7438
+ if (canvas.autoFitText !== void 0) this.config.autoFitText = canvas.autoFitText;
7439
+ return this;
7440
+ }
7441
+ /** Configure procedural InkBrushEngine variables (when customRenderer = InkBrushEngine) */
7442
+ setInkBrush(ink) {
7443
+ if (ink.inkColor !== void 0) this.config.inkColor = ink.inkColor;
7444
+ if (ink.bristleDensity !== void 0) this.config.bristleDensity = ink.bristleDensity;
7445
+ if (ink.bristleSkipRate !== void 0) this.config.bristleSkipRate = ink.bristleSkipRate;
7446
+ if (ink.dripRate !== void 0) this.config.dripRate = ink.dripRate;
7447
+ if (ink.dripMaxLength !== void 0) this.config.dripMaxLength = ink.dripMaxLength;
7448
+ if (ink.grainDensity !== void 0) this.config.grainDensity = ink.grainDensity;
7449
+ if (ink.skewX !== void 0) this.config.skewX = ink.skewX;
7450
+ return this;
7451
+ }
7452
+ /** Build and return a copy of the updated TextEffectConfig */
7453
+ buildConfig() {
7454
+ return { ...this.config };
7455
+ }
7456
+ /** Build and return a SceneDocument prepared for rendering with evaluateScene */
7457
+ buildScene() {
7458
+ return textEffectConfigToScene(this.config);
7459
+ }
7460
+ };
6644
7461
  // Annotate the CommonJS export names for ESM import in node:
6645
7462
  0 && (module.exports = {
6646
7463
  COMPOSITION_PRESETS,
@@ -6666,6 +7483,7 @@ function duplicateTrackAtPlayhead(doc, trackIndex, previewTime) {
6666
7483
  SCENE_VERSION,
6667
7484
  SUPPORTED_FONT_FAMILIES,
6668
7485
  TEMPLATE_CATEGORIES,
7486
+ TextEffectBuilder,
6669
7487
  TextEffectRenderer,
6670
7488
  WEBM_EXPORT_MAX_FRAMES,
6671
7489
  WebGLCompositor,
@@ -6802,6 +7620,16 @@ function duplicateTrackAtPlayhead(doc, trackIndex, previewTime) {
6802
7620
  textEffectConfigToScene,
6803
7621
  trackId,
6804
7622
  updateKeyframe,
7623
+ updateSceneBevel,
7624
+ updateSceneCanvas,
7625
+ updateSceneCustomEngine,
7626
+ updateSceneFill,
7627
+ updateSceneGlow,
7628
+ updateScenePanel,
7629
+ updateSceneShadow,
7630
+ updateSceneStack,
7631
+ updateSceneStroke,
7632
+ updateSceneText,
6805
7633
  updateStaticProperty,
6806
7634
  updateTimeline,
6807
7635
  updateTrack,