@clypra/engine 1.1.0 → 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 +426 -47
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +168 -4
- package/dist/index.d.ts +168 -4
- package/dist/index.js +417 -47
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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,
|
|
@@ -87,6 +90,7 @@ __export(index_exports, {
|
|
|
87
90
|
createPulseOpacityTrack: () => createPulseOpacityTrack,
|
|
88
91
|
defaultConfig: () => defaultConfig,
|
|
89
92
|
deleteKeyframe: () => deleteKeyframe,
|
|
93
|
+
disposeSharedCompositor: () => disposeSharedCompositor,
|
|
90
94
|
downloadDotLottie: () => downloadDotLottie,
|
|
91
95
|
downloadLottieJson: () => downloadLottieJson,
|
|
92
96
|
downloadPngSequenceZip: () => downloadPngSequenceZip,
|
|
@@ -99,6 +103,7 @@ __export(index_exports, {
|
|
|
99
103
|
encodeGif: () => encodeGif,
|
|
100
104
|
ensureDefaultTimeline: () => ensureDefaultTimeline,
|
|
101
105
|
ensureFontInLottie: () => ensureFontInLottie,
|
|
106
|
+
ensureFontsLoaded: () => ensureFontsLoaded,
|
|
102
107
|
evaluateConfig: () => evaluateConfig,
|
|
103
108
|
evaluateScene: () => evaluateScene,
|
|
104
109
|
findTrackIndex: () => findTrackIndex,
|
|
@@ -106,6 +111,7 @@ __export(index_exports, {
|
|
|
106
111
|
getAnimatableParamDef: () => getAnimatableParamDef,
|
|
107
112
|
getAnimatableParamsForLayer: () => getAnimatableParamsForLayer,
|
|
108
113
|
getDefaultText: () => getDefaultText,
|
|
114
|
+
getFontLoader: () => getFontLoader,
|
|
109
115
|
getLayerById: () => getLayerById,
|
|
110
116
|
getPresetScene: () => getPresetScene,
|
|
111
117
|
getSceneTime: () => getSceneTime,
|
|
@@ -124,6 +130,7 @@ __export(index_exports, {
|
|
|
124
130
|
injectText: () => injectText,
|
|
125
131
|
injectTextStyle: () => injectTextStyle,
|
|
126
132
|
isWebMExportSupported: () => isWebMExportSupported,
|
|
133
|
+
layerToTextEffectConfig: () => layerToTextEffectConfig,
|
|
127
134
|
loadLottieFonts: () => loadLottieFonts,
|
|
128
135
|
lottieColorToHex: () => lottieColorToHex,
|
|
129
136
|
lottieJToAlign: () => lottieJToAlign,
|
|
@@ -146,10 +153,12 @@ __export(index_exports, {
|
|
|
146
153
|
renderPngSequence: () => renderPngSequence,
|
|
147
154
|
renderSceneWebM: () => renderSceneWebM,
|
|
148
155
|
renderTextEffectCore: () => renderTextEffectCore,
|
|
156
|
+
resetFontLoader: () => resetFontLoader,
|
|
149
157
|
resetSceneTime: () => resetSceneTime,
|
|
150
158
|
resizeCharFillColors: () => resizeCharFillColors,
|
|
151
159
|
resolveAnimatedScalar: () => resolveAnimatedScalar,
|
|
152
160
|
resolveCustomEngineId: () => resolveCustomEngineId,
|
|
161
|
+
resolveFontFamilyName: () => resolveFontFamilyName,
|
|
153
162
|
restoreLetterSpacing: () => restoreLetterSpacing,
|
|
154
163
|
scanLottieFonts: () => scanLottieFonts,
|
|
155
164
|
scanTextLayers: () => scanTextLayers,
|
|
@@ -296,7 +305,7 @@ function layoutWithFontSize(ctx, cfg, fontSize, lines) {
|
|
|
296
305
|
ctx.font = fontStr;
|
|
297
306
|
const lineWidths = lines.map((line) => measureLine(ctx, line, letterSpacing));
|
|
298
307
|
const maxLineWidth = Math.max(...lineWidths, 1);
|
|
299
|
-
const textBlockHeight = fontSize
|
|
308
|
+
const textBlockHeight = lines.length === 1 ? fontSize : (lines.length - 1) * fontSize * lineHeight + fontSize;
|
|
300
309
|
let align = "center";
|
|
301
310
|
let startX = cWidth / 2;
|
|
302
311
|
if (cfg.textPosX === "left") {
|
|
@@ -557,9 +566,8 @@ function createCanvas(width, height) {
|
|
|
557
566
|
}
|
|
558
567
|
function releaseCanvas(canvas) {
|
|
559
568
|
if (canvas instanceof OffscreenCanvas) return;
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
}
|
|
569
|
+
canvas.width = 0;
|
|
570
|
+
canvas.height = 0;
|
|
563
571
|
}
|
|
564
572
|
function _resetPlatformCache() {
|
|
565
573
|
_ctxFilter = null;
|
|
@@ -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) {
|
|
@@ -2086,7 +2134,7 @@ function renderTextEffectCore(ctx, cfg) {
|
|
|
2086
2134
|
ctx.globalCompositeOperation = "source-atop";
|
|
2087
2135
|
const renderCount = Math.max(1, Math.min(20, layer2.strength ?? 1));
|
|
2088
2136
|
for (let i = 0; i < renderCount; i++) {
|
|
2089
|
-
renderWithShadowTrick("fill", layer2.color, layer2.blur, 0, 0, layer2.opacity, "
|
|
2137
|
+
renderWithShadowTrick("fill", layer2.color, layer2.blur, 0, 0, layer2.opacity, "#000000", layer2.spread ?? 0);
|
|
2090
2138
|
}
|
|
2091
2139
|
ctx.restore();
|
|
2092
2140
|
}
|
|
@@ -2094,7 +2142,7 @@ function renderTextEffectCore(ctx, cfg) {
|
|
|
2094
2142
|
if (shadowEnabled && shadowType === "inner" && shadowOpacity > 0) {
|
|
2095
2143
|
ctx.save();
|
|
2096
2144
|
ctx.globalCompositeOperation = "source-atop";
|
|
2097
|
-
renderWithShadowTrick("fill", shadowColor, shadowBlur, shadowOffsetX, shadowOffsetY, shadowOpacity, "
|
|
2145
|
+
renderWithShadowTrick("fill", shadowColor, shadowBlur, shadowOffsetX, shadowOffsetY, shadowOpacity, "#000000");
|
|
2098
2146
|
ctx.restore();
|
|
2099
2147
|
}
|
|
2100
2148
|
if (isGlitch) {
|
|
@@ -2527,12 +2575,148 @@ async function initializeFontSystem() {
|
|
|
2527
2575
|
}
|
|
2528
2576
|
}
|
|
2529
2577
|
function checkFontVariant(variantName) {
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2578
|
+
if (typeof document === "undefined" || !document.fonts) return false;
|
|
2579
|
+
return document.fonts.check(`16px "${variantName}"`);
|
|
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);
|
|
2536
2720
|
}
|
|
2537
2721
|
|
|
2538
2722
|
// src/engine/timelineDefaults.ts
|
|
@@ -2905,6 +3089,212 @@ function mergeSceneIntoConfig(doc, base) {
|
|
|
2905
3089
|
const out = sceneToConfig({ ...doc, legacyConfig: base });
|
|
2906
3090
|
return out;
|
|
2907
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
|
+
}
|
|
2908
3298
|
|
|
2909
3299
|
// src/engine/animation.ts
|
|
2910
3300
|
function ease(t, kind = "linear") {
|
|
@@ -3190,6 +3580,10 @@ function getCompositor() {
|
|
|
3190
3580
|
}
|
|
3191
3581
|
return sharedCompositor;
|
|
3192
3582
|
}
|
|
3583
|
+
function disposeSharedCompositor() {
|
|
3584
|
+
sharedCompositor?.dispose();
|
|
3585
|
+
sharedCompositor = null;
|
|
3586
|
+
}
|
|
3193
3587
|
function evaluateScene(doc, time, ctx, options = {}) {
|
|
3194
3588
|
const animated = applyTimelineAtTime(doc, time);
|
|
3195
3589
|
const cfg = sceneToConfig(animated);
|
|
@@ -3210,47 +3604,23 @@ function evaluateScene(doc, time, ctx, options = {}) {
|
|
|
3210
3604
|
finishFrame();
|
|
3211
3605
|
return;
|
|
3212
3606
|
}
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
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,
|
|
3226
|
-
|
|
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,
|
|
@@ -6284,6 +6657,7 @@ function duplicateTrackAtPlayhead(doc, trackIndex, previewTime) {
|
|
|
6284
6657
|
createPulseOpacityTrack,
|
|
6285
6658
|
defaultConfig,
|
|
6286
6659
|
deleteKeyframe,
|
|
6660
|
+
disposeSharedCompositor,
|
|
6287
6661
|
downloadDotLottie,
|
|
6288
6662
|
downloadLottieJson,
|
|
6289
6663
|
downloadPngSequenceZip,
|
|
@@ -6296,6 +6670,7 @@ function duplicateTrackAtPlayhead(doc, trackIndex, previewTime) {
|
|
|
6296
6670
|
encodeGif,
|
|
6297
6671
|
ensureDefaultTimeline,
|
|
6298
6672
|
ensureFontInLottie,
|
|
6673
|
+
ensureFontsLoaded,
|
|
6299
6674
|
evaluateConfig,
|
|
6300
6675
|
evaluateScene,
|
|
6301
6676
|
findTrackIndex,
|
|
@@ -6303,6 +6678,7 @@ function duplicateTrackAtPlayhead(doc, trackIndex, previewTime) {
|
|
|
6303
6678
|
getAnimatableParamDef,
|
|
6304
6679
|
getAnimatableParamsForLayer,
|
|
6305
6680
|
getDefaultText,
|
|
6681
|
+
getFontLoader,
|
|
6306
6682
|
getLayerById,
|
|
6307
6683
|
getPresetScene,
|
|
6308
6684
|
getSceneTime,
|
|
@@ -6321,6 +6697,7 @@ function duplicateTrackAtPlayhead(doc, trackIndex, previewTime) {
|
|
|
6321
6697
|
injectText,
|
|
6322
6698
|
injectTextStyle,
|
|
6323
6699
|
isWebMExportSupported,
|
|
6700
|
+
layerToTextEffectConfig,
|
|
6324
6701
|
loadLottieFonts,
|
|
6325
6702
|
lottieColorToHex,
|
|
6326
6703
|
lottieJToAlign,
|
|
@@ -6343,10 +6720,12 @@ function duplicateTrackAtPlayhead(doc, trackIndex, previewTime) {
|
|
|
6343
6720
|
renderPngSequence,
|
|
6344
6721
|
renderSceneWebM,
|
|
6345
6722
|
renderTextEffectCore,
|
|
6723
|
+
resetFontLoader,
|
|
6346
6724
|
resetSceneTime,
|
|
6347
6725
|
resizeCharFillColors,
|
|
6348
6726
|
resolveAnimatedScalar,
|
|
6349
6727
|
resolveCustomEngineId,
|
|
6728
|
+
resolveFontFamilyName,
|
|
6350
6729
|
restoreLetterSpacing,
|
|
6351
6730
|
scanLottieFonts,
|
|
6352
6731
|
scanTextLayers,
|