@clypra/engine 1.1.1 → 1.1.2

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
@@ -21,6 +21,7 @@ var index_exports = {};
21
21
  __export(index_exports, {
22
22
  COMPOSITION_PRESETS: () => COMPOSITION_PRESETS,
23
23
  CUSTOM_ENGINE_IDS: () => CUSTOM_ENGINE_IDS,
24
+ CanvasDevice: () => CanvasDevice,
24
25
  DEFAULT_CANVAS_HEIGHT: () => DEFAULT_CANVAS_HEIGHT,
25
26
  DEFAULT_CANVAS_WIDTH: () => DEFAULT_CANVAS_WIDTH,
26
27
  DEFAULT_DURATION: () => DEFAULT_DURATION,
@@ -32,6 +33,7 @@ __export(index_exports, {
32
33
  ENTRANCE_PRESETS: () => ENTRANCE_PRESETS,
33
34
  EXIT_PRESETS: () => EXIT_PRESETS,
34
35
  FONT_WEIGHT_OPTIONS: () => FONT_WEIGHT_OPTIONS,
36
+ FontLoader: () => FontLoader,
35
37
  InkBrushEngine: () => InkBrushEngine,
36
38
  LEGACY_RENDERER_MAP: () => LEGACY_RENDERER_MAP,
37
39
  LOOP_PRESETS: () => LOOP_PRESETS,
@@ -43,6 +45,7 @@ __export(index_exports, {
43
45
  TextEffectRenderer: () => TextEffectRenderer,
44
46
  WEBM_EXPORT_MAX_FRAMES: () => WEBM_EXPORT_MAX_FRAMES,
45
47
  WebGLCompositor: () => WebGLCompositor,
48
+ _buildConfig: () => _buildConfig,
46
49
  _resetPlatformCache: () => _resetPlatformCache,
47
50
  addImageLayer: () => addImageLayer,
48
51
  addKeyframeAtTime: () => addKeyframeAtTime,
@@ -100,6 +103,7 @@ __export(index_exports, {
100
103
  encodeGif: () => encodeGif,
101
104
  ensureDefaultTimeline: () => ensureDefaultTimeline,
102
105
  ensureFontInLottie: () => ensureFontInLottie,
106
+ ensureFontsLoaded: () => ensureFontsLoaded,
103
107
  evaluateConfig: () => evaluateConfig,
104
108
  evaluateScene: () => evaluateScene,
105
109
  findTrackIndex: () => findTrackIndex,
@@ -107,6 +111,7 @@ __export(index_exports, {
107
111
  getAnimatableParamDef: () => getAnimatableParamDef,
108
112
  getAnimatableParamsForLayer: () => getAnimatableParamsForLayer,
109
113
  getDefaultText: () => getDefaultText,
114
+ getFontLoader: () => getFontLoader,
110
115
  getLayerById: () => getLayerById,
111
116
  getPresetScene: () => getPresetScene,
112
117
  getSceneTime: () => getSceneTime,
@@ -125,6 +130,7 @@ __export(index_exports, {
125
130
  injectText: () => injectText,
126
131
  injectTextStyle: () => injectTextStyle,
127
132
  isWebMExportSupported: () => isWebMExportSupported,
133
+ layerToTextEffectConfig: () => layerToTextEffectConfig,
128
134
  loadLottieFonts: () => loadLottieFonts,
129
135
  lottieColorToHex: () => lottieColorToHex,
130
136
  lottieJToAlign: () => lottieJToAlign,
@@ -147,10 +153,12 @@ __export(index_exports, {
147
153
  renderPngSequence: () => renderPngSequence,
148
154
  renderSceneWebM: () => renderSceneWebM,
149
155
  renderTextEffectCore: () => renderTextEffectCore,
156
+ resetFontLoader: () => resetFontLoader,
150
157
  resetSceneTime: () => resetSceneTime,
151
158
  resizeCharFillColors: () => resizeCharFillColors,
152
159
  resolveAnimatedScalar: () => resolveAnimatedScalar,
153
160
  resolveCustomEngineId: () => resolveCustomEngineId,
161
+ resolveFontFamilyName: () => resolveFontFamilyName,
154
162
  restoreLetterSpacing: () => restoreLetterSpacing,
155
163
  scanLottieFonts: () => scanLottieFonts,
156
164
  scanTextLayers: () => scanTextLayers,
@@ -568,6 +576,46 @@ function _resetPlatformCache() {
568
576
  _offscreenCanvas = null;
569
577
  _webgl2 = null;
570
578
  }
579
+ var CanvasDevice = class {
580
+ static canvases = [];
581
+ static maxPoolSize = 10;
582
+ /**
583
+ * Acquire a Canvas context from the pool or create a new one.
584
+ * If a canvas is pulled from the pool, it is resized to the target dimensions.
585
+ */
586
+ static acquire(width, height) {
587
+ let canvas;
588
+ if (this.canvases.length > 0) {
589
+ canvas = this.canvases.pop();
590
+ if (canvas.width !== width || canvas.height !== height) {
591
+ canvas.width = width;
592
+ canvas.height = height;
593
+ }
594
+ } else {
595
+ canvas = createCanvas(width, height);
596
+ }
597
+ return canvas;
598
+ }
599
+ /**
600
+ * Release a canvas back to the pool, or free its resources immediately if pool is full.
601
+ */
602
+ static release(canvas) {
603
+ if (this.canvases.length < this.maxPoolSize) {
604
+ this.canvases.push(canvas);
605
+ } else {
606
+ releaseCanvas(canvas);
607
+ }
608
+ }
609
+ /**
610
+ * Disposes all pooled canvases to release GPU/memory backing stores.
611
+ */
612
+ static clearPool() {
613
+ while (this.canvases.length > 0) {
614
+ const c = this.canvases.pop();
615
+ releaseCanvas(c);
616
+ }
617
+ }
618
+ };
571
619
 
572
620
  // src/engine/procedural/utils.ts
573
621
  function getCanvas2DContext(canvas) {
@@ -2530,6 +2578,146 @@ function checkFontVariant(variantName) {
2530
2578
  if (typeof document === "undefined" || !document.fonts) return false;
2531
2579
  return document.fonts.check(`16px "${variantName}"`);
2532
2580
  }
2581
+ var FontLoader = class {
2582
+ state = {
2583
+ loading: /* @__PURE__ */ new Set(),
2584
+ loaded: /* @__PURE__ */ new Set(),
2585
+ failed: /* @__PURE__ */ new Map(),
2586
+ promises: /* @__PURE__ */ new Map()
2587
+ };
2588
+ async ensureFont(descriptor) {
2589
+ const key = this.getFontKey(descriptor);
2590
+ if (this.state.loaded.has(key)) {
2591
+ return {
2592
+ font: descriptor,
2593
+ loaded: true,
2594
+ loadTimeMs: 0
2595
+ };
2596
+ }
2597
+ if (this.state.failed.has(key)) {
2598
+ return {
2599
+ font: descriptor,
2600
+ loaded: false,
2601
+ error: this.state.failed.get(key),
2602
+ loadTimeMs: 0
2603
+ };
2604
+ }
2605
+ if (this.state.promises.has(key)) {
2606
+ return this.state.promises.get(key);
2607
+ }
2608
+ const promise = this.loadFont(descriptor);
2609
+ this.state.promises.set(key, promise);
2610
+ return promise;
2611
+ }
2612
+ async ensureFonts(descriptors) {
2613
+ return Promise.all(descriptors.map((desc) => this.ensureFont(desc)));
2614
+ }
2615
+ async waitForFontsReady() {
2616
+ if (typeof document === "undefined" || !document.fonts) {
2617
+ return;
2618
+ }
2619
+ await document.fonts.ready;
2620
+ }
2621
+ isLoaded(descriptor) {
2622
+ const key = this.getFontKey(descriptor);
2623
+ return this.state.loaded.has(key);
2624
+ }
2625
+ getStats() {
2626
+ return {
2627
+ loaded: this.state.loaded.size,
2628
+ loading: this.state.loading.size,
2629
+ failed: this.state.failed.size
2630
+ };
2631
+ }
2632
+ clear() {
2633
+ this.state.loading.clear();
2634
+ this.state.loaded.clear();
2635
+ this.state.failed.clear();
2636
+ this.state.promises.clear();
2637
+ }
2638
+ async loadFont(descriptor) {
2639
+ const key = this.getFontKey(descriptor);
2640
+ const startTime = performance.now();
2641
+ this.state.loading.add(key);
2642
+ try {
2643
+ if (typeof document === "undefined" || !document.fonts) {
2644
+ throw new Error("Font API not available");
2645
+ }
2646
+ const weight = this.normalizeFontWeight(descriptor.weight);
2647
+ const style = descriptor.style || "normal";
2648
+ const fontFace = `${style} ${weight} 16px "${descriptor.family}"`;
2649
+ if (document.fonts.check(fontFace)) {
2650
+ this.state.loaded.add(key);
2651
+ this.state.loading.delete(key);
2652
+ this.state.promises.delete(key);
2653
+ return {
2654
+ font: descriptor,
2655
+ loaded: true,
2656
+ loadTimeMs: performance.now() - startTime
2657
+ };
2658
+ }
2659
+ await document.fonts.load(fontFace);
2660
+ if (!document.fonts.check(fontFace)) {
2661
+ throw new Error(`Font "${descriptor.family}" failed to load`);
2662
+ }
2663
+ this.state.loaded.add(key);
2664
+ this.state.loading.delete(key);
2665
+ this.state.promises.delete(key);
2666
+ return {
2667
+ font: descriptor,
2668
+ loaded: true,
2669
+ loadTimeMs: performance.now() - startTime
2670
+ };
2671
+ } catch (error) {
2672
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
2673
+ this.state.failed.set(key, errorMessage);
2674
+ this.state.loading.delete(key);
2675
+ this.state.promises.delete(key);
2676
+ return {
2677
+ font: descriptor,
2678
+ loaded: false,
2679
+ error: errorMessage,
2680
+ loadTimeMs: performance.now() - startTime
2681
+ };
2682
+ }
2683
+ }
2684
+ getFontKey(descriptor) {
2685
+ const weight = this.normalizeFontWeight(descriptor.weight);
2686
+ const style = descriptor.style || "normal";
2687
+ return `${descriptor.family}|${weight}|${style}`;
2688
+ }
2689
+ normalizeFontWeight(weight) {
2690
+ if (typeof weight === "number") {
2691
+ return weight;
2692
+ }
2693
+ if (!weight) return 400;
2694
+ const asNum = parseInt(weight, 10);
2695
+ if (!isNaN(asNum) && asNum >= 100 && asNum <= 900) {
2696
+ return asNum;
2697
+ }
2698
+ const weightMap = {
2699
+ normal: 400,
2700
+ bold: 700,
2701
+ lighter: 300,
2702
+ bolder: 700
2703
+ };
2704
+ return weightMap[weight] ?? 400;
2705
+ }
2706
+ };
2707
+ var globalFontLoader = null;
2708
+ function getFontLoader() {
2709
+ if (!globalFontLoader) {
2710
+ globalFontLoader = new FontLoader();
2711
+ }
2712
+ return globalFontLoader;
2713
+ }
2714
+ function resetFontLoader() {
2715
+ globalFontLoader = null;
2716
+ }
2717
+ async function ensureFontsLoaded(descriptors) {
2718
+ const loader = getFontLoader();
2719
+ return loader.ensureFonts(descriptors);
2720
+ }
2533
2721
 
2534
2722
  // src/engine/timelineDefaults.ts
2535
2723
  function ensureDefaultTimeline(doc) {
@@ -2901,6 +3089,212 @@ function mergeSceneIntoConfig(doc, base) {
2901
3089
  const out = sceneToConfig({ ...doc, legacyConfig: base });
2902
3090
  return out;
2903
3091
  }
3092
+ function resolveFontFamilyName(fontFamily) {
3093
+ const f = fontFamily?.toLowerCase() || "";
3094
+ if (f.includes("inter")) return "Inter Variable";
3095
+ if (f.includes("montserrat")) return "Montserrat Variable";
3096
+ if (f.includes("geist")) return "Geist Variable";
3097
+ if (f.includes("space grotesk") || f.includes("grotesk")) return "Space Grotesk Variable";
3098
+ if (f.includes("outfit")) return "Outfit Variable";
3099
+ if (f.includes("roboto variable")) return "Roboto Variable";
3100
+ if (f.includes("roboto condensed")) return "Roboto Condensed";
3101
+ if (f === "roboto") return "Roboto Variable";
3102
+ if (f.includes("open sans")) return "Open Sans Variable";
3103
+ if (f.includes("raleway")) return "Raleway Variable";
3104
+ if (f.includes("oswald")) return "Oswald Variable";
3105
+ if (f.includes("playfair display")) return "Playfair Display Variable";
3106
+ if (f.includes("nunito")) return "Nunito Variable";
3107
+ if (f.includes("dancing script")) return "Dancing Script Variable";
3108
+ if (f === "lato") return "Lato";
3109
+ if (f === "anton") return "Anton";
3110
+ if (f === "bebas neue") return "Bebas Neue";
3111
+ if (f === "poppins") return "Poppins";
3112
+ if (f === "permanent marker") return "Permanent Marker";
3113
+ if (f === "bangers") return "Bangers";
3114
+ if (f === "press start 2p") return "Press Start 2P";
3115
+ if (f === "pacifico") return "Pacifico";
3116
+ return fontFamily;
3117
+ }
3118
+ function _buildConfig(effect, text, fontSize, canvasWidth, canvasHeight, time, clipStartTime, clipDuration) {
3119
+ const fill = effect.fills?.[0];
3120
+ const stroke = effect.strokes?.[0];
3121
+ const shadow = effect.shadows?.[0];
3122
+ const bevel = effect.bevel;
3123
+ const panel = effect.panel;
3124
+ const ratio = fontSize / 100;
3125
+ const config = {
3126
+ // Canvas / text
3127
+ width: canvasWidth,
3128
+ height: canvasHeight,
3129
+ canvasWidth,
3130
+ canvasHeight,
3131
+ text,
3132
+ time: time ?? 0,
3133
+ clipStartTime: clipStartTime ?? 0,
3134
+ clipDuration: clipDuration ?? 5,
3135
+ // Font
3136
+ fontFamily: resolveFontFamilyName(effect.font.family),
3137
+ fontWeight: effect.font.weight,
3138
+ fontStyle: effect.font.style,
3139
+ fontSize,
3140
+ letterSpacing: effect.font.letterSpacing,
3141
+ lineHeight: effect.font.lineHeight
3142
+ };
3143
+ if (effect.animation) {
3144
+ config.animation = effect.animation;
3145
+ }
3146
+ if (fill) {
3147
+ if (fill.type !== void 0) config.fillType = fill.type;
3148
+ if (fill.color !== void 0) config.fillColor = fill.color;
3149
+ if (fill.gradient?.angle !== void 0) config.fillGradientAngle = fill.gradient.angle;
3150
+ if (fill.gradient?.stops !== void 0) config.fillGradientStops = fill.gradient.stops;
3151
+ if (fill.patternType !== void 0) config.patternType = fill.patternType;
3152
+ if (fill.perCharFillEnabled !== void 0) config.perCharFillEnabled = fill.perCharFillEnabled;
3153
+ if (fill.charFillColors !== void 0) config.charFillColors = fill.charFillColors;
3154
+ } else {
3155
+ config.fillType = "none";
3156
+ }
3157
+ config.strokeEnabled = !!stroke;
3158
+ if (stroke) {
3159
+ if (stroke.color !== void 0) config.strokeColor = stroke.color;
3160
+ if (stroke.width !== void 0) config.strokeWidth = stroke.width * ratio;
3161
+ if (stroke.position !== void 0) config.strokePosition = stroke.position;
3162
+ if (stroke.opacity !== void 0) config.strokeOpacity = stroke.opacity;
3163
+ if (stroke.lineJoin !== void 0) config.strokeLineJoin = stroke.lineJoin;
3164
+ if (stroke.blur !== void 0) config.strokeBlur = stroke.blur * ratio;
3165
+ if (stroke.type !== void 0) config.strokeType = stroke.type;
3166
+ if (stroke.colorSecondary !== void 0) config.strokeColorSecondary = stroke.colorSecondary;
3167
+ if (stroke.widthSecondary !== void 0) config.strokeWidthSecondary = stroke.widthSecondary * ratio;
3168
+ if (stroke.fadeRange !== void 0) config.strokeFadeRange = stroke.fadeRange;
3169
+ }
3170
+ config.shadowEnabled = !!shadow;
3171
+ if (shadow) {
3172
+ if (shadow.color !== void 0) config.shadowColor = shadow.color;
3173
+ if (shadow.blur !== void 0) config.shadowBlur = shadow.blur * ratio;
3174
+ if (shadow.offsetX !== void 0) config.shadowOffsetX = shadow.offsetX * ratio;
3175
+ if (shadow.offsetY !== void 0) config.shadowOffsetY = shadow.offsetY * ratio;
3176
+ if (shadow.opacity !== void 0) config.shadowOpacity = shadow.opacity;
3177
+ if (shadow.type !== void 0) config.shadowType = shadow.type;
3178
+ }
3179
+ config.bevelEnabled = !!bevel;
3180
+ if (bevel) {
3181
+ if (bevel.depth !== void 0) config.bevelDepth = Math.round(bevel.depth * ratio);
3182
+ if (bevel.highlightColor !== void 0) config.bevelHighlight = bevel.highlightColor;
3183
+ if (bevel.shadowColor !== void 0) config.bevelShadow = bevel.shadowColor;
3184
+ if (bevel.direction !== void 0) config.bevelDirection = bevel.direction;
3185
+ if (bevel.coreColor !== void 0) config.bevelCoreColor = bevel.coreColor;
3186
+ if (bevel.edgeColor !== void 0) config.bevelEdgeColor = bevel.edgeColor;
3187
+ if (bevel.edgeWidth !== void 0) config.bevelEdgeWidth = bevel.edgeWidth * ratio;
3188
+ if (bevel.blur !== void 0) config.bevelBlur = bevel.blur * ratio;
3189
+ if (bevel.blurColor !== void 0) config.bevelBlurColor = bevel.blurColor;
3190
+ if (bevel.perspectiveEnabled !== void 0) config.bevelPerspectiveEnabled = bevel.perspectiveEnabled;
3191
+ if (bevel.vanishingPointX !== void 0) config.bevelVanishingPointX = bevel.vanishingPointX;
3192
+ if (bevel.vanishingPointY !== void 0) config.bevelVanishingPointY = bevel.vanishingPointY;
3193
+ if (bevel.focalLength !== void 0) config.bevelFocalLength = bevel.focalLength;
3194
+ }
3195
+ if (effect.stack) {
3196
+ config.stackEnabled = !!effect.stack.count;
3197
+ if (effect.stack.count !== void 0) config.stackCount = effect.stack.count;
3198
+ if (effect.stack.offsetX !== void 0) config.stackOffsetX = effect.stack.offsetX * ratio;
3199
+ if (effect.stack.offsetY !== void 0) config.stackOffsetY = effect.stack.offsetY * ratio;
3200
+ if (effect.stack.opacityDecay !== void 0) config.stackOpacityDecay = effect.stack.opacityDecay;
3201
+ if (effect.stack.color1 !== void 0) config.stackColor1 = effect.stack.color1;
3202
+ if (effect.stack.color2 !== void 0) config.stackColor2 = effect.stack.color2;
3203
+ if (effect.stack.color3 !== void 0) config.stackColor3 = effect.stack.color3;
3204
+ if (effect.stack.color4 !== void 0) config.stackColor4 = effect.stack.color4;
3205
+ }
3206
+ config.panelEnabled = !!panel;
3207
+ if (panel) {
3208
+ if (panel.color !== void 0) config.panelColor = panel.color;
3209
+ if (panel.opacity !== void 0) config.panelOpacity = panel.opacity;
3210
+ if (panel.radius !== void 0) config.panelRadius = panel.radius;
3211
+ if (panel.paddingX !== void 0) config.panelPaddingX = panel.paddingX * ratio;
3212
+ if (panel.paddingY !== void 0) config.panelPaddingY = panel.paddingY * ratio;
3213
+ if (panel.stroke !== void 0) {
3214
+ config.panelStrokeEnabled = !!panel.stroke;
3215
+ if (panel.stroke.color !== void 0) config.panelStrokeColor = panel.stroke.color;
3216
+ if (panel.stroke.width !== void 0) config.panelStrokeWidth = panel.stroke.width * ratio;
3217
+ }
3218
+ }
3219
+ if (effect.glows) {
3220
+ config.glowLayers = effect.glows.map((g) => {
3221
+ const mappedGlow = {
3222
+ enabled: true,
3223
+ color: g.color,
3224
+ blur: typeof g.blur === "number" ? g.blur * ratio : g.blur ?? 0,
3225
+ opacity: g.opacity,
3226
+ type: g.type ?? "outer"
3227
+ };
3228
+ if (g.strength !== void 0) mappedGlow.strength = g.strength;
3229
+ if (g.spread !== void 0) mappedGlow.spread = g.spread * ratio;
3230
+ return mappedGlow;
3231
+ });
3232
+ }
3233
+ const standardKeys = /* @__PURE__ */ new Set([
3234
+ "id",
3235
+ "name",
3236
+ "category",
3237
+ "description",
3238
+ "tags",
3239
+ "font",
3240
+ "fills",
3241
+ "strokes",
3242
+ "shadows",
3243
+ "glows",
3244
+ "bevel",
3245
+ "panel",
3246
+ "text",
3247
+ "animation",
3248
+ "stack"
3249
+ ]);
3250
+ for (const key of Object.keys(effect)) {
3251
+ if (!standardKeys.has(key)) {
3252
+ config[key] = effect[key];
3253
+ }
3254
+ }
3255
+ return config;
3256
+ }
3257
+ function layerToTextEffectConfig(layer2) {
3258
+ const normWeight = typeof layer2.fontWeight === "number" ? layer2.fontWeight : layer2.fontWeight === "bold" ? 700 : 400;
3259
+ const config = {
3260
+ ...defaultConfig,
3261
+ width: layer2.width,
3262
+ height: layer2.height,
3263
+ canvasWidth: layer2.width,
3264
+ canvasHeight: layer2.height,
3265
+ text: layer2.text,
3266
+ fontFamily: resolveFontFamilyName(layer2.fontFamily),
3267
+ fontWeight: normWeight,
3268
+ fontStyle: layer2.fontStyle || "normal",
3269
+ fontSize: layer2.fontSize,
3270
+ letterSpacing: layer2.letterSpacing ?? 0,
3271
+ lineHeight: layer2.lineHeight ?? 1.2,
3272
+ fillType: layer2.color ? "solid" : "none",
3273
+ fillColor: layer2.color ?? "#FFFFFF",
3274
+ strokeEnabled: !!layer2.stroke,
3275
+ strokeColor: layer2.stroke?.color ?? "#000000",
3276
+ strokeWidth: layer2.stroke?.width ?? 0,
3277
+ strokePosition: "center",
3278
+ strokeOpacity: 100,
3279
+ strokeLineJoin: "round",
3280
+ shadowEnabled: !!layer2.shadow,
3281
+ shadowColor: layer2.shadow?.color ?? "#000000",
3282
+ shadowBlur: layer2.shadow?.blur ?? 0,
3283
+ shadowOffsetX: layer2.shadow?.offsetX ?? 0,
3284
+ shadowOffsetY: layer2.shadow?.offsetY ?? 0,
3285
+ shadowOpacity: 100,
3286
+ shadowType: "drop",
3287
+ panelEnabled: !!layer2.background,
3288
+ panelColor: layer2.background?.color ?? "#1E1E26",
3289
+ panelOpacity: 80,
3290
+ panelRadius: layer2.background?.borderRadius ?? 6,
3291
+ panelPaddingX: layer2.background?.padding ?? 12,
3292
+ panelPaddingY: layer2.background?.padding ?? 12,
3293
+ textPosX: layer2.textAlign || "center",
3294
+ textPosY: layer2.verticalAlign === "middle" ? "middle" : layer2.verticalAlign || "middle"
3295
+ };
3296
+ return config;
3297
+ }
2904
3298
 
2905
3299
  // src/engine/animation.ts
2906
3300
  function ease(t, kind = "linear") {
@@ -3210,47 +3604,23 @@ function evaluateScene(doc, time, ctx, options = {}) {
3210
3604
  finishFrame();
3211
3605
  return;
3212
3606
  }
3213
- if (supportsOffscreenCanvas()) {
3214
- const off = new OffscreenCanvas(w, h);
3215
- const offCtx = off.getContext("2d");
3216
- if (!offCtx) {
3217
- renderTextEffectCore(ctx, cfg);
3218
- finishFrame();
3219
- return;
3220
- }
3221
- renderTextEffectCore(offCtx, cfg);
3222
- applyMaskReveal(offCtx, animated, w, h);
3607
+ const temp = CanvasDevice.acquire(w, h);
3608
+ const tctx = temp.getContext("2d");
3609
+ if (tctx) {
3610
+ tctx.clearRect(0, 0, w, h);
3611
+ renderTextEffectCore(tctx, cfg);
3612
+ applyMaskReveal(tctx, animated, w, h);
3223
3613
  const compositor = options.compositor ?? getCompositor();
3224
3614
  if (compositor?.isSupported) {
3225
- compositor.renderToContext(ctx, off, comp);
3226
- return;
3227
- }
3228
- ctx.clearRect(0, 0, w, h);
3229
- ctx.drawImage(off, 0, 0);
3230
- return;
3231
- }
3232
- if (typeof document !== "undefined") {
3233
- const temp = document.createElement("canvas");
3234
- temp.width = w;
3235
- temp.height = h;
3236
- const tctx = temp.getContext("2d");
3237
- if (tctx) {
3238
- renderTextEffectCore(tctx, cfg);
3239
- applyMaskReveal(tctx, animated, w, h);
3240
- const compositor = options.compositor ?? getCompositor();
3241
- if (compositor?.isSupported) {
3242
- compositor.renderToContext(ctx, temp, comp);
3243
- temp.width = 0;
3244
- temp.height = 0;
3245
- return;
3246
- }
3615
+ compositor.renderToContext(ctx, temp, comp);
3616
+ } else {
3247
3617
  ctx.clearRect(0, 0, w, h);
3248
3618
  ctx.drawImage(temp, 0, 0);
3249
- temp.width = 0;
3250
- temp.height = 0;
3251
- return;
3252
3619
  }
3620
+ CanvasDevice.release(temp);
3621
+ return;
3253
3622
  }
3623
+ CanvasDevice.release(temp);
3254
3624
  renderTextEffectCore(ctx, cfg);
3255
3625
  finishFrame();
3256
3626
  }
@@ -6218,6 +6588,7 @@ function duplicateTrackAtPlayhead(doc, trackIndex, previewTime) {
6218
6588
  0 && (module.exports = {
6219
6589
  COMPOSITION_PRESETS,
6220
6590
  CUSTOM_ENGINE_IDS,
6591
+ CanvasDevice,
6221
6592
  DEFAULT_CANVAS_HEIGHT,
6222
6593
  DEFAULT_CANVAS_WIDTH,
6223
6594
  DEFAULT_DURATION,
@@ -6229,6 +6600,7 @@ function duplicateTrackAtPlayhead(doc, trackIndex, previewTime) {
6229
6600
  ENTRANCE_PRESETS,
6230
6601
  EXIT_PRESETS,
6231
6602
  FONT_WEIGHT_OPTIONS,
6603
+ FontLoader,
6232
6604
  InkBrushEngine,
6233
6605
  LEGACY_RENDERER_MAP,
6234
6606
  LOOP_PRESETS,
@@ -6240,6 +6612,7 @@ function duplicateTrackAtPlayhead(doc, trackIndex, previewTime) {
6240
6612
  TextEffectRenderer,
6241
6613
  WEBM_EXPORT_MAX_FRAMES,
6242
6614
  WebGLCompositor,
6615
+ _buildConfig,
6243
6616
  _resetPlatformCache,
6244
6617
  addImageLayer,
6245
6618
  addKeyframeAtTime,
@@ -6297,6 +6670,7 @@ function duplicateTrackAtPlayhead(doc, trackIndex, previewTime) {
6297
6670
  encodeGif,
6298
6671
  ensureDefaultTimeline,
6299
6672
  ensureFontInLottie,
6673
+ ensureFontsLoaded,
6300
6674
  evaluateConfig,
6301
6675
  evaluateScene,
6302
6676
  findTrackIndex,
@@ -6304,6 +6678,7 @@ function duplicateTrackAtPlayhead(doc, trackIndex, previewTime) {
6304
6678
  getAnimatableParamDef,
6305
6679
  getAnimatableParamsForLayer,
6306
6680
  getDefaultText,
6681
+ getFontLoader,
6307
6682
  getLayerById,
6308
6683
  getPresetScene,
6309
6684
  getSceneTime,
@@ -6322,6 +6697,7 @@ function duplicateTrackAtPlayhead(doc, trackIndex, previewTime) {
6322
6697
  injectText,
6323
6698
  injectTextStyle,
6324
6699
  isWebMExportSupported,
6700
+ layerToTextEffectConfig,
6325
6701
  loadLottieFonts,
6326
6702
  lottieColorToHex,
6327
6703
  lottieJToAlign,
@@ -6344,10 +6720,12 @@ function duplicateTrackAtPlayhead(doc, trackIndex, previewTime) {
6344
6720
  renderPngSequence,
6345
6721
  renderSceneWebM,
6346
6722
  renderTextEffectCore,
6723
+ resetFontLoader,
6347
6724
  resetSceneTime,
6348
6725
  resizeCharFillColors,
6349
6726
  resolveAnimatedScalar,
6350
6727
  resolveCustomEngineId,
6728
+ resolveFontFamilyName,
6351
6729
  restoreLetterSpacing,
6352
6730
  scanLottieFonts,
6353
6731
  scanTextLayers,