@clypra/engine 1.0.1 → 1.1.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.js CHANGED
@@ -1,3 +1,44 @@
1
+ // src/engine/schema.ts
2
+ var SCENE_VERSION = 1;
3
+ var DEFAULT_CANVAS_WIDTH = 800;
4
+ var DEFAULT_CANVAS_HEIGHT = 200;
5
+ var DEFAULT_FONT_SIZE = 80;
6
+ var DEFAULT_FPS = 30;
7
+ var DEFAULT_DURATION = 2;
8
+ var CUSTOM_ENGINE_IDS = ["ink"];
9
+ var LEGACY_RENDERER_MAP = {
10
+ InkBrushEngine: "ink"
11
+ };
12
+ var ENGINE_ID_TO_LEGACY = {
13
+ ink: "InkBrushEngine"
14
+ };
15
+ function createEmptyScene(overrides) {
16
+ return {
17
+ version: SCENE_VERSION,
18
+ effectName: "My Effect",
19
+ canvas: { width: DEFAULT_CANVAS_WIDTH, height: DEFAULT_CANVAS_HEIGHT, background: "transparent" },
20
+ text: {
21
+ content: "CLYPRA",
22
+ fontFamily: "Poppins",
23
+ fontWeight: 700,
24
+ fontStyle: "normal",
25
+ fontSize: DEFAULT_FONT_SIZE,
26
+ letterSpacing: 4,
27
+ lineHeight: 1.2,
28
+ textPosX: "center",
29
+ textPosY: "middle"
30
+ },
31
+ effectLayers: [],
32
+ customEngineId: null,
33
+ compositor: { blur: 0, bloom: 0, bloomThreshold: 0.6 },
34
+ timeline: { duration: DEFAULT_DURATION, fps: DEFAULT_FPS, loop: true, tracks: [] },
35
+ ...overrides
36
+ };
37
+ }
38
+ function newLayerId() {
39
+ return `layer-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 7)}`;
40
+ }
41
+
1
42
  // src/engine/textLayout.ts
