@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 +413 -35
- 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 +405 -35
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -386,6 +386,46 @@ function _resetPlatformCache() {
|
|
|
386
386
|
_offscreenCanvas = null;
|
|
387
387
|
_webgl2 = null;
|
|
388
388
|
}
|
|
389
|
+
var CanvasDevice = class {
|
|
390
|
+
static canvases = [];
|
|
391
|
+
static maxPoolSize = 10;
|
|
392
|
+
/**
|
|
393
|
+
* Acquire a Canvas context from the pool or create a new one.
|
|
394
|
+
* If a canvas is pulled from the pool, it is resized to the target dimensions.
|
|
395
|
+
*/
|
|
396
|
+
static acquire(width, height) {
|
|
397
|
+
let canvas;
|
|
398
|
+
if (this.canvases.length > 0) {
|
|
399
|
+
canvas = this.canvases.pop();
|
|
400
|
+
if (canvas.width !== width || canvas.height !== height) {
|
|
401
|
+
canvas.width = width;
|
|
402
|
+
canvas.height = height;
|
|
403
|
+
}
|
|
404
|
+
} else {
|
|
405
|
+
canvas = createCanvas(width, height);
|
|
406
|
+
}
|
|
407
|
+
return canvas;
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* Release a canvas back to the pool, or free its resources immediately if pool is full.
|
|
411
|
+
*/
|
|
412
|
+
static release(canvas) {
|
|
413
|
+
if (this.canvases.length < this.maxPoolSize) {
|
|
414
|
+
this.canvases.push(canvas);
|
|
415
|
+
} else {
|
|
416
|
+
releaseCanvas(canvas);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Disposes all pooled canvases to release GPU/memory backing stores.
|
|
421
|
+
*/
|
|
422
|
+
static clearPool() {
|
|
423
|
+
while (this.canvases.length > 0) {
|
|
424
|
+
const c = this.canvases.pop();
|
|
425
|
+
releaseCanvas(c);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
};
|
|
389
429
|
|
|
390
430
|
// src/engine/procedural/utils.ts
|
|
391
431
|
function getCanvas2DContext(canvas) {
|
|
@@ -2348,6 +2388,146 @@ function checkFontVariant(variantName) {
|
|
|
2348
2388
|
if (typeof document === "undefined" || !document.fonts) return false;
|
|
2349
2389
|
return document.fonts.check(`16px "${variantName}"`);
|
|
2350
2390
|
}
|
|
2391
|
+
var FontLoader = class {
|
|
2392
|
+
state = {
|
|
2393
|
+
loading: /* @__PURE__ */ new Set(),
|
|
2394
|
+
loaded: /* @__PURE__ */ new Set(),
|
|
2395
|
+
failed: /* @__PURE__ */ new Map(),
|
|
2396
|
+
promises: /* @__PURE__ */ new Map()
|
|
2397
|
+
};
|
|
2398
|
+
async ensureFont(descriptor) {
|
|
2399
|
+
const key = this.getFontKey(descriptor);
|
|
2400
|
+
if (this.state.loaded.has(key)) {
|
|
2401
|
+
return {
|
|
2402
|
+
font: descriptor,
|
|
2403
|
+
loaded: true,
|
|
2404
|
+
loadTimeMs: 0
|
|
2405
|
+
};
|
|
2406
|
+
}
|
|
2407
|
+
if (this.state.failed.has(key)) {
|
|
2408
|
+
return {
|
|
2409
|
+
font: descriptor,
|
|
2410
|
+
loaded: false,
|
|
2411
|
+
error: this.state.failed.get(key),
|
|
2412
|
+
loadTimeMs: 0
|
|
2413
|
+
};
|
|
2414
|
+
}
|
|
2415
|
+
if (this.state.promises.has(key)) {
|
|
2416
|
+
return this.state.promises.get(key);
|
|
2417
|
+
}
|
|
2418
|
+
const promise = this.loadFont(descriptor);
|
|
2419
|
+
this.state.promises.set(key, promise);
|
|
2420
|
+
return promise;
|
|
2421
|
+
}
|
|
2422
|
+
async ensureFonts(descriptors) {
|
|
2423
|
+
return Promise.all(descriptors.map((desc) => this.ensureFont(desc)));
|
|
2424
|
+
}
|
|
2425
|
+
async waitForFontsReady() {
|
|
2426
|
+
if (typeof document === "undefined" || !document.fonts) {
|
|
2427
|
+
return;
|
|
2428
|
+
}
|
|
2429
|
+
await document.fonts.ready;
|
|
2430
|
+
}
|
|
2431
|
+
isLoaded(descriptor) {
|
|
2432
|
+
const key = this.getFontKey(descriptor);
|
|
2433
|
+
return this.state.loaded.has(key);
|
|
2434
|
+
}
|
|
2435
|
+
getStats() {
|
|
2436
|
+
return {
|
|
2437
|
+
loaded: this.state.loaded.size,
|
|
2438
|
+
loading: this.state.loading.size,
|
|
2439
|
+
failed: this.state.failed.size
|
|
2440
|
+
};
|
|
2441
|
+
}
|
|
2442
|
+
clear() {
|
|
2443
|
+
this.state.loading.clear();
|
|
2444
|
+
this.state.loaded.clear();
|
|
2445
|
+
this.state.failed.clear();
|
|
2446
|
+
this.state.promises.clear();
|
|
2447
|
+
}
|
|
2448
|
+
async loadFont(descriptor) {
|
|
2449
|
+
const key = this.getFontKey(descriptor);
|
|
2450
|
+
const startTime = performance.now();
|
|
2451
|
+
this.state.loading.add(key);
|
|
2452
|
+
try {
|
|
2453
|
+
if (typeof document === "undefined" || !document.fonts) {
|
|
2454
|
+
throw new Error("Font API not available");
|
|
2455
|
+
}
|
|
2456
|
+
const weight = this.normalizeFontWeight(descriptor.weight);
|
|
2457
|
+
const style = descriptor.style || "normal";
|
|
2458
|
+
const fontFace = `${style} ${weight} 16px "${descriptor.family}"`;
|
|
2459
|
+
if (document.fonts.check(fontFace)) {
|
|
2460
|
+
this.state.loaded.add(key);
|
|
2461
|
+
this.state.loading.delete(key);
|
|
2462
|
+
this.state.promises.delete(key);
|
|
2463
|
+
return {
|
|
2464
|
+
font: descriptor,
|
|
2465
|
+
loaded: true,
|
|
2466
|
+
loadTimeMs: performance.now() - startTime
|
|
2467
|
+
};
|
|
2468
|
+
}
|
|
2469
|
+
await document.fonts.load(fontFace);
|
|
2470
|
+
if (!document.fonts.check(fontFace)) {
|
|
2471
|
+
throw new Error(`Font "${descriptor.family}" failed to load`);
|
|
2472
|
+
}
|
|
2473
|
+
this.state.loaded.add(key);
|
|
2474
|
+
this.state.loading.delete(key);
|
|
2475
|
+
this.state.promises.delete(key);
|
|
2476
|
+
return {
|
|
2477
|
+
font: descriptor,
|
|
2478
|
+
loaded: true,
|
|
2479
|
+
loadTimeMs: performance.now() - startTime
|
|
2480
|
+
};
|
|
2481
|
+
} catch (error) {
|
|
2482
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
2483
|
+
this.state.failed.set(key, errorMessage);
|
|
2484
|
+
this.state.loading.delete(key);
|
|
2485
|
+
this.state.promises.delete(key);
|
|
2486
|
+
return {
|
|
2487
|
+
font: descriptor,
|
|
2488
|
+
loaded: false,
|
|
2489
|
+
error: errorMessage,
|
|
2490
|
+
loadTimeMs: performance.now() - startTime
|
|
2491
|
+
};
|
|
2492
|
+
}
|
|
2493
|
+
}
|
|
2494
|
+
getFontKey(descriptor) {
|
|
2495
|
+
const weight = this.normalizeFontWeight(descriptor.weight);
|
|
2496
|
+
const style = descriptor.style || "normal";
|
|
2497
|
+
return `${descriptor.family}|${weight}|${style}`;
|
|
2498
|
+
}
|
|
2499
|
+
normalizeFontWeight(weight) {
|
|
2500
|
+
if (typeof weight === "number") {
|
|
2501
|
+
return weight;
|
|
2502
|
+
}
|
|
2503
|
+
if (!weight) return 400;
|
|
2504
|
+
const asNum = parseInt(weight, 10);
|
|
2505
|
+
if (!isNaN(asNum) && asNum >= 100 && asNum <= 900) {
|
|
2506
|
+
return asNum;
|
|
2507
|
+
}
|
|
2508
|
+
const weightMap = {
|
|
2509
|
+
normal: 400,
|
|
2510
|
+
bold: 700,
|
|
2511
|
+
lighter: 300,
|
|
2512
|
+
bolder: 700
|
|
2513
|
+
};
|
|
2514
|
+
return weightMap[weight] ?? 400;
|
|
2515
|
+
}
|
|
2516
|
+
};
|
|
2517
|
+
var globalFontLoader = null;
|
|
2518
|
+
function getFontLoader() {
|
|
2519
|
+
if (!globalFontLoader) {
|
|
2520
|
+
globalFontLoader = new FontLoader();
|
|
2521
|
+
}
|
|
2522
|
+
return globalFontLoader;
|
|
2523
|
+
}
|
|
2524
|
+
function resetFontLoader() {
|
|
2525
|
+
globalFontLoader = null;
|
|
2526
|
+
}
|
|
2527
|
+
async function ensureFontsLoaded(descriptors) {
|
|
2528
|
+
const loader = getFontLoader();
|
|
2529
|
+
return loader.ensureFonts(descriptors);
|
|
2530
|
+
}
|
|
2351
2531
|
|
|
2352
2532
|
// src/engine/timelineDefaults.ts
|
|
2353
2533
|
function ensureDefaultTimeline(doc) {
|
|
@@ -2719,6 +2899,212 @@ function mergeSceneIntoConfig(doc, base) {
|
|
|
2719
2899
|
const out = sceneToConfig({ ...doc, legacyConfig: base });
|
|
2720
2900
|
return out;
|
|
2721
2901
|
}
|
|
2902
|
+
function resolveFontFamilyName(fontFamily) {
|
|
2903
|
+
const f = fontFamily?.toLowerCase() || "";
|
|
2904
|
+
if (f.includes("inter")) return "Inter Variable";
|
|
2905
|
+
if (f.includes("montserrat")) return "Montserrat Variable";
|
|
2906
|
+
if (f.includes("geist")) return "Geist Variable";
|
|
2907
|
+
if (f.includes("space grotesk") || f.includes("grotesk")) return "Space Grotesk Variable";
|
|
2908
|
+
if (f.includes("outfit")) return "Outfit Variable";
|
|
2909
|
+
if (f.includes("roboto variable")) return "Roboto Variable";
|
|
2910
|
+
if (f.includes("roboto condensed")) return "Roboto Condensed";
|
|
2911
|
+
if (f === "roboto") return "Roboto Variable";
|
|
2912
|
+
if (f.includes("open sans")) return "Open Sans Variable";
|
|
2913
|
+
if (f.includes("raleway")) return "Raleway Variable";
|
|
2914
|
+
if (f.includes("oswald")) return "Oswald Variable";
|
|
2915
|
+
if (f.includes("playfair display")) return "Playfair Display Variable";
|
|
2916
|
+
if (f.includes("nunito")) return "Nunito Variable";
|
|
2917
|
+
if (f.includes("dancing script")) return "Dancing Script Variable";
|
|
2918
|
+
if (f === "lato") return "Lato";
|
|
2919
|
+
if (f === "anton") return "Anton";
|
|
2920
|
+
if (f === "bebas neue") return "Bebas Neue";
|
|
2921
|
+
if (f === "poppins") return "Poppins";
|
|
2922
|
+
if (f === "permanent marker") return "Permanent Marker";
|
|
2923
|
+
if (f === "bangers") return "Bangers";
|
|
2924
|
+
if (f === "press start 2p") return "Press Start 2P";
|
|
2925
|
+
if (f === "pacifico") return "Pacifico";
|
|
2926
|
+
return fontFamily;
|
|
2927
|
+
}
|
|
2928
|
+
function _buildConfig(effect, text, fontSize, canvasWidth, canvasHeight, time, clipStartTime, clipDuration) {
|
|
2929
|
+
const fill = effect.fills?.[0];
|
|
2930
|
+
const stroke = effect.strokes?.[0];
|
|
2931
|
+
const shadow = effect.shadows?.[0];
|
|
2932
|
+
const bevel = effect.bevel;
|
|
2933
|
+
const panel = effect.panel;
|
|
2934
|
+
const ratio = fontSize / 100;
|
|
2935
|
+
const config = {
|
|
2936
|
+
// Canvas / text
|
|
2937
|
+
width: canvasWidth,
|
|
2938
|
+
height: canvasHeight,
|
|
2939
|
+
canvasWidth,
|
|
2940
|
+
canvasHeight,
|
|
2941
|
+
text,
|
|
2942
|
+
time: time ?? 0,
|
|
2943
|
+
clipStartTime: clipStartTime ?? 0,
|
|
2944
|
+
clipDuration: clipDuration ?? 5,
|
|
2945
|
+
// Font
|
|
2946
|
+
fontFamily: resolveFontFamilyName(effect.font.family),
|
|
2947
|
+
fontWeight: effect.font.weight,
|
|
2948
|
+
fontStyle: effect.font.style,
|
|
2949
|
+
fontSize,
|
|
2950
|
+
letterSpacing: effect.font.letterSpacing,
|
|
2951
|
+
lineHeight: effect.font.lineHeight
|
|
2952
|
+
};
|
|
2953
|
+
if (effect.animation) {
|
|
2954
|
+
config.animation = effect.animation;
|
|
2955
|
+
}
|
|
2956
|
+
if (fill) {
|
|
2957
|
+
if (fill.type !== void 0) config.fillType = fill.type;
|
|
2958
|
+
if (fill.color !== void 0) config.fillColor = fill.color;
|
|
2959
|
+
if (fill.gradient?.angle !== void 0) config.fillGradientAngle = fill.gradient.angle;
|
|
2960
|
+
if (fill.gradient?.stops !== void 0) config.fillGradientStops = fill.gradient.stops;
|
|
2961
|
+
if (fill.patternType !== void 0) config.patternType = fill.patternType;
|
|
2962
|
+
if (fill.perCharFillEnabled !== void 0) config.perCharFillEnabled = fill.perCharFillEnabled;
|
|
2963
|
+
if (fill.charFillColors !== void 0) config.charFillColors = fill.charFillColors;
|
|
2964
|
+
} else {
|
|
2965
|
+
config.fillType = "none";
|
|
2966
|
+
}
|
|
2967
|
+
config.strokeEnabled = !!stroke;
|
|
2968
|
+
if (stroke) {
|
|
2969
|
+
if (stroke.color !== void 0) config.strokeColor = stroke.color;
|
|
2970
|
+
if (stroke.width !== void 0) config.strokeWidth = stroke.width * ratio;
|
|
2971
|
+
if (stroke.position !== void 0) config.strokePosition = stroke.position;
|
|
2972
|
+
if (stroke.opacity !== void 0) config.strokeOpacity = stroke.opacity;
|
|
2973
|
+
if (stroke.lineJoin !== void 0) config.strokeLineJoin = stroke.lineJoin;
|
|
2974
|
+
if (stroke.blur !== void 0) config.strokeBlur = stroke.blur * ratio;
|
|
2975
|
+
if (stroke.type !== void 0) config.strokeType = stroke.type;
|
|
2976
|
+
if (stroke.colorSecondary !== void 0) config.strokeColorSecondary = stroke.colorSecondary;
|
|
2977
|
+
if (stroke.widthSecondary !== void 0) config.strokeWidthSecondary = stroke.widthSecondary * ratio;
|
|
2978
|
+
if (stroke.fadeRange !== void 0) config.strokeFadeRange = stroke.fadeRange;
|
|
2979
|
+
}
|
|
2980
|
+
config.shadowEnabled = !!shadow;
|
|
2981
|
+
if (shadow) {
|
|
2982
|
+
if (shadow.color !== void 0) config.shadowColor = shadow.color;
|
|
2983
|
+
if (shadow.blur !== void 0) config.shadowBlur = shadow.blur * ratio;
|
|
2984
|
+
if (shadow.offsetX !== void 0) config.shadowOffsetX = shadow.offsetX * ratio;
|
|
2985
|
+
if (shadow.offsetY !== void 0) config.shadowOffsetY = shadow.offsetY * ratio;
|
|
2986
|
+
if (shadow.opacity !== void 0) config.shadowOpacity = shadow.opacity;
|
|
2987
|
+
if (shadow.type !== void 0) config.shadowType = shadow.type;
|
|
2988
|
+
}
|
|
2989
|
+
config.bevelEnabled = !!bevel;
|
|
2990
|
+
if (bevel) {
|
|
2991
|
+
if (bevel.depth !== void 0) config.bevelDepth = Math.round(bevel.depth * ratio);
|
|
2992
|
+
if (bevel.highlightColor !== void 0) config.bevelHighlight = bevel.highlightColor;
|
|
2993
|
+
if (bevel.shadowColor !== void 0) config.bevelShadow = bevel.shadowColor;
|
|
2994
|
+
if (bevel.direction !== void 0) config.bevelDirection = bevel.direction;
|
|
2995
|
+
if (bevel.coreColor !== void 0) config.bevelCoreColor = bevel.coreColor;
|
|
2996
|
+
if (bevel.edgeColor !== void 0) config.bevelEdgeColor = bevel.edgeColor;
|
|
2997
|
+
if (bevel.edgeWidth !== void 0) config.bevelEdgeWidth = bevel.edgeWidth * ratio;
|
|
2998
|
+
if (bevel.blur !== void 0) config.bevelBlur = bevel.blur * ratio;
|
|
2999
|
+
if (bevel.blurColor !== void 0) config.bevelBlurColor = bevel.blurColor;
|
|
3000
|
+
if (bevel.perspectiveEnabled !== void 0) config.bevelPerspectiveEnabled = bevel.perspectiveEnabled;
|
|
3001
|
+
if (bevel.vanishingPointX !== void 0) config.bevelVanishingPointX = bevel.vanishingPointX;
|
|
3002
|
+
if (bevel.vanishingPointY !== void 0) config.bevelVanishingPointY = bevel.vanishingPointY;
|
|
3003
|
+
if (bevel.focalLength !== void 0) config.bevelFocalLength = bevel.focalLength;
|
|
3004
|
+
}
|
|
3005
|
+
if (effect.stack) {
|
|
3006
|
+
config.stackEnabled = !!effect.stack.count;
|
|
3007
|
+
if (effect.stack.count !== void 0) config.stackCount = effect.stack.count;
|
|
3008
|
+
if (effect.stack.offsetX !== void 0) config.stackOffsetX = effect.stack.offsetX * ratio;
|
|
3009
|
+
if (effect.stack.offsetY !== void 0) config.stackOffsetY = effect.stack.offsetY * ratio;
|
|
3010
|
+
if (effect.stack.opacityDecay !== void 0) config.stackOpacityDecay = effect.stack.opacityDecay;
|
|
3011
|
+
if (effect.stack.color1 !== void 0) config.stackColor1 = effect.stack.color1;
|
|
3012
|
+
if (effect.stack.color2 !== void 0) config.stackColor2 = effect.stack.color2;
|
|
3013
|
+
if (effect.stack.color3 !== void 0) config.stackColor3 = effect.stack.color3;
|
|
3014
|
+
if (effect.stack.color4 !== void 0) config.stackColor4 = effect.stack.color4;
|
|
3015
|
+
}
|
|
3016
|
+
config.panelEnabled = !!panel;
|
|
3017
|
+
if (panel) {
|
|
3018
|
+
if (panel.color !== void 0) config.panelColor = panel.color;
|
|
3019
|
+
if (panel.opacity !== void 0) config.panelOpacity = panel.opacity;
|
|
3020
|
+
if (panel.radius !== void 0) config.panelRadius = panel.radius;
|
|
3021
|
+
if (panel.paddingX !== void 0) config.panelPaddingX = panel.paddingX * ratio;
|
|
3022
|
+
if (panel.paddingY !== void 0) config.panelPaddingY = panel.paddingY * ratio;
|
|
3023
|
+
if (panel.stroke !== void 0) {
|
|
3024
|
+
config.panelStrokeEnabled = !!panel.stroke;
|
|
3025
|
+
if (panel.stroke.color !== void 0) config.panelStrokeColor = panel.stroke.color;
|
|
3026
|
+
if (panel.stroke.width !== void 0) config.panelStrokeWidth = panel.stroke.width * ratio;
|
|
3027
|
+
}
|
|
3028
|
+
}
|
|
3029
|
+
if (effect.glows) {
|
|
3030
|
+
config.glowLayers = effect.glows.map((g) => {
|
|
3031
|
+
const mappedGlow = {
|
|
3032
|
+
enabled: true,
|
|
3033
|
+
color: g.color,
|
|
3034
|
+
blur: typeof g.blur === "number" ? g.blur * ratio : g.blur ?? 0,
|
|
3035
|
+
opacity: g.opacity,
|
|
3036
|
+
type: g.type ?? "outer"
|
|
3037
|
+
};
|
|
3038
|
+
if (g.strength !== void 0) mappedGlow.strength = g.strength;
|
|
3039
|
+
if (g.spread !== void 0) mappedGlow.spread = g.spread * ratio;
|
|
3040
|
+
return mappedGlow;
|
|
3041
|
+
});
|
|
3042
|
+
}
|
|
3043
|
+
const standardKeys = /* @__PURE__ */ new Set([
|
|
3044
|
+
"id",
|
|
3045
|
+
"name",
|
|
3046
|
+
"category",
|
|
3047
|
+
"description",
|
|
3048
|
+
"tags",
|
|
3049
|
+
"font",
|
|
3050
|
+
"fills",
|
|
3051
|
+
"strokes",
|
|
3052
|
+
"shadows",
|
|
3053
|
+
"glows",
|
|
3054
|
+
"bevel",
|
|
3055
|
+
"panel",
|
|
3056
|
+
"text",
|
|
3057
|
+
"animation",
|
|
3058
|
+
"stack"
|
|
3059
|
+
]);
|
|
3060
|
+
for (const key of Object.keys(effect)) {
|
|
3061
|
+
if (!standardKeys.has(key)) {
|
|
3062
|
+
config[key] = effect[key];
|
|
3063
|
+
}
|
|
3064
|
+
}
|
|
3065
|
+
return config;
|
|
3066
|
+
}
|
|
3067
|
+
function layerToTextEffectConfig(layer2) {
|
|
3068
|
+
const normWeight = typeof layer2.fontWeight === "number" ? layer2.fontWeight : layer2.fontWeight === "bold" ? 700 : 400;
|
|
3069
|
+
const config = {
|
|
3070
|
+
...defaultConfig,
|
|
3071
|
+
width: layer2.width,
|
|
3072
|
+
height: layer2.height,
|
|
3073
|
+
canvasWidth: layer2.width,
|
|
3074
|
+
canvasHeight: layer2.height,
|
|
3075
|
+
text: layer2.text,
|
|
3076
|
+
fontFamily: resolveFontFamilyName(layer2.fontFamily),
|
|
3077
|
+
fontWeight: normWeight,
|
|
3078
|
+
fontStyle: layer2.fontStyle || "normal",
|
|
3079
|
+
fontSize: layer2.fontSize,
|
|
3080
|
+
letterSpacing: layer2.letterSpacing ?? 0,
|
|
3081
|
+
lineHeight: layer2.lineHeight ?? 1.2,
|
|
3082
|
+
fillType: layer2.color ? "solid" : "none",
|
|
3083
|
+
fillColor: layer2.color ?? "#FFFFFF",
|
|
3084
|
+
strokeEnabled: !!layer2.stroke,
|
|
3085
|
+
strokeColor: layer2.stroke?.color ?? "#000000",
|
|
3086
|
+
strokeWidth: layer2.stroke?.width ?? 0,
|
|
3087
|
+
strokePosition: "center",
|
|
3088
|
+
strokeOpacity: 100,
|
|
3089
|
+
strokeLineJoin: "round",
|
|
3090
|
+
shadowEnabled: !!layer2.shadow,
|
|
3091
|
+
shadowColor: layer2.shadow?.color ?? "#000000",
|
|
3092
|
+
shadowBlur: layer2.shadow?.blur ?? 0,
|
|
3093
|
+
shadowOffsetX: layer2.shadow?.offsetX ?? 0,
|
|
3094
|
+
shadowOffsetY: layer2.shadow?.offsetY ?? 0,
|
|
3095
|
+
shadowOpacity: 100,
|
|
3096
|
+
shadowType: "drop",
|
|
3097
|
+
panelEnabled: !!layer2.background,
|
|
3098
|
+
panelColor: layer2.background?.color ?? "#1E1E26",
|
|
3099
|
+
panelOpacity: 80,
|
|
3100
|
+
panelRadius: layer2.background?.borderRadius ?? 6,
|
|
3101
|
+
panelPaddingX: layer2.background?.padding ?? 12,
|
|
3102
|
+
panelPaddingY: layer2.background?.padding ?? 12,
|
|
3103
|
+
textPosX: layer2.textAlign || "center",
|
|
3104
|
+
textPosY: layer2.verticalAlign === "middle" ? "middle" : layer2.verticalAlign || "middle"
|
|
3105
|
+
};
|
|
3106
|
+
return config;
|
|
3107
|
+
}
|
|
2722
3108
|
|
|
2723
3109
|
// src/engine/animation.ts
|
|
2724
3110
|
function ease(t, kind = "linear") {
|
|
@@ -3028,47 +3414,23 @@ function evaluateScene(doc, time, ctx, options = {}) {
|
|
|
3028
3414
|
finishFrame();
|
|
3029
3415
|
return;
|
|
3030
3416
|
}
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
return;
|
|
3038
|
-
}
|
|
3039
|
-
renderTextEffectCore(offCtx, cfg);
|
|
3040
|
-
applyMaskReveal(offCtx, animated, w, h);
|
|
3417
|
+
const temp = CanvasDevice.acquire(w, h);
|
|
3418
|
+
const tctx = temp.getContext("2d");
|
|
3419
|
+
if (tctx) {
|
|
3420
|
+
tctx.clearRect(0, 0, w, h);
|
|
3421
|
+
renderTextEffectCore(tctx, cfg);
|
|
3422
|
+
applyMaskReveal(tctx, animated, w, h);
|
|
3041
3423
|
const compositor = options.compositor ?? getCompositor();
|
|
3042
3424
|
if (compositor?.isSupported) {
|
|
3043
|
-
compositor.renderToContext(ctx,
|
|
3044
|
-
|
|
3045
|
-
}
|
|
3046
|
-
ctx.clearRect(0, 0, w, h);
|
|
3047
|
-
ctx.drawImage(off, 0, 0);
|
|
3048
|
-
return;
|
|
3049
|
-
}
|
|
3050
|
-
if (typeof document !== "undefined") {
|
|
3051
|
-
const temp = document.createElement("canvas");
|
|
3052
|
-
temp.width = w;
|
|
3053
|
-
temp.height = h;
|
|
3054
|
-
const tctx = temp.getContext("2d");
|
|
3055
|
-
if (tctx) {
|
|
3056
|
-
renderTextEffectCore(tctx, cfg);
|
|
3057
|
-
applyMaskReveal(tctx, animated, w, h);
|
|
3058
|
-
const compositor = options.compositor ?? getCompositor();
|
|
3059
|
-
if (compositor?.isSupported) {
|
|
3060
|
-
compositor.renderToContext(ctx, temp, comp);
|
|
3061
|
-
temp.width = 0;
|
|
3062
|
-
temp.height = 0;
|
|
3063
|
-
return;
|
|
3064
|
-
}
|
|
3425
|
+
compositor.renderToContext(ctx, temp, comp);
|
|
3426
|
+
} else {
|
|
3065
3427
|
ctx.clearRect(0, 0, w, h);
|
|
3066
3428
|
ctx.drawImage(temp, 0, 0);
|
|
3067
|
-
temp.width = 0;
|
|
3068
|
-
temp.height = 0;
|
|
3069
|
-
return;
|
|
3070
3429
|
}
|
|
3430
|
+
CanvasDevice.release(temp);
|
|
3431
|
+
return;
|
|
3071
3432
|
}
|
|
3433
|
+
CanvasDevice.release(temp);
|
|
3072
3434
|
renderTextEffectCore(ctx, cfg);
|
|
3073
3435
|
finishFrame();
|
|
3074
3436
|
}
|
|
@@ -6035,6 +6397,7 @@ function duplicateTrackAtPlayhead(doc, trackIndex, previewTime) {
|
|
|
6035
6397
|
export {
|
|
6036
6398
|
COMPOSITION_PRESETS,
|
|
6037
6399
|
CUSTOM_ENGINE_IDS,
|
|
6400
|
+
CanvasDevice,
|
|
6038
6401
|
DEFAULT_CANVAS_HEIGHT,
|
|
6039
6402
|
DEFAULT_CANVAS_WIDTH,
|
|
6040
6403
|
DEFAULT_DURATION,
|
|
@@ -6046,6 +6409,7 @@ export {
|
|
|
6046
6409
|
ENTRANCE_PRESETS,
|
|
6047
6410
|
EXIT_PRESETS,
|
|
6048
6411
|
FONT_WEIGHT_OPTIONS,
|
|
6412
|
+
FontLoader,
|
|
6049
6413
|
InkBrushEngine,
|
|
6050
6414
|
LEGACY_RENDERER_MAP,
|
|
6051
6415
|
LOOP_PRESETS,
|
|
@@ -6057,6 +6421,7 @@ export {
|
|
|
6057
6421
|
TextEffectRenderer,
|
|
6058
6422
|
WEBM_EXPORT_MAX_FRAMES,
|
|
6059
6423
|
WebGLCompositor,
|
|
6424
|
+
_buildConfig,
|
|
6060
6425
|
_resetPlatformCache,
|
|
6061
6426
|
addImageLayer,
|
|
6062
6427
|
addKeyframeAtTime,
|
|
@@ -6114,6 +6479,7 @@ export {
|
|
|
6114
6479
|
encodeGif,
|
|
6115
6480
|
ensureDefaultTimeline,
|
|
6116
6481
|
ensureFontInLottie,
|
|
6482
|
+
ensureFontsLoaded,
|
|
6117
6483
|
evaluateConfig,
|
|
6118
6484
|
evaluateScene,
|
|
6119
6485
|
findTrackIndex,
|
|
@@ -6121,6 +6487,7 @@ export {
|
|
|
6121
6487
|
getAnimatableParamDef,
|
|
6122
6488
|
getAnimatableParamsForLayer,
|
|
6123
6489
|
getDefaultText,
|
|
6490
|
+
getFontLoader,
|
|
6124
6491
|
getLayerById,
|
|
6125
6492
|
getPresetScene,
|
|
6126
6493
|
getSceneTime,
|
|
@@ -6139,6 +6506,7 @@ export {
|
|
|
6139
6506
|
injectText,
|
|
6140
6507
|
injectTextStyle,
|
|
6141
6508
|
isWebMExportSupported,
|
|
6509
|
+
layerToTextEffectConfig,
|
|
6142
6510
|
loadLottieFonts,
|
|
6143
6511
|
lottieColorToHex,
|
|
6144
6512
|
lottieJToAlign,
|
|
@@ -6161,10 +6529,12 @@ export {
|
|
|
6161
6529
|
renderPngSequence,
|
|
6162
6530
|
renderSceneWebM,
|
|
6163
6531
|
renderTextEffectCore,
|
|
6532
|
+
resetFontLoader,
|
|
6164
6533
|
resetSceneTime,
|
|
6165
6534
|
resizeCharFillColors,
|
|
6166
6535
|
resolveAnimatedScalar,
|
|
6167
6536
|
resolveCustomEngineId,
|
|
6537
|
+
resolveFontFamilyName,
|
|
6168
6538
|
restoreLetterSpacing,
|
|
6169
6539
|
scanLottieFonts,
|
|
6170
6540
|
scanTextLayers,
|