@glissade/lottie 0.51.0 → 0.52.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.d.ts +11 -1
- package/dist/index.js +31 -11
- package/package.json +4 -4
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _glissade_scene0 from "@glissade/scene";
|
|
2
|
-
import { Node, SceneModule } from "@glissade/scene";
|
|
2
|
+
import { Node, SceneModule, TextMeasurer } from "@glissade/scene";
|
|
3
3
|
import { Paint, PathContour, PathValue, Timeline, Vec2 } from "@glissade/core";
|
|
4
4
|
|
|
5
5
|
//#region src/spec.d.ts
|
|
@@ -310,6 +310,16 @@ interface ExportOptions {
|
|
|
310
310
|
fps?: number;
|
|
311
311
|
/** Sink for scope-out / degrade warnings; default `console.warn`. */
|
|
312
312
|
onWarn?: (message: string) => void;
|
|
313
|
+
/**
|
|
314
|
+
* Real text measurer (a backend's — e.g. the Skia measurer). When present, a
|
|
315
|
+
* width-wrapped Text node has its wrapped lines BAKED into the Lottie text
|
|
316
|
+
* document `t` (joined by '\n') so the round-trip reproduces glissade's line
|
|
317
|
+
* breaks — the importer copies `t` verbatim and drops the wrap `width`, so
|
|
318
|
+
* without the bake wrapped text collapses onto one line. Absent, the raw
|
|
319
|
+
* string passes through unchanged (the estimating measurer's wrap points
|
|
320
|
+
* wouldn't match a faithful render, so we don't bake with it).
|
|
321
|
+
*/
|
|
322
|
+
measurer?: TextMeasurer;
|
|
313
323
|
}
|
|
314
324
|
/** Convert a SceneModule to a Lottie document. Pure over (scene, timeline). */
|
|
315
325
|
declare function exportLottie(mod: SceneModule, opts: ExportOptions): LottieDocument;
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Circle, Group, ImageNode, Path, Rect, Text, createScene } from "@glissade/scene";
|
|
1
|
+
import { Circle, Group, ImageNode, Path, Rect, Text, breakLines, createScene } from "@glissade/scene";
|
|
2
2
|
import { compileTimeline, cubicBezier, formatColor, parseColor, sampleTrack, track } from "@glissade/core";
|
|
3
3
|
import "@glissade/core/expr";
|
|
4
4
|
//#region src/spec.ts
|
|
@@ -1705,6 +1705,7 @@ const IDENTITY_OPACITY = {
|
|
|
1705
1705
|
/** Convert a SceneModule to a Lottie document. Pure over (scene, timeline). */
|
|
1706
1706
|
function exportLottie(mod, opts) {
|
|
1707
1707
|
const scene = mod.createScene();
|
|
1708
|
+
if (opts.measurer) scene.setTextMeasurer(opts.measurer);
|
|
1708
1709
|
const fr = opts.fps ?? mod.timeline.fps ?? 60;
|
|
1709
1710
|
const warn = opts.onWarn ?? ((m) => console.warn(`gs export: ${m}`));
|
|
1710
1711
|
const compiled = compileTimeline(mod.timeline);
|
|
@@ -1731,7 +1732,8 @@ function exportLottie(mod, opts) {
|
|
|
1731
1732
|
warn,
|
|
1732
1733
|
layers: [],
|
|
1733
1734
|
ind: 0,
|
|
1734
|
-
fonts: /* @__PURE__ */ new Map()
|
|
1735
|
+
fonts: /* @__PURE__ */ new Map(),
|
|
1736
|
+
measurer: opts.measurer
|
|
1735
1737
|
};
|
|
1736
1738
|
walkChildren(ctx, scene.root.children, void 0, byNode, IDENTITY_OPACITY);
|
|
1737
1739
|
const fonts = [...ctx.fonts.values()];
|
|
@@ -2056,13 +2058,30 @@ function registerFont(ctx, node) {
|
|
|
2056
2058
|
function alignToJustification(align) {
|
|
2057
2059
|
return align === "left" ? 0 : align === "right" ? 1 : 2;
|
|
2058
2060
|
}
|
|
2061
|
+
/**
|
|
2062
|
+
* The FontSpec at `t` for the wrap measurement, mirroring `Text.fontSpec()` but
|
|
2063
|
+
* with the SAMPLED size so animated `fontSize` re-wraps per frame. Weight, style,
|
|
2064
|
+
* static variable-font axes, and letter-spacing all feed `measureText` (they move
|
|
2065
|
+
* wrap points), so they must be present to match the reference render's breaks.
|
|
2066
|
+
*/
|
|
2067
|
+
function wrapFontSpec(node, size) {
|
|
2068
|
+
return {
|
|
2069
|
+
family: node.fontFamily,
|
|
2070
|
+
size,
|
|
2071
|
+
weight: node.fontWeight,
|
|
2072
|
+
...node.fontStyle === "italic" ? { style: "italic" } : {},
|
|
2073
|
+
...node.fontVariationSettings !== void 0 ? { fontVariationSettings: node.fontVariationSettings } : {},
|
|
2074
|
+
...node.letterSpacing !== void 0 ? { letterSpacing: node.letterSpacing } : {}
|
|
2075
|
+
};
|
|
2076
|
+
}
|
|
2059
2077
|
/** The text document at time `t`, sampling the animatable text/fill/fontSize props. */
|
|
2060
|
-
function textDocAt(node, fName, tracks, t) {
|
|
2061
|
-
const
|
|
2078
|
+
function textDocAt(ctx, node, fName, tracks, t) {
|
|
2079
|
+
const rawText = sampleStr(tracks, "text", node.text(), t);
|
|
2062
2080
|
const fill = sampleColor(tracks, "fill", node.fill(), t);
|
|
2063
2081
|
const size = sampleNum(tracks, "fontSize", node.fontSize(), t);
|
|
2082
|
+
const width = sampleNum(tracks, "width", node.width(), t);
|
|
2064
2083
|
return {
|
|
2065
|
-
t:
|
|
2084
|
+
t: width > 0 && ctx.measurer !== void 0 ? breakLines(rawText, wrapFontSpec(node, size), width, ctx.measurer).join("\n") : rawText,
|
|
2066
2085
|
f: fName,
|
|
2067
2086
|
s: size,
|
|
2068
2087
|
fc: colorToLottie(fill),
|
|
@@ -2096,16 +2115,17 @@ function buildTextDocKeyframes(ctx, node, fName, tracks) {
|
|
|
2096
2115
|
"fill",
|
|
2097
2116
|
"fontSize"
|
|
2098
2117
|
];
|
|
2099
|
-
|
|
2118
|
+
const streamProps = ctx.measurer !== void 0 && tracks.has("width") ? [...docProps, "width"] : docProps;
|
|
2119
|
+
if (!streamProps.some((p) => tracks.has(p))) return [{
|
|
2100
2120
|
t: ctx.ip,
|
|
2101
|
-
s: textDocAt(node, fName, tracks, ctx.ip / ctx.fr)
|
|
2121
|
+
s: textDocAt(ctx, node, fName, tracks, ctx.ip / ctx.fr)
|
|
2102
2122
|
}];
|
|
2103
|
-
ctx.warn(`${describe(node)}: animated text/fill/fontSize is sampled at ${ctx.fr} fps into stepped text documents (not smoothly interpolated)`);
|
|
2104
|
-
const [f0, f1] = frameSpan(ctx,
|
|
2123
|
+
if (docProps.some((p) => tracks.has(p))) ctx.warn(`${describe(node)}: animated text/fill/fontSize is sampled at ${ctx.fr} fps into stepped text documents (not smoothly interpolated)`);
|
|
2124
|
+
const [f0, f1] = frameSpan(ctx, streamProps.map((p) => tracks.get(p)));
|
|
2105
2125
|
const keys = [];
|
|
2106
2126
|
let prev;
|
|
2107
2127
|
for (let f = f0; f <= f1; f++) {
|
|
2108
|
-
const s = textDocAt(node, fName, tracks, f / ctx.fr);
|
|
2128
|
+
const s = textDocAt(ctx, node, fName, tracks, f / ctx.fr);
|
|
2109
2129
|
const sig = JSON.stringify(s);
|
|
2110
2130
|
if (sig === prev) continue;
|
|
2111
2131
|
keys.push({
|
|
@@ -2122,7 +2142,7 @@ function warnTextUnsupported(ctx, node, tracks) {
|
|
|
2122
2142
|
if (tracks.has("revealFraction") || !Number.isNaN(node.revealFraction())) ctx.warn(`${describe(node)}: 'revealFraction' is not exported — dropped, full text shown`);
|
|
2123
2143
|
if (tracks.has("fontAxes") || Object.keys(node.fontAxes()).length > 0 || node.fontVariationSettings !== void 0) ctx.warn(`${describe(node)}: variable-font axes (fontAxes/fontVariationSettings) have no Lottie text-document field — dropped`);
|
|
2124
2144
|
if (node.box !== void 0) ctx.warn(`${describe(node)}: box valign is approximated as baseline-anchored (no Lottie ink-box anchor) — vertical placement may shift`);
|
|
2125
|
-
if (tracks.has("width") || node.width() > 0) ctx.warn(`${describe(node)}: wrap 'width' relies on the player's own line reflow — wrapping may diverge from glissade's`);
|
|
2145
|
+
if (ctx.measurer === void 0 && (tracks.has("width") || node.width() > 0)) ctx.warn(`${describe(node)}: wrap 'width' relies on the player's own line reflow — wrapping may diverge from glissade's`);
|
|
2126
2146
|
}
|
|
2127
2147
|
function buildTextLayer(ctx, node, ind, parentInd, tracks, opacity) {
|
|
2128
2148
|
const fName = registerFont(ctx, node);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@glissade/lottie",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.52.0",
|
|
4
4
|
"description": "glissade Lottie import (S1 MVP): pure .json (Lottie/bodymovin) → node specs + a v1 Timeline. Fail-fast feature audit; no DOM/Node dependencies.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"engines": {
|
|
@@ -18,11 +18,11 @@
|
|
|
18
18
|
"dist"
|
|
19
19
|
],
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@glissade/core": "0.
|
|
22
|
-
"@glissade/scene": "0.
|
|
21
|
+
"@glissade/core": "0.52.0",
|
|
22
|
+
"@glissade/scene": "0.52.0"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
|
-
"@glissade/backend-skia": "0.
|
|
25
|
+
"@glissade/backend-skia": "0.52.0"
|
|
26
26
|
},
|
|
27
27
|
"repository": {
|
|
28
28
|
"type": "git",
|