@clypra/engine 1.1.1 → 1.2.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 +501 -66
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +157 -1
- package/dist/index.d.ts +157 -1
- package/dist/index.js +493 -66
- 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,
|
|
@@ -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) {
|
|
@@ -959,6 +1007,17 @@ function restoreLetterSpacing(ctx, saved) {
|
|
|
959
1007
|
function getCanvas2DContext2(canvas) {
|
|
960
1008
|
return canvas.getContext("2d");
|
|
961
1009
|
}
|
|
1010
|
+
function ctxSupportsFilter(ctx) {
|
|
1011
|
+
try {
|
|
1012
|
+
const prev = ctx.filter;
|
|
1013
|
+
ctx.filter = "blur(4px)";
|
|
1014
|
+
const ok = typeof ctx.filter === "string" && ctx.filter.includes("blur");
|
|
1015
|
+
ctx.filter = prev;
|
|
1016
|
+
return ok;
|
|
1017
|
+
} catch {
|
|
1018
|
+
return false;
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
962
1021
|
function renderTextEffectCore(ctx, cfg) {
|
|
963
1022
|
if (cfg.customRenderer === "InkBrushEngine") {
|
|
964
1023
|
const engine = new InkBrushEngine(cfg);
|
|
@@ -1268,19 +1327,31 @@ function renderTextEffectCore(ctx, cfg) {
|
|
|
1268
1327
|
const vpy = cHeight / 2 + (bevelVanishingPointY !== void 0 ? bevelVanishingPointY : 80) / 100 * (cHeight / 2);
|
|
1269
1328
|
const fl = Math.max(100, bevelFocalLength !== void 0 ? bevelFocalLength : 400);
|
|
1270
1329
|
if (bevelBlur && bevelBlur > 0) {
|
|
1271
|
-
ctx.save();
|
|
1272
|
-
ctx.filter = `blur(${bevelBlur}px)`;
|
|
1273
1330
|
const blurColor = bevelBlurColor || bevelShadow || "#000000";
|
|
1274
|
-
|
|
1275
|
-
const scale = fl / (fl + i);
|
|
1331
|
+
if (ctxSupportsFilter(ctx)) {
|
|
1276
1332
|
ctx.save();
|
|
1277
|
-
ctx.
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1333
|
+
ctx.filter = `blur(${bevelBlur}px)`;
|
|
1334
|
+
for (let i = bevelDepth; i > 0; i -= Math.max(1, Math.floor(bevelDepth / 4))) {
|
|
1335
|
+
const scale = fl / (fl + i);
|
|
1336
|
+
ctx.save();
|
|
1337
|
+
ctx.translate(vpx, vpy);
|
|
1338
|
+
ctx.scale(scale, scale);
|
|
1339
|
+
ctx.translate(-vpx, -vpy);
|
|
1340
|
+
renderLines("fill", blurColor);
|
|
1341
|
+
ctx.restore();
|
|
1342
|
+
}
|
|
1281
1343
|
ctx.restore();
|
|
1344
|
+
} else {
|
|
1345
|
+
for (let i = bevelDepth; i > 0; i -= Math.max(1, Math.floor(bevelDepth / 4))) {
|
|
1346
|
+
const scale = fl / (fl + i);
|
|
1347
|
+
ctx.save();
|
|
1348
|
+
ctx.translate(vpx, vpy);
|
|
1349
|
+
ctx.scale(scale, scale);
|
|
1350
|
+
ctx.translate(-vpx, -vpy);
|
|
1351
|
+
renderWithShadowTrick("fill", blurColor, bevelBlur, 0, 0, 100);
|
|
1352
|
+
ctx.restore();
|
|
1353
|
+
}
|
|
1282
1354
|
}
|
|
1283
|
-
ctx.restore();
|
|
1284
1355
|
}
|
|
1285
1356
|
ctx.save();
|
|
1286
1357
|
for (let i = bevelDepth; i > 0; i--) {
|
|
@@ -1327,14 +1398,21 @@ function renderTextEffectCore(ctx, cfg) {
|
|
|
1327
1398
|
return { dx: i, dy: i };
|
|
1328
1399
|
};
|
|
1329
1400
|
if (bevelBlur && bevelBlur > 0) {
|
|
1330
|
-
ctx.save();
|
|
1331
|
-
ctx.filter = `blur(${bevelBlur}px)`;
|
|
1332
1401
|
const blurColor = bevelBlurColor || bevelShadow || "#000000";
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1402
|
+
if (ctxSupportsFilter(ctx)) {
|
|
1403
|
+
ctx.save();
|
|
1404
|
+
ctx.filter = `blur(${bevelBlur}px)`;
|
|
1405
|
+
for (let i = bevelDepth; i > 0; i -= Math.max(1, Math.floor(bevelDepth / 4))) {
|
|
1406
|
+
const { dx, dy } = getDirOffset(i);
|
|
1407
|
+
renderLines("fill", blurColor, dx, dy);
|
|
1408
|
+
}
|
|
1409
|
+
ctx.restore();
|
|
1410
|
+
} else {
|
|
1411
|
+
for (let i = bevelDepth; i > 0; i -= Math.max(1, Math.floor(bevelDepth / 4))) {
|
|
1412
|
+
const { dx, dy } = getDirOffset(i);
|
|
1413
|
+
renderWithShadowTrick("fill", blurColor, bevelBlur, dx, dy, 100);
|
|
1414
|
+
}
|
|
1336
1415
|
}
|
|
1337
|
-
ctx.restore();
|
|
1338
1416
|
}
|
|
1339
1417
|
ctx.save();
|
|
1340
1418
|
for (let i = bevelDepth; i > 0; i--) {
|
|
@@ -1388,24 +1466,51 @@ function renderTextEffectCore(ctx, cfg) {
|
|
|
1388
1466
|
customStrokeStyle = grad;
|
|
1389
1467
|
}
|
|
1390
1468
|
const drawStrokeLayer = (color, width, blurAmount, opacity, position) => {
|
|
1391
|
-
ctx
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1469
|
+
if (blurAmount > 0 && ctxSupportsFilter(ctx)) {
|
|
1470
|
+
ctx.save();
|
|
1471
|
+
ctx.globalAlpha = opacity / 100;
|
|
1472
|
+
ctx.strokeStyle = color;
|
|
1395
1473
|
ctx.filter = `blur(${blurAmount}px)`;
|
|
1474
|
+
if (position === "outside") {
|
|
1475
|
+
ctx.lineWidth = width * 2;
|
|
1476
|
+
renderLines("stroke");
|
|
1477
|
+
} else if (position === "center") {
|
|
1478
|
+
ctx.lineWidth = width;
|
|
1479
|
+
renderLines("stroke");
|
|
1480
|
+
} else if (position === "inside") {
|
|
1481
|
+
ctx.globalCompositeOperation = "source-atop";
|
|
1482
|
+
ctx.lineWidth = width * 2;
|
|
1483
|
+
renderLines("stroke");
|
|
1484
|
+
}
|
|
1485
|
+
ctx.restore();
|
|
1486
|
+
} else if (blurAmount > 0) {
|
|
1487
|
+
const colorStr = typeof color === "string" ? color : strokeColor;
|
|
1488
|
+
const spread = position === "center" ? width / 2 : width;
|
|
1489
|
+
if (position === "inside") {
|
|
1490
|
+
ctx.save();
|
|
1491
|
+
ctx.globalCompositeOperation = "source-atop";
|
|
1492
|
+
renderWithShadowTrick("stroke", colorStr, blurAmount, 0, 0, opacity, void 0, spread);
|
|
1493
|
+
ctx.restore();
|
|
1494
|
+
} else {
|
|
1495
|
+
renderWithShadowTrick("stroke", colorStr, blurAmount, 0, 0, opacity, void 0, spread);
|
|
1496
|
+
}
|
|
1497
|
+
} else {
|
|
1498
|
+
ctx.save();
|
|
1499
|
+
ctx.globalAlpha = opacity / 100;
|
|
1500
|
+
ctx.strokeStyle = color;
|
|
1501
|
+
if (position === "outside") {
|
|
1502
|
+
ctx.lineWidth = width * 2;
|
|
1503
|
+
renderLines("stroke");
|
|
1504
|
+
} else if (position === "center") {
|
|
1505
|
+
ctx.lineWidth = width;
|
|
1506
|
+
renderLines("stroke");
|
|
1507
|
+
} else if (position === "inside") {
|
|
1508
|
+
ctx.globalCompositeOperation = "source-atop";
|
|
1509
|
+
ctx.lineWidth = width * 2;
|
|
1510
|
+
renderLines("stroke");
|
|
1511
|
+
}
|
|
1512
|
+
ctx.restore();
|
|
1396
1513
|
}
|
|
1397
|
-
if (position === "outside") {
|
|
1398
|
-
ctx.lineWidth = width * 2;
|
|
1399
|
-
renderLines("stroke");
|
|
1400
|
-
} else if (position === "center") {
|
|
1401
|
-
ctx.lineWidth = width;
|
|
1402
|
-
renderLines("stroke");
|
|
1403
|
-
} else if (position === "inside") {
|
|
1404
|
-
ctx.globalCompositeOperation = "source-atop";
|
|
1405
|
-
ctx.lineWidth = width * 2;
|
|
1406
|
-
renderLines("stroke");
|
|
1407
|
-
}
|
|
1408
|
-
ctx.restore();
|
|
1409
1514
|
};
|
|
1410
1515
|
if (sType === "double") {
|
|
1411
1516
|
const outerWidth = strokeWidth + sWidthSecondary;
|
|
@@ -2530,6 +2635,146 @@ function checkFontVariant(variantName) {
|
|
|
2530
2635
|
if (typeof document === "undefined" || !document.fonts) return false;
|
|
2531
2636
|
return document.fonts.check(`16px "${variantName}"`);
|
|
2532
2637
|
}
|
|
2638
|
+
var FontLoader = class {
|
|
2639
|
+
state = {
|
|
2640
|
+
loading: /* @__PURE__ */ new Set(),
|
|
2641
|
+
loaded: /* @__PURE__ */ new Set(),
|
|
2642
|
+
failed: /* @__PURE__ */ new Map(),
|
|
2643
|
+
promises: /* @__PURE__ */ new Map()
|
|
2644
|
+
};
|
|
2645
|
+
async ensureFont(descriptor) {
|
|
2646
|
+
const key = this.getFontKey(descriptor);
|
|
2647
|
+
if (this.state.loaded.has(key)) {
|
|
2648
|
+
return {
|
|
2649
|
+
font: descriptor,
|
|
2650
|
+
loaded: true,
|
|
2651
|
+
loadTimeMs: 0
|
|
2652
|
+
};
|
|
2653
|
+
}
|
|
2654
|
+
if (this.state.failed.has(key)) {
|
|
2655
|
+
return {
|
|
2656
|
+
font: descriptor,
|
|
2657
|
+
loaded: false,
|
|
2658
|
+
error: this.state.failed.get(key),
|
|
2659
|
+
loadTimeMs: 0
|
|
2660
|
+
};
|
|
2661
|
+
}
|
|
2662
|
+
if (this.state.promises.has(key)) {
|
|
2663
|
+
return this.state.promises.get(key);
|
|
2664
|
+
}
|
|
2665
|
+
const promise = this.loadFont(descriptor);
|
|
2666
|
+
this.state.promises.set(key, promise);
|
|
2667
|
+
return promise;
|
|
2668
|
+
}
|
|
2669
|
+
async ensureFonts(descriptors) {
|
|
2670
|
+
return Promise.all(descriptors.map((desc) => this.ensureFont(desc)));
|
|
2671
|
+
}
|
|
2672
|
+
async waitForFontsReady() {
|
|
2673
|
+
if (typeof document === "undefined" || !document.fonts) {
|
|
2674
|
+
return;
|
|
2675
|
+
}
|
|
2676
|
+
await document.fonts.ready;
|
|
2677
|
+
}
|
|
2678
|
+
isLoaded(descriptor) {
|
|
2679
|
+
const key = this.getFontKey(descriptor);
|
|
2680
|
+
return this.state.loaded.has(key);
|
|
2681
|
+
}
|
|
2682
|
+
getStats() {
|
|
2683
|
+
return {
|
|
2684
|
+
loaded: this.state.loaded.size,
|
|
2685
|
+
loading: this.state.loading.size,
|
|
2686
|
+
failed: this.state.failed.size
|
|
2687
|
+
};
|
|
2688
|
+
}
|
|
2689
|
+
clear() {
|
|
2690
|
+
this.state.loading.clear();
|
|
2691
|
+
this.state.loaded.clear();
|
|
2692
|
+
this.state.failed.clear();
|
|
2693
|
+
this.state.promises.clear();
|
|
2694
|
+
}
|
|
2695
|
+
async loadFont(descriptor) {
|
|
2696
|
+
const key = this.getFontKey(descriptor);
|
|
2697
|
+
const startTime = performance.now();
|
|
2698
|
+
this.state.loading.add(key);
|
|
2699
|
+
try {
|
|
2700
|
+
if (typeof document === "undefined" || !document.fonts) {
|
|
2701
|
+
throw new Error("Font API not available");
|
|
2702
|
+
}
|
|
2703
|
+
const weight = this.normalizeFontWeight(descriptor.weight);
|
|
2704
|
+
const style = descriptor.style || "normal";
|
|
2705
|
+
const fontFace = `${style} ${weight} 16px "${descriptor.family}"`;
|
|
2706
|
+
if (document.fonts.check(fontFace)) {
|
|
2707
|
+
this.state.loaded.add(key);
|
|
2708
|
+
this.state.loading.delete(key);
|
|
2709
|
+
this.state.promises.delete(key);
|
|
2710
|
+
return {
|
|
2711
|
+
font: descriptor,
|
|
2712
|
+
loaded: true,
|
|
2713
|
+
loadTimeMs: performance.now() - startTime
|
|
2714
|
+
};
|
|
2715
|
+
}
|
|
2716
|
+
await document.fonts.load(fontFace);
|
|
2717
|
+
if (!document.fonts.check(fontFace)) {
|
|
2718
|
+
throw new Error(`Font "${descriptor.family}" failed to load`);
|
|
2719
|
+
}
|
|
2720
|
+
this.state.loaded.add(key);
|
|
2721
|
+
this.state.loading.delete(key);
|
|
2722
|
+
this.state.promises.delete(key);
|
|
2723
|
+
return {
|
|
2724
|
+
font: descriptor,
|
|
2725
|
+
loaded: true,
|
|
2726
|
+
loadTimeMs: performance.now() - startTime
|
|
2727
|
+
};
|
|
2728
|
+
} catch (error) {
|
|
2729
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
2730
|
+
this.state.failed.set(key, errorMessage);
|
|
2731
|
+
this.state.loading.delete(key);
|
|
2732
|
+
this.state.promises.delete(key);
|
|
2733
|
+
return {
|
|
2734
|
+
font: descriptor,
|
|
2735
|
+
loaded: false,
|
|
2736
|
+
error: errorMessage,
|
|
2737
|
+
loadTimeMs: performance.now() - startTime
|
|
2738
|
+
};
|
|
2739
|
+
}
|
|
2740
|
+
}
|
|
2741
|
+
getFontKey(descriptor) {
|
|
2742
|
+
const weight = this.normalizeFontWeight(descriptor.weight);
|
|
2743
|
+
const style = descriptor.style || "normal";
|
|
2744
|
+
return `${descriptor.family}|${weight}|${style}`;
|
|
2745
|
+
}
|
|
2746
|
+
normalizeFontWeight(weight) {
|
|
2747
|
+
if (typeof weight === "number") {
|
|
2748
|
+
return weight;
|
|
2749
|
+
}
|
|
2750
|
+
if (!weight) return 400;
|
|
2751
|
+
const asNum = parseInt(weight, 10);
|
|
2752
|
+
if (!isNaN(asNum) && asNum >= 100 && asNum <= 900) {
|
|
2753
|
+
return asNum;
|
|
2754
|
+
}
|
|
2755
|
+
const weightMap = {
|
|
2756
|
+
normal: 400,
|
|
2757
|
+
bold: 700,
|
|
2758
|
+
lighter: 300,
|
|
2759
|
+
bolder: 700
|
|
2760
|
+
};
|
|
2761
|
+
return weightMap[weight] ?? 400;
|
|
2762
|
+
}
|
|
2763
|
+
};
|
|
2764
|
+
var globalFontLoader = null;
|
|
2765
|
+
function getFontLoader() {
|
|
2766
|
+
if (!globalFontLoader) {
|
|
2767
|
+
globalFontLoader = new FontLoader();
|
|
2768
|
+
}
|
|
2769
|
+
return globalFontLoader;
|
|
2770
|
+
}
|
|
2771
|
+
function resetFontLoader() {
|
|
2772
|
+
globalFontLoader = null;
|
|
2773
|
+
}
|
|
2774
|
+
async function ensureFontsLoaded(descriptors) {
|
|
2775
|
+
const loader = getFontLoader();
|
|
2776
|
+
return loader.ensureFonts(descriptors);
|
|
2777
|
+
}
|
|
2533
2778
|
|
|
2534
2779
|
// src/engine/timelineDefaults.ts
|
|
2535
2780
|
function ensureDefaultTimeline(doc) {
|
|
@@ -2901,6 +3146,212 @@ function mergeSceneIntoConfig(doc, base) {
|
|
|
2901
3146
|
const out = sceneToConfig({ ...doc, legacyConfig: base });
|
|
2902
3147
|
return out;
|
|
2903
3148
|
}
|
|
3149
|
+
function resolveFontFamilyName(fontFamily) {
|
|
3150
|
+
const f = fontFamily?.toLowerCase() || "";
|
|
3151
|
+
if (f.includes("inter")) return "Inter Variable";
|
|
3152
|
+
if (f.includes("montserrat")) return "Montserrat Variable";
|
|
3153
|
+
if (f.includes("geist")) return "Geist Variable";
|
|
3154
|
+
if (f.includes("space grotesk") || f.includes("grotesk")) return "Space Grotesk Variable";
|
|
3155
|
+
if (f.includes("outfit")) return "Outfit Variable";
|
|
3156
|
+
if (f.includes("roboto variable")) return "Roboto Variable";
|
|
3157
|
+
if (f.includes("roboto condensed")) return "Roboto Condensed";
|
|
3158
|
+
if (f === "roboto") return "Roboto Variable";
|
|
3159
|
+
if (f.includes("open sans")) return "Open Sans Variable";
|
|
3160
|
+
if (f.includes("raleway")) return "Raleway Variable";
|
|
3161
|
+
if (f.includes("oswald")) return "Oswald Variable";
|
|
3162
|
+
if (f.includes("playfair display")) return "Playfair Display Variable";
|
|
3163
|
+
if (f.includes("nunito")) return "Nunito Variable";
|
|
3164
|
+
if (f.includes("dancing script")) return "Dancing Script Variable";
|
|
3165
|
+
if (f === "lato") return "Lato";
|
|
3166
|
+
if (f === "anton") return "Anton";
|
|
3167
|
+
if (f === "bebas neue") return "Bebas Neue";
|
|
3168
|
+
if (f === "poppins") return "Poppins";
|
|
3169
|
+
if (f === "permanent marker") return "Permanent Marker";
|
|
3170
|
+
if (f === "bangers") return "Bangers";
|
|
3171
|
+
if (f === "press start 2p") return "Press Start 2P";
|
|
3172
|
+
if (f === "pacifico") return "Pacifico";
|
|
3173
|
+
return fontFamily;
|
|
3174
|
+
}
|
|
3175
|
+
function _buildConfig(effect, text, fontSize, canvasWidth, canvasHeight, time, clipStartTime, clipDuration) {
|
|
3176
|
+
const fill = effect.fills?.[0];
|
|
3177
|
+
const stroke = effect.strokes?.[0];
|
|
3178
|
+
const shadow = effect.shadows?.[0];
|
|
3179
|
+
const bevel = effect.bevel;
|
|
3180
|
+
const panel = effect.panel;
|
|
3181
|
+
const ratio = fontSize / 100;
|
|
3182
|
+
const config = {
|
|
3183
|
+
// Canvas / text
|
|
3184
|
+
width: canvasWidth,
|
|
3185
|
+
height: canvasHeight,
|
|
3186
|
+
canvasWidth,
|
|
3187
|
+
canvasHeight,
|
|
3188
|
+
text,
|
|
3189
|
+
time: time ?? 0,
|
|
3190
|
+
clipStartTime: clipStartTime ?? 0,
|
|
3191
|
+
clipDuration: clipDuration ?? 5,
|
|
3192
|
+
// Font
|
|
3193
|
+
fontFamily: resolveFontFamilyName(effect.font.family),
|
|
3194
|
+
fontWeight: effect.font.weight,
|
|
3195
|
+
fontStyle: effect.font.style,
|
|
3196
|
+
fontSize,
|
|
3197
|
+
letterSpacing: effect.font.letterSpacing,
|
|
3198
|
+
lineHeight: effect.font.lineHeight
|
|
3199
|
+
};
|
|
3200
|
+
if (effect.animation) {
|
|
3201
|
+
config.animation = effect.animation;
|
|
3202
|
+
}
|
|
3203
|
+
if (fill) {
|
|
3204
|
+
if (fill.type !== void 0) config.fillType = fill.type;
|
|
3205
|
+
if (fill.color !== void 0) config.fillColor = fill.color;
|
|
3206
|
+
if (fill.gradient?.angle !== void 0) config.fillGradientAngle = fill.gradient.angle;
|
|
3207
|
+
if (fill.gradient?.stops !== void 0) config.fillGradientStops = fill.gradient.stops;
|
|
3208
|
+
if (fill.patternType !== void 0) config.patternType = fill.patternType;
|
|
3209
|
+
if (fill.perCharFillEnabled !== void 0) config.perCharFillEnabled = fill.perCharFillEnabled;
|
|
3210
|
+
if (fill.charFillColors !== void 0) config.charFillColors = fill.charFillColors;
|
|
3211
|
+
} else {
|
|
3212
|
+
config.fillType = "none";
|
|
3213
|
+
}
|
|
3214
|
+
config.strokeEnabled = !!stroke;
|
|
3215
|
+
if (stroke) {
|
|
3216
|
+
if (stroke.color !== void 0) config.strokeColor = stroke.color;
|
|
3217
|
+
if (stroke.width !== void 0) config.strokeWidth = stroke.width * ratio;
|
|
3218
|
+
if (stroke.position !== void 0) config.strokePosition = stroke.position;
|
|
3219
|
+
if (stroke.opacity !== void 0) config.strokeOpacity = stroke.opacity;
|
|
3220
|
+
if (stroke.lineJoin !== void 0) config.strokeLineJoin = stroke.lineJoin;
|
|
3221
|
+
if (stroke.blur !== void 0) config.strokeBlur = stroke.blur * ratio;
|
|
3222
|
+
if (stroke.type !== void 0) config.strokeType = stroke.type;
|
|
3223
|
+
if (stroke.colorSecondary !== void 0) config.strokeColorSecondary = stroke.colorSecondary;
|
|
3224
|
+
if (stroke.widthSecondary !== void 0) config.strokeWidthSecondary = stroke.widthSecondary * ratio;
|
|
3225
|
+
if (stroke.fadeRange !== void 0) config.strokeFadeRange = stroke.fadeRange;
|
|
3226
|
+
}
|
|
3227
|
+
config.shadowEnabled = !!shadow;
|
|
3228
|
+
if (shadow) {
|
|
3229
|
+
if (shadow.color !== void 0) config.shadowColor = shadow.color;
|
|
3230
|
+
if (shadow.blur !== void 0) config.shadowBlur = shadow.blur * ratio;
|
|
3231
|
+
if (shadow.offsetX !== void 0) config.shadowOffsetX = shadow.offsetX * ratio;
|
|
3232
|
+
if (shadow.offsetY !== void 0) config.shadowOffsetY = shadow.offsetY * ratio;
|
|
3233
|
+
if (shadow.opacity !== void 0) config.shadowOpacity = shadow.opacity;
|
|
3234
|
+
if (shadow.type !== void 0) config.shadowType = shadow.type;
|
|
3235
|
+
}
|
|
3236
|
+
config.bevelEnabled = !!bevel;
|
|
3237
|
+
if (bevel) {
|
|
3238
|
+
if (bevel.depth !== void 0) config.bevelDepth = Math.round(bevel.depth * ratio);
|
|
3239
|
+
if (bevel.highlightColor !== void 0) config.bevelHighlight = bevel.highlightColor;
|
|
3240
|
+
if (bevel.shadowColor !== void 0) config.bevelShadow = bevel.shadowColor;
|
|
3241
|
+
if (bevel.direction !== void 0) config.bevelDirection = bevel.direction;
|
|
3242
|
+
if (bevel.coreColor !== void 0) config.bevelCoreColor = bevel.coreColor;
|
|
3243
|
+
if (bevel.edgeColor !== void 0) config.bevelEdgeColor = bevel.edgeColor;
|
|
3244
|
+
if (bevel.edgeWidth !== void 0) config.bevelEdgeWidth = bevel.edgeWidth * ratio;
|
|
3245
|
+
if (bevel.blur !== void 0) config.bevelBlur = bevel.blur * ratio;
|
|
3246
|
+
if (bevel.blurColor !== void 0) config.bevelBlurColor = bevel.blurColor;
|
|
3247
|
+
if (bevel.perspectiveEnabled !== void 0) config.bevelPerspectiveEnabled = bevel.perspectiveEnabled;
|
|
3248
|
+
if (bevel.vanishingPointX !== void 0) config.bevelVanishingPointX = bevel.vanishingPointX;
|
|
3249
|
+
if (bevel.vanishingPointY !== void 0) config.bevelVanishingPointY = bevel.vanishingPointY;
|
|
3250
|
+
if (bevel.focalLength !== void 0) config.bevelFocalLength = bevel.focalLength;
|
|
3251
|
+
}
|
|
3252
|
+
if (effect.stack) {
|
|
3253
|
+
config.stackEnabled = !!effect.stack.count;
|
|
3254
|
+
if (effect.stack.count !== void 0) config.stackCount = effect.stack.count;
|
|
3255
|
+
if (effect.stack.offsetX !== void 0) config.stackOffsetX = effect.stack.offsetX * ratio;
|
|
3256
|
+
if (effect.stack.offsetY !== void 0) config.stackOffsetY = effect.stack.offsetY * ratio;
|
|
3257
|
+
if (effect.stack.opacityDecay !== void 0) config.stackOpacityDecay = effect.stack.opacityDecay;
|
|
3258
|
+
if (effect.stack.color1 !== void 0) config.stackColor1 = effect.stack.color1;
|
|
3259
|
+
if (effect.stack.color2 !== void 0) config.stackColor2 = effect.stack.color2;
|
|
3260
|
+
if (effect.stack.color3 !== void 0) config.stackColor3 = effect.stack.color3;
|
|
3261
|
+
if (effect.stack.color4 !== void 0) config.stackColor4 = effect.stack.color4;
|
|
3262
|
+
}
|
|
3263
|
+
config.panelEnabled = !!panel;
|
|
3264
|
+
if (panel) {
|
|
3265
|
+
if (panel.color !== void 0) config.panelColor = panel.color;
|
|
3266
|
+
if (panel.opacity !== void 0) config.panelOpacity = panel.opacity;
|
|
3267
|
+
if (panel.radius !== void 0) config.panelRadius = panel.radius;
|
|
3268
|
+
if (panel.paddingX !== void 0) config.panelPaddingX = panel.paddingX * ratio;
|
|
3269
|
+
if (panel.paddingY !== void 0) config.panelPaddingY = panel.paddingY * ratio;
|
|
3270
|
+
if (panel.stroke !== void 0) {
|
|
3271
|
+
config.panelStrokeEnabled = !!panel.stroke;
|
|
3272
|
+
if (panel.stroke.color !== void 0) config.panelStrokeColor = panel.stroke.color;
|
|
3273
|
+
if (panel.stroke.width !== void 0) config.panelStrokeWidth = panel.stroke.width * ratio;
|
|
3274
|
+
}
|
|
3275
|
+
}
|
|
3276
|
+
if (effect.glows) {
|
|
3277
|
+
config.glowLayers = effect.glows.map((g) => {
|
|
3278
|
+
const mappedGlow = {
|
|
3279
|
+
enabled: true,
|
|
3280
|
+
color: g.color,
|
|
3281
|
+
blur: typeof g.blur === "number" ? g.blur * ratio : g.blur ?? 0,
|
|
3282
|
+
opacity: g.opacity,
|
|
3283
|
+
type: g.type ?? "outer"
|
|
3284
|
+
};
|
|
3285
|
+
if (g.strength !== void 0) mappedGlow.strength = g.strength;
|
|
3286
|
+
if (g.spread !== void 0) mappedGlow.spread = g.spread * ratio;
|
|
3287
|
+
return mappedGlow;
|
|
3288
|
+
});
|
|
3289
|
+
}
|
|
3290
|
+
const standardKeys = /* @__PURE__ */ new Set([
|
|
3291
|
+
"id",
|
|
3292
|
+
"name",
|
|
3293
|
+
"category",
|
|
3294
|
+
"description",
|
|
3295
|
+
"tags",
|
|
3296
|
+
"font",
|
|
3297
|
+
"fills",
|
|
3298
|
+
"strokes",
|
|
3299
|
+
"shadows",
|
|
3300
|
+
"glows",
|
|
3301
|
+
"bevel",
|
|
3302
|
+
"panel",
|
|
3303
|
+
"text",
|
|
3304
|
+
"animation",
|
|
3305
|
+
"stack"
|
|
3306
|
+
]);
|
|
3307
|
+
for (const key of Object.keys(effect)) {
|
|
3308
|
+
if (!standardKeys.has(key)) {
|
|
3309
|
+
config[key] = effect[key];
|
|
3310
|
+
}
|
|
3311
|
+
}
|
|
3312
|
+
return config;
|
|
3313
|
+
}
|
|
3314
|
+
function layerToTextEffectConfig(layer2) {
|
|
3315
|
+
const normWeight = typeof layer2.fontWeight === "number" ? layer2.fontWeight : layer2.fontWeight === "bold" ? 700 : 400;
|
|
3316
|
+
const config = {
|
|
3317
|
+
...defaultConfig,
|
|
3318
|
+
width: layer2.width,
|
|
3319
|
+
height: layer2.height,
|
|
3320
|
+
canvasWidth: layer2.width,
|
|
3321
|
+
canvasHeight: layer2.height,
|
|
3322
|
+
text: layer2.text,
|
|
3323
|
+
fontFamily: resolveFontFamilyName(layer2.fontFamily),
|
|
3324
|
+
fontWeight: normWeight,
|
|
3325
|
+
fontStyle: layer2.fontStyle || "normal",
|
|
3326
|
+
fontSize: layer2.fontSize,
|
|
3327
|
+
letterSpacing: layer2.letterSpacing ?? 0,
|
|
3328
|
+
lineHeight: layer2.lineHeight ?? 1.2,
|
|
3329
|
+
fillType: layer2.color ? "solid" : "none",
|
|
3330
|
+
fillColor: layer2.color ?? "#FFFFFF",
|
|
3331
|
+
strokeEnabled: !!layer2.stroke,
|
|
3332
|
+
strokeColor: layer2.stroke?.color ?? "#000000",
|
|
3333
|
+
strokeWidth: layer2.stroke?.width ?? 0,
|
|
3334
|
+
strokePosition: "center",
|
|
3335
|
+
strokeOpacity: 100,
|
|
3336
|
+
strokeLineJoin: "round",
|
|
3337
|
+
shadowEnabled: !!layer2.shadow,
|
|
3338
|
+
shadowColor: layer2.shadow?.color ?? "#000000",
|
|
3339
|
+
shadowBlur: layer2.shadow?.blur ?? 0,
|
|
3340
|
+
shadowOffsetX: layer2.shadow?.offsetX ?? 0,
|
|
3341
|
+
shadowOffsetY: layer2.shadow?.offsetY ?? 0,
|
|
3342
|
+
shadowOpacity: 100,
|
|
3343
|
+
shadowType: "drop",
|
|
3344
|
+
panelEnabled: !!layer2.background,
|
|
3345
|
+
panelColor: layer2.background?.color ?? "#1E1E26",
|
|
3346
|
+
panelOpacity: 80,
|
|
3347
|
+
panelRadius: layer2.background?.borderRadius ?? 6,
|
|
3348
|
+
panelPaddingX: layer2.background?.padding ?? 12,
|
|
3349
|
+
panelPaddingY: layer2.background?.padding ?? 12,
|
|
3350
|
+
textPosX: layer2.textAlign || "center",
|
|
3351
|
+
textPosY: layer2.verticalAlign === "middle" ? "middle" : layer2.verticalAlign || "middle"
|
|
3352
|
+
};
|
|
3353
|
+
return config;
|
|
3354
|
+
}
|
|
2904
3355
|
|
|
2905
3356
|
// src/engine/animation.ts
|
|
2906
3357
|
function ease(t, kind = "linear") {
|
|
@@ -3210,47 +3661,23 @@ function evaluateScene(doc, time, ctx, options = {}) {
|
|
|
3210
3661
|
finishFrame();
|
|
3211
3662
|
return;
|
|
3212
3663
|
}
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
return;
|
|
3220
|
-
}
|
|
3221
|
-
renderTextEffectCore(offCtx, cfg);
|
|
3222
|
-
applyMaskReveal(offCtx, animated, w, h);
|
|
3664
|
+
const temp = CanvasDevice.acquire(w, h);
|
|
3665
|
+
const tctx = temp.getContext("2d");
|
|
3666
|
+
if (tctx) {
|
|
3667
|
+
tctx.clearRect(0, 0, w, h);
|
|
3668
|
+
renderTextEffectCore(tctx, cfg);
|
|
3669
|
+
applyMaskReveal(tctx, animated, w, h);
|
|
3223
3670
|
const compositor = options.compositor ?? getCompositor();
|
|
3224
3671
|
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
|
-
}
|
|
3672
|
+
compositor.renderToContext(ctx, temp, comp);
|
|
3673
|
+
} else {
|
|
3247
3674
|
ctx.clearRect(0, 0, w, h);
|
|
3248
3675
|
ctx.drawImage(temp, 0, 0);
|
|
3249
|
-
temp.width = 0;
|
|
3250
|
-
temp.height = 0;
|
|
3251
|
-
return;
|
|
3252
3676
|
}
|
|
3677
|
+
CanvasDevice.release(temp);
|
|
3678
|
+
return;
|
|
3253
3679
|
}
|
|
3680
|
+
CanvasDevice.release(temp);
|
|
3254
3681
|
renderTextEffectCore(ctx, cfg);
|
|
3255
3682
|
finishFrame();
|
|
3256
3683
|
}
|
|
@@ -6218,6 +6645,7 @@ function duplicateTrackAtPlayhead(doc, trackIndex, previewTime) {
|
|
|
6218
6645
|
0 && (module.exports = {
|
|
6219
6646
|
COMPOSITION_PRESETS,
|
|
6220
6647
|
CUSTOM_ENGINE_IDS,
|
|
6648
|
+
CanvasDevice,
|
|
6221
6649
|
DEFAULT_CANVAS_HEIGHT,
|
|
6222
6650
|
DEFAULT_CANVAS_WIDTH,
|
|
6223
6651
|
DEFAULT_DURATION,
|
|
@@ -6229,6 +6657,7 @@ function duplicateTrackAtPlayhead(doc, trackIndex, previewTime) {
|
|
|
6229
6657
|
ENTRANCE_PRESETS,
|
|
6230
6658
|
EXIT_PRESETS,
|
|
6231
6659
|
FONT_WEIGHT_OPTIONS,
|
|
6660
|
+
FontLoader,
|
|
6232
6661
|
InkBrushEngine,
|
|
6233
6662
|
LEGACY_RENDERER_MAP,
|
|
6234
6663
|
LOOP_PRESETS,
|
|
@@ -6240,6 +6669,7 @@ function duplicateTrackAtPlayhead(doc, trackIndex, previewTime) {
|
|
|
6240
6669
|
TextEffectRenderer,
|
|
6241
6670
|
WEBM_EXPORT_MAX_FRAMES,
|
|
6242
6671
|
WebGLCompositor,
|
|
6672
|
+
_buildConfig,
|
|
6243
6673
|
_resetPlatformCache,
|
|
6244
6674
|
addImageLayer,
|
|
6245
6675
|
addKeyframeAtTime,
|
|
@@ -6297,6 +6727,7 @@ function duplicateTrackAtPlayhead(doc, trackIndex, previewTime) {
|
|
|
6297
6727
|
encodeGif,
|
|
6298
6728
|
ensureDefaultTimeline,
|
|
6299
6729
|
ensureFontInLottie,
|
|
6730
|
+
ensureFontsLoaded,
|
|
6300
6731
|
evaluateConfig,
|
|
6301
6732
|
evaluateScene,
|
|
6302
6733
|
findTrackIndex,
|
|
@@ -6304,6 +6735,7 @@ function duplicateTrackAtPlayhead(doc, trackIndex, previewTime) {
|
|
|
6304
6735
|
getAnimatableParamDef,
|
|
6305
6736
|
getAnimatableParamsForLayer,
|
|
6306
6737
|
getDefaultText,
|
|
6738
|
+
getFontLoader,
|
|
6307
6739
|
getLayerById,
|
|
6308
6740
|
getPresetScene,
|
|
6309
6741
|
getSceneTime,
|
|
@@ -6322,6 +6754,7 @@ function duplicateTrackAtPlayhead(doc, trackIndex, previewTime) {
|
|
|
6322
6754
|
injectText,
|
|
6323
6755
|
injectTextStyle,
|
|
6324
6756
|
isWebMExportSupported,
|
|
6757
|
+
layerToTextEffectConfig,
|
|
6325
6758
|
loadLottieFonts,
|
|
6326
6759
|
lottieColorToHex,
|
|
6327
6760
|
lottieJToAlign,
|
|
@@ -6344,10 +6777,12 @@ function duplicateTrackAtPlayhead(doc, trackIndex, previewTime) {
|
|
|
6344
6777
|
renderPngSequence,
|
|
6345
6778
|
renderSceneWebM,
|
|
6346
6779
|
renderTextEffectCore,
|
|
6780
|
+
resetFontLoader,
|
|
6347
6781
|
resetSceneTime,
|
|
6348
6782
|
resizeCharFillColors,
|
|
6349
6783
|
resolveAnimatedScalar,
|
|
6350
6784
|
resolveCustomEngineId,
|
|
6785
|
+
resolveFontFamilyName,
|
|
6351
6786
|
restoreLetterSpacing,
|
|
6352
6787
|
scanLottieFonts,
|
|
6353
6788
|
scanTextLayers,
|