2
43
  var COMPOSITION_PRESETS = [
3
44
  { id: "banner", label: "Banner", width: 800, height: 200, description: "Lower third / title bar" },
@@ -17,8 +58,8 @@ function measureLine(ctx, line, letterSpacing) {
17
58
  return w;
18
59
  }
19
60
  function getSafeRect(cfg) {
20
- const w = cfg.canvasWidth || 800;
21
- const h = cfg.canvasHeight || 200;
61
+ const w = cfg.canvasWidth || DEFAULT_CANVAS_WIDTH;
62
+ const h = cfg.canvasHeight || DEFAULT_CANVAS_HEIGHT;
22
63
  const marginX = cfg.panelEnabled ? (cfg.panelPaddingX ?? 40) + 16 : Math.min(48, w * 0.06);
23
64
  const marginY = cfg.panelEnabled ? (cfg.panelPaddingY ?? 20) + 16 : Math.min(40, h * 0.1);
24
65
  return {
@@ -65,8 +106,8 @@ function wrapTextToWidth(ctx, text, maxWidth, letterSpacing) {
65
106
  return lines.length > 0 ? lines : [""];
66
107
  }
67
108
  function layoutWithFontSize(ctx, cfg, fontSize, lines) {
68
- const cWidth = cfg.canvasWidth || 800;
69
- const cHeight = cfg.canvasHeight || 200;
109
+ const cWidth = cfg.canvasWidth || DEFAULT_CANVAS_WIDTH;
110
+ const cHeight = cfg.canvasHeight || DEFAULT_CANVAS_HEIGHT;
70
111
  const safe = getSafeRect(cfg);
71
112
  const lineHeight = cfg.lineHeight ?? 1.2;
72
113
  const letterSpacing = cfg.letterSpacing ?? 0;
@@ -122,7 +163,7 @@ function measureTextFits(ctx, cfg, fontSize, lines) {
122
163
  return layout.bounds.maxLineWidth <= safe.width + 1 && layout.bounds.textBlockHeight <= safe.height + 1;
123
164
  }
124
165
  function computeAutoFitFontSize(ctx, cfg, wrappedLines) {
125
- const max = Math.min(cfg.fontSize || 80, 200);
166
+ const max = Math.min(cfg.fontSize || DEFAULT_FONT_SIZE, 200);
126
167
  let lo = 12;
127
168
  let hi = max;
128
169
  let best = 12;
@@ -242,29 +283,112 @@ function shouldUsePerCharFill(cfg) {
242
283
  return !!cfg.perCharFillEnabled && cfg.fillType === "solid" && !cfg.customRenderer && (cfg.charFillColors?.length ?? 0) > 0;
243
284
  }
244
285
 
245
- // src/engine/procedural/utils.ts
246
- function createCanvas(w, h) {
247
- if (typeof document !== "undefined") {
286
+ // src/platform.ts
287
+ var _ctxFilter = null;
288
+ var _roundRect = null;
289
+ var _letterSpacing = null;
290
+ var _offscreenCanvas = null;
291
+ var _webgl2 = null;
292
+ function probe2d() {
293
+ if (typeof document === "undefined") return null;
294
+ try {
295
+ return document.createElement("canvas").getContext("2d");
296
+ } catch {
297
+ return null;
298
+ }
299
+ }
300
+ function supportsCtxFilter() {
301
+ if (_ctxFilter !== null) return _ctxFilter;
302
+ const ctx = probe2d();
303
+ if (!ctx) {
304
+ _ctxFilter = false;
305
+ return false;
306
+ }
307
+ try {
308
+ ctx.filter = "blur(4px)";
309
+ _ctxFilter = typeof ctx.filter === "string" && ctx.filter.includes("blur");
310
+ } catch {
311
+ _ctxFilter = false;
312
+ }
313
+ return _ctxFilter;
314
+ }
315
+ function supportsRoundRect() {
316
+ if (_roundRect !== null) return _roundRect;
317
+ const ctx = probe2d();
318
+ _roundRect = !!ctx && typeof ctx.roundRect === "function";
319
+ return _roundRect;
320
+ }
321
+ function supportsLetterSpacing() {
322
+ if (_letterSpacing !== null) return _letterSpacing;
323
+ const ctx = probe2d();
324
+ if (!ctx) {
325
+ _letterSpacing = false;
326
+ return false;
327
+ }
328
+ try {
329
+ ctx.letterSpacing = "2px";
330
+ _letterSpacing = typeof ctx.letterSpacing === "string" && ctx.letterSpacing === "2px";
331
+ } catch {
332
+ _letterSpacing = false;
333
+ }
334
+ return _letterSpacing;
335
+ }
336
+ function supportsOffscreenCanvas() {
337
+ if (_offscreenCanvas !== null) return _offscreenCanvas;
338
+ _offscreenCanvas = typeof globalThis !== "undefined" && typeof globalThis.OffscreenCanvas === "function";
339
+ return _offscreenCanvas;
340
+ }
341
+ function supportsWebGL2() {
342
+ if (_webgl2 !== null) return _webgl2;
343
+ if (typeof document === "undefined") {
344
+ _webgl2 = false;
345
+ return false;
346
+ }
347
+ try {
248
348
  const canvas = document.createElement("canvas");
249
- canvas.width = w;
250
- canvas.height = h;
251
- return canvas;
349
+ canvas.width = 1;
350
+ canvas.height = 1;
351
+ _webgl2 = !!canvas.getContext("webgl2");
352
+ } catch {
353
+ _webgl2 = false;
252
354
  }
253
- if (typeof OffscreenCanvas !== "undefined") {
254
- return new OffscreenCanvas(w, h);
355
+ return _webgl2;
356
+ }
357
+ function createCanvas(width, height) {
358
+ if (supportsOffscreenCanvas()) {
359
+ return new OffscreenCanvas(width, height);
255
360
  }
256
- const runtimeCanvasFactory = globalThis.__clypraCreateCanvas;
257
- if (runtimeCanvasFactory) {
258
- return runtimeCanvasFactory(w, h);
361
+ if (typeof document !== "undefined") {
362
+ const canvas = document.createElement("canvas");
363
+ canvas.width = width;
364
+ canvas.height = height;
365
+ return canvas;
259
366
  }
367
+ const factory = globalThis.__clypraCreateCanvas;
368
+ if (factory) return factory(width, height);
260
369
  try {
261
370
  const nodeRequire = (0, eval)("require");
262
371
  const nodeCanvas = nodeRequire("@napi-rs/canvas");
263
- return nodeCanvas.createCanvas(w, h);
372
+ return nodeCanvas.createCanvas(width, height);
264
373
  } catch {
265
- throw new Error("No canvas implementation found in this environment.");
374
+ throw new Error("[clypra/engine] No canvas implementation available in this environment. Set globalThis.__clypraCreateCanvas or install @napi-rs/canvas.");
266
375
  }
267
376
  }
377
+ function releaseCanvas(canvas) {
378
+ if (canvas instanceof OffscreenCanvas) return;
379
+ if (typeof document !== "undefined" && canvas.parentNode) {
380
+ canvas.parentNode.removeChild(canvas);
381
+ }
382
+ }
383
+ function _resetPlatformCache() {
384
+ _ctxFilter = null;
385
+ _roundRect = null;
386
+ _letterSpacing = null;
387
+ _offscreenCanvas = null;
388
+ _webgl2 = null;
389
+ }
390
+
391
+ // src/engine/procedural/utils.ts
268
392
  function getCanvas2DContext(canvas) {
269
393
  return canvas.getContext("2d");
270
394
  }
@@ -365,8 +489,8 @@ var InkBrushEngine = class {
365
489
  panelStrokeEnabled: false,
366
490
  panelStrokeColor: "#2A2A38",
367
491
  panelStrokeWidth: 2,
368
- canvasWidth: 800,
369
- canvasHeight: 200,
492
+ canvasWidth: DEFAULT_CANVAS_WIDTH,
493
+ canvasHeight: DEFAULT_CANVAS_HEIGHT,
370
494
  textPosX: "center",
371
495
  textPosY: "middle",
372
496
  inkColor: "#FFFFFF",
@@ -621,42 +745,39 @@ var InkBrushEngine = class {
621
745
  }
622
746
  };
623
747
 
624
- // src/renderer.ts
625
- function createCanvas2(w, h) {
626
- if (typeof document !== "undefined") {
627
- const canvas = document.createElement("canvas");
628
- canvas.width = w;
629
- canvas.height = h;
630
- return canvas;
631
- }
632
- if (typeof OffscreenCanvas !== "undefined") {
633
- return new OffscreenCanvas(w, h);
634
- }
635
- const runtimeCanvasFactory = globalThis.__clypraCreateCanvas;
636
- if (runtimeCanvasFactory) {
637
- return runtimeCanvasFactory(w, h);
748
+ // src/canvas-utils.ts
749
+ function drawRoundedRect(ctx, x, y, w, h, r) {
750
+ const radius = Math.max(0, Math.min(r, Math.min(w, h) / 2));
751
+ ctx.beginPath();
752
+ if (supportsRoundRect()) {
753
+ ctx.roundRect(x, y, w, h, radius);
754
+ } else {
755
+ ctx.moveTo(x + radius, y);
756
+ ctx.lineTo(x + w - radius, y);
757
+ ctx.quadraticCurveTo(x + w, y, x + w, y + radius);
758
+ ctx.lineTo(x + w, y + h - radius);
759
+ ctx.quadraticCurveTo(x + w, y + h, x + w - radius, y + h);
760
+ ctx.lineTo(x + radius, y + h);
761
+ ctx.quadraticCurveTo(x, y + h, x, y + h - radius);
762
+ ctx.lineTo(x, y + radius);
763
+ ctx.quadraticCurveTo(x, y, x + radius, y);
638
764
  }
639
- try {
640
- const nodeRequire = (0, eval)("require");
641
- const nodeCanvas = nodeRequire("@napi-rs/canvas");
642
- return nodeCanvas.createCanvas(w, h);
643
- } catch {
644
- throw new Error("No canvas implementation found in this environment.");
765
+ }
766
+ function applyLetterSpacing(ctx, value) {
767
+ const prev = ctx.letterSpacing ?? "0px";
768
+ if (value !== 0) {
769
+ ctx.letterSpacing = `${value}px`;
645
770
  }
771
+ return prev;
772
+ }
773
+ function restoreLetterSpacing(ctx, saved) {
774
+ ctx.letterSpacing = saved;
646
775
  }
776
+
777
+ // src/renderer.ts
647
778
  function getCanvas2DContext2(canvas) {
648
779
  return canvas.getContext("2d");
649
780
  }
650
- function hexToRgb2(hex) {
651
- const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
652
- const fullHex = hex.replace(shorthandRegex, (m, r, g, b) => r + r + g + g + b + b);
653
- const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(fullHex);
654
- return result ? {
655
- r: parseInt(result[1], 16),
656
- g: parseInt(result[2], 16),
657
- b: parseInt(result[3], 16)
658
- } : { r: 255, g: 255, b: 255 };
659
- }
660
781
  function renderTextEffectCore(ctx, cfg) {
661
782
  if (cfg.customRenderer === "InkBrushEngine") {
662
783
  const engine = new InkBrushEngine(cfg);
@@ -666,8 +787,8 @@ function renderTextEffectCore(ctx, cfg) {
666
787
  const { text, fontFamily, fontWeight, fontStyle, fontSize, letterSpacing, lineHeight, fillType, fillColor, fillGradientAngle, fillGradientStops, patternType, strokeEnabled, strokeColor, strokeWidth, strokePosition, strokeOpacity, strokeLineJoin, strokeBlur, strokeType, strokeColorSecondary, strokeWidthSecondary, strokeFadeRange, glowLayers, shadowEnabled, shadowColor, shadowBlur, shadowOffsetX, shadowOffsetY, shadowOpacity, shadowType, bevelEnabled, bevelDepth, bevelHighlight, bevelShadow, bevelDirection, bevelCoreColor, bevelEdgeColor, bevelEdgeWidth, bevelBlur, bevelBlurColor, bevelPerspectiveEnabled, bevelVanishingPointX, bevelVanishingPointY, bevelFocalLength, stackEnabled, stackCount, stackOffsetX, stackOffsetY, stackOpacityDecay, stackColor1, stackColor2, stackColor3, stackColor4, panelEnabled, panelColor, panelOpacity, panelRadius, panelPaddingX, panelPaddingY, panelStrokeEnabled, panelStrokeColor, panelStrokeWidth, canvasWidth, canvasHeight, textPosX, textPosY } = cfg;
667
788
  ctx.imageSmoothingEnabled = true;
668
789
  ctx.lineJoin = strokeLineJoin;
669
- const cWidth = canvasWidth || 800;
670
- const cHeight = canvasHeight || 200;
790
+ const cWidth = canvasWidth || DEFAULT_CANVAS_WIDTH;
791
+ const cHeight = canvasHeight || DEFAULT_CANVAS_HEIGHT;
671
792
  const layout = computeTextLayout(ctx, cfg, {
672
793
  wrap: cfg.wrapText !== false,
673
794
  autoFit: !!cfg.autoFitText
@@ -879,7 +1000,7 @@ function renderTextEffectCore(ctx, cfg) {
879
1000
  }
880
1001
  }
881
1002
  } else {
882
- ctx.roundRect(px, py, pw, ph, panelRadius);
1003
+ drawRoundedRect(ctx, px, py, pw, ph, panelRadius);
883
1004
  }
884
1005
  ctx.closePath();
885
1006
  ctx.fill();
@@ -942,9 +1063,9 @@ function renderTextEffectCore(ctx, cfg) {
942
1063
  ctx.restore();
943
1064
  }
944
1065
  if (bevelEnabled && bevelDepth > 0) {
945
- const shadowRgb = hexToRgb2(bevelShadow || "#1A0A00");
946
- const coreRgb = hexToRgb2(bevelCoreColor || bevelShadow || "#3A1A00");
947
- const highlightRgb = hexToRgb2(bevelHighlight || "#FFFFFF");
1066
+ const shadowRgb = hexToRgb(bevelShadow || "#1A0A00");
1067
+ const coreRgb = hexToRgb(bevelCoreColor || bevelShadow || "#3A1A00");
1068
+ const highlightRgb = hexToRgb(bevelHighlight || "#FFFFFF");
948
1069
  const shadeForDepth = (t) => {
949
1070
  const eased = t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
950
1071
  if (eased <= 0.5) {
@@ -985,7 +1106,7 @@ function renderTextEffectCore(ctx, cfg) {
985
1106
  const t = 1 - (i - 1) / Math.max(1, bevelDepth - 1);
986
1107
  const aoFactor = 0.35 + 0.65 * (1 - (i - 1) / Math.max(1, bevelDepth));
987
1108
  const baseColor = shadeForDepth(t);
988
- const bRgb = hexToRgb2(baseColor.startsWith("#") ? baseColor : "#000000");
1109
+ const bRgb = hexToRgb(baseColor.startsWith("#") ? baseColor : "#000000");
989
1110
  const baseRgbParsed = (() => {
990
1111
  const m = baseColor.match(/rgb\((\d+),(\d+),(\d+)\)/);
991
1112
  return m ? { r: +m[1], g: +m[2], b: +m[3] } : bRgb;
@@ -1078,7 +1199,7 @@ function renderTextEffectCore(ctx, cfg) {
1078
1199
  let customStrokeStyle = strokeColor;
1079
1200
  if (sFadeRange > 0) {
1080
1201
  const grad = ctx.createLinearGradient(0, yMin, 0, yMax);
1081
- const rgb = hexToRgb2(strokeColor);
1202
+ const rgb = hexToRgb(strokeColor);
1082
1203
  grad.addColorStop(0, `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${strokeOpacity / 100})`);
1083
1204
  const fadeLimit = Math.min(1, sFadeRange / 100);
1084
1205
  grad.addColorStop(fadeLimit, `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0)`);
@@ -1188,7 +1309,7 @@ function renderTextEffectCore(ctx, cfg) {
1188
1309
  } else if (fillType === "pattern") {
1189
1310
  const pType = patternType || "chalk";
1190
1311
  const patColor = fillColor || "#ffffff";
1191
- const patCanvas = createCanvas2(128, 128);
1312
+ const patCanvas = createCanvas(128, 128);
1192
1313
  if (pType === "carbon") {
1193
1314
  patCanvas.width = 8;
1194
1315
  patCanvas.height = 8;
@@ -1622,7 +1743,7 @@ function renderTextEffectCore(ctx, cfg) {
1622
1743
  };
1623
1744
  const isInkStyle = cfg.effectName.toLowerCase().includes("ink") || cfg.fontFamily.toLowerCase().includes("brush") || cfg.effectName.toLowerCase().includes("grunge") || cfg.effectName.toLowerCase().includes("scratch") || cfg.fontFamily === "Permanent Marker";
1624
1745
  if (isInkStyle) {
1625
- const tCanvas = createCanvas2(cWidth, cHeight);
1746
+ const tCanvas = createCanvas(cWidth, cHeight);
1626
1747
  tCanvas.width = cWidth;
1627
1748
  tCanvas.height = cHeight;
1628
1749
  const tCtx = getCanvas2DContext2(tCanvas);
@@ -1751,7 +1872,7 @@ function renderTextEffectCore(ctx, cfg) {
1751
1872
  }
1752
1873
  tCtx.letterSpacing = originalLSpacing;
1753
1874
  ctx.save();
1754
- const tintCanvas = createCanvas2(cWidth, cHeight);
1875
+ const tintCanvas = createCanvas(cWidth, cHeight);
1755
1876
  tintCanvas.width = cWidth;
1756
1877
  tintCanvas.height = cHeight;
1757
1878
  const tintCtx = getCanvas2DContext2(tintCanvas);
@@ -1822,7 +1943,7 @@ var defaultConfig = {
1822
1943
  fontFamily: "Poppins",
1823
1944
  fontWeight: 700,
1824
1945
  fontStyle: "normal",
1825
- fontSize: 80,
1946
+ fontSize: DEFAULT_FONT_SIZE,
1826
1947
  letterSpacing: 4,
1827
1948
  lineHeight: 1.2,
1828
1949
  fillType: "solid",
@@ -1882,8 +2003,8 @@ var defaultConfig = {
1882
2003
  panelStrokeEnabled: false,
1883
2004
  panelStrokeColor: "#2A2A38",
1884
2005
  panelStrokeWidth: 2,
1885
- canvasWidth: 800,
1886
- canvasHeight: 200,
2006
+ canvasWidth: DEFAULT_CANVAS_WIDTH,
2007
+ canvasHeight: DEFAULT_CANVAS_HEIGHT,
1887
2008
  textPosX: "center",
1888
2009
  textPosY: "middle",
1889
2010
  wrapText: true,
@@ -2233,42 +2354,6 @@ function checkFontVariant(variantName) {
2233
2354
  return metrics.width > 0;
2234
2355
  }
2235
2356
 
2236
- // src/engine/schema.ts
2237
- var SCENE_VERSION = 1;
2238
- var CUSTOM_ENGINE_IDS = ["ink"];
2239
- var LEGACY_RENDERER_MAP = {
2240
- InkBrushEngine: "ink"
2241
- };
2242
- var ENGINE_ID_TO_LEGACY = {
2243
- ink: "InkBrushEngine"
2244
- };
2245
- function createEmptyScene(overrides) {
2246
- return {
2247
- version: SCENE_VERSION,
2248
- effectName: "My Effect",
2249
- canvas: { width: 800, height: 200, background: "transparent" },
2250
- text: {
2251
- content: "CLYPRA",
2252
- fontFamily: "Poppins",
2253
- fontWeight: 700,
2254
- fontStyle: "normal",
2255
- fontSize: 80,
2256
- letterSpacing: 4,
2257
- lineHeight: 1.2,
2258
- textPosX: "center",
2259
- textPosY: "middle"
2260
- },
2261
- effectLayers: [],
2262
- customEngineId: null,
2263
- compositor: { blur: 0, bloom: 0, bloomThreshold: 0.6 },
2264
- timeline: { duration: 2, fps: 30, loop: true, tracks: [] },
2265
- ...overrides
2266
- };
2267
- }
2268
- function newLayerId() {
2269
- return `layer-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 7)}`;
2270
- }
2271
-
2272
2357
  // src/engine/timelineDefaults.ts
2273
2358
  function ensureDefaultTimeline(doc) {
2274
2359
  if (doc.timeline.tracks.length > 0) return doc;
@@ -2927,8 +3012,8 @@ function getCompositor() {
2927
3012
  function evaluateScene(doc, time, ctx, options = {}) {
2928
3013
  const animated = applyTimelineAtTime(doc, time);
2929
3014
  const cfg = sceneToConfig(animated);
2930
- const w = cfg.canvasWidth || 800;
2931
- const h = cfg.canvasHeight || 200;
3015
+ const w = cfg.canvasWidth || DEFAULT_CANVAS_WIDTH;
3016
+ const h = cfg.canvasHeight || DEFAULT_CANVAS_HEIGHT;
2932
3017
  const filterLayers = animated.effectLayers.filter((l) => l.type === "filter" && l.enabled);
2933
3018
  const lastFilter = filterLayers[filterLayers.length - 1]?.params;
2934
3019
  const comp = {
@@ -2944,8 +3029,8 @@ function evaluateScene(doc, time, ctx, options = {}) {
2944
3029
  finishFrame();
2945
3030
  return;
2946
3031
  }
2947
- const off = typeof OffscreenCanvas !== "undefined" ? new OffscreenCanvas(w, h) : null;
2948
- if (off) {
3032
+ if (supportsOffscreenCanvas()) {
3033
+ const off = new OffscreenCanvas(w, h);
2949
3034
  const offCtx = off.getContext("2d");
2950
3035
  if (!offCtx) {
2951
3036
  renderTextEffectCore(ctx, cfg);
@@ -2974,10 +3059,14 @@ function evaluateScene(doc, time, ctx, options = {}) {
2974
3059
  const compositor = options.compositor ?? getCompositor();
2975
3060
  if (compositor?.isSupported) {
2976
3061
  compositor.renderToContext(ctx, temp, comp);
3062
+ temp.width = 0;
3063
+ temp.height = 0;
2977
3064
  return;
2978
3065
  }
2979
3066
  ctx.clearRect(0, 0, w, h);
2980
3067
  ctx.drawImage(temp, 0, 0);
3068
+ temp.width = 0;
3069
+ temp.height = 0;
2981
3070
  return;
2982
3071
  }
2983
3072
  }
@@ -2988,9 +3077,9 @@ function evaluateConfig(cfg, time, ctx, options) {
2988
3077
  evaluateScene(textEffectConfigToScene(cfg), time, ctx, options);
2989
3078
  }
2990
3079
  function advanceSceneTime(doc, steps) {
2991
- const dt = 1 / (doc.timeline.fps || 30);
3080
+ const dt = 1 / (doc.timeline.fps || DEFAULT_FPS);
2992
3081
  const next = doc._time ?? 0;
2993
- const duration = doc.timeline.duration || 2;
3082
+ const duration = doc.timeline.duration || DEFAULT_DURATION;
2994
3083
  let t = next + steps * dt;
2995
3084
  if (doc.timeline.loop) {
2996
3085
  t = duration > 0 ? t % duration : t;
@@ -5947,6 +6036,11 @@ function duplicateTrackAtPlayhead(doc, trackIndex, previewTime) {
5947
6036
  export {
5948
6037
  COMPOSITION_PRESETS,
5949
6038
  CUSTOM_ENGINE_IDS,
6039
+ DEFAULT_CANVAS_HEIGHT,
6040
+ DEFAULT_CANVAS_WIDTH,
6041
+ DEFAULT_DURATION,
6042
+ DEFAULT_FONT_SIZE,
6043
+ DEFAULT_FPS,
5950
6044
  DEFAULT_TEXT_STYLE,
5951
6045
  EMPHASIS_PRESETS,
5952
6046
  ENGINE_ID_TO_LEGACY,
@@ -5964,6 +6058,7 @@ export {
5964
6058
  TextEffectRenderer,
5965
6059
  WEBM_EXPORT_MAX_FRAMES,
5966
6060
  WebGLCompositor,
6061
+ _resetPlatformCache,
5967
6062
  addImageLayer,
5968
6063
  addKeyframeAtTime,
5969
6064
  addOrUpdateKeyframe,
@@ -5975,6 +6070,7 @@ export {
5975
6070
  advanceSceneTime,
5976
6071
  alignToLottieJ,
5977
6072
  applyFillColorToAll,
6073
+ applyLetterSpacing,
5978
6074
  applyMaskReveal,
5979
6075
  applyRecipeToScene,
5980
6076
  applyStyleToLottie,
@@ -6000,6 +6096,7 @@ export {
6000
6096
  computeTextLayout,
6001
6097
  countTextGlyphs,
6002
6098
  createBlankLottie,
6099
+ createCanvas,
6003
6100
  createDefaultRevealTrack,
6004
6101
  createEmptyScene,
6005
6102
  createPulseOpacityTrack,
@@ -6010,6 +6107,7 @@ export {
6010
6107
  downloadPngSequenceZip,
6011
6108
  downloadSceneWebM,
6012
6109
  drawPerCharText,
6110
+ drawRoundedRect,
6013
6111
  duplicateTrackAtPlayhead,
6014
6112
  ease,
6015
6113
  enableKeyframing,
@@ -6057,6 +6155,7 @@ export {
6057
6155
  readLayerScalar,
6058
6156
  readStyleFromLottieLayer,
6059
6157
  reindexLayers,
6158
+ releaseCanvas,
6060
6159
  removeKeyframe,
6061
6160
  removeTrack,
6062
6161
  renderPngSequence,
@@ -6066,6 +6165,7 @@ export {
6066
6165
  resizeCharFillColors,
6067
6166
  resolveAnimatedScalar,
6068
6167
  resolveCustomEngineId,
6168
+ restoreLetterSpacing,
6069
6169
  scanLottieFonts,
6070
6170
  scanTextLayers,
6071
6171
  sceneToConfig,
@@ -6075,6 +6175,11 @@ export {
6075
6175
  shouldUsePerCharFill,
6076
6176
  snapshotScene,
6077
6177
  sortKeyframes,
6178
+ supportsCtxFilter,
6179
+ supportsLetterSpacing,
6180
+ supportsOffscreenCanvas,
6181
+ supportsRoundRect,
6182
+ supportsWebGL2,
6078
6183
  syncCompositorFromScene,
6079
6184
  textEffectConfigToScene,
6080
6185
  trackId,