@pixerate/flair 0.24.0 → 0.25.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/CHANGELOG.md +12 -0
- package/dist/catalog/index.js +2 -2
- package/dist/chunk-DBTLCXKY.js +332 -0
- package/dist/chunk-DBTLCXKY.js.map +1 -0
- package/dist/{chunk-VP6IEWIK.js → chunk-H6L67KHI.js} +1 -1
- package/dist/chunk-H6VDFBIO.js +498 -0
- package/dist/chunk-H6VDFBIO.js.map +1 -0
- package/dist/chunk-JL6TI6II.js +724 -0
- package/dist/chunk-JL6TI6II.js.map +1 -0
- package/dist/{chunk-NGKNI3QX.js → chunk-O44ZJTGG.js} +5 -485
- package/dist/chunk-O44ZJTGG.js.map +1 -0
- package/dist/chunk-OKYMKSXK.js +414 -0
- package/dist/chunk-OKYMKSXK.js.map +1 -0
- package/dist/{chunk-OHW7UG6D.js → chunk-ORAFCHX3.js} +26 -2
- package/dist/{chunk-OHW7UG6D.js.map → chunk-ORAFCHX3.js.map} +1 -1
- package/dist/{chunk-OQ4EWZ3B.js → chunk-PYDN5G2P.js} +5 -5
- package/dist/{chunk-ARKC7LDW.js → chunk-RDU63CDO.js} +2 -331
- package/dist/chunk-RDU63CDO.js.map +1 -0
- package/dist/chunk-S2RGHHKZ.js +902 -0
- package/dist/chunk-S2RGHHKZ.js.map +1 -0
- package/dist/{chunk-LVPIIWPP.js → chunk-STKEKXCK.js} +18 -8
- package/dist/chunk-STKEKXCK.js.map +1 -0
- package/dist/chunk-YBGRXVAE.js +407 -0
- package/dist/chunk-YBGRXVAE.js.map +1 -0
- package/dist/cli.js +68 -5
- package/dist/cli.js.map +1 -1
- package/dist/editor/index.d.ts +1 -1
- package/dist/editor/index.js +14 -12
- package/dist/editor/index.js.map +1 -1
- package/dist/effect-26CPF5HS.js +47 -0
- package/dist/embed/index.d.ts +215 -0
- package/dist/embed/index.js +21 -0
- package/dist/embed/index.js.map +1 -0
- package/dist/frames-VEcqa40g.d.ts +161 -0
- package/dist/index.d.ts +6 -163
- package/dist/index.js +86 -78
- package/dist/index.js.map +1 -1
- package/dist/node.d.ts +167 -7
- package/dist/node.js +25 -3
- package/dist/react/index.d.ts +33 -2
- package/dist/react/index.js +54 -9
- package/dist/react/index.js.map +1 -1
- package/dist/recorder-CDPPTJMG.js +31 -0
- package/dist/recorder-CDPPTJMG.js.map +1 -0
- package/dist/{renderer-C2P1qGzP.d.ts → renderer-teaa98RE.d.ts} +1 -1
- package/dist/svelte/index.d.ts +33 -4
- package/dist/svelte/index.js +51 -9
- package/dist/svelte/index.js.map +1 -1
- package/dist/vector/index.d.ts +52 -1
- package/dist/vector/index.js +8 -4
- package/package.json +1 -1
- package/dist/chunk-ARKC7LDW.js.map +0 -1
- package/dist/chunk-LVPIIWPP.js.map +0 -1
- package/dist/chunk-NGKNI3QX.js.map +0 -1
- package/dist/chunk-UP6QQVRS.js +0 -331
- package/dist/chunk-UP6QQVRS.js.map +0 -1
- package/dist/recorder-HKFFHQES.js +0 -10
- /package/dist/{chunk-VP6IEWIK.js.map → chunk-H6L67KHI.js.map} +0 -0
- /package/dist/{chunk-OQ4EWZ3B.js.map → chunk-PYDN5G2P.js.map} +0 -0
- /package/dist/{recorder-HKFFHQES.js.map → effect-26CPF5HS.js.map} +0 -0
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getAttr,
|
|
3
|
+
serialize,
|
|
4
|
+
setAttr,
|
|
5
|
+
svgFrameTree
|
|
6
|
+
} from "./chunk-STKEKXCK.js";
|
|
7
|
+
import {
|
|
8
|
+
STEP_MS,
|
|
9
|
+
SVG_PICTURE,
|
|
10
|
+
stepStart,
|
|
11
|
+
svgDuration,
|
|
12
|
+
svgFrame
|
|
13
|
+
} from "./chunk-PFGGPIMT.js";
|
|
14
|
+
import {
|
|
15
|
+
pathPointAt
|
|
16
|
+
} from "./chunk-ORAFCHX3.js";
|
|
17
|
+
|
|
18
|
+
// src/vector/animated.ts
|
|
19
|
+
var SPLINES = { linear: "0 0 1 1", in: "0.3333 0 0.6667 0", out: "0.3333 1 0.6667 1" };
|
|
20
|
+
var HALFWAY = { linear: 0.5, "in-out": 0.5, out: 1 - 0.5 ** (1 / 3) };
|
|
21
|
+
var NUMBER = /-?(?:\d+\.?\d*|\.\d+)(?:e[-+]?\d+)?/gi;
|
|
22
|
+
var HEX = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i;
|
|
23
|
+
var TRANSFORMS = /* @__PURE__ */ new Set(["transform", "gradienttransform", "patterntransform"]);
|
|
24
|
+
var URL_REF = /url\(\s*(['"]?)#([^'")\s]+)\1\s*\)/g;
|
|
25
|
+
function blends(a, b) {
|
|
26
|
+
if (typeof a === "number" && typeof b === "number") return true;
|
|
27
|
+
const [sa, sb] = [String(a), String(b)];
|
|
28
|
+
if (HEX.test(sa) && HEX.test(sb)) return true;
|
|
29
|
+
const na = sa.match(NUMBER) ?? [];
|
|
30
|
+
return na.length > 0 && na.length === (sb.match(NUMBER) ?? []).length && sa.replace(NUMBER, "#") === sb.replace(NUMBER, "#");
|
|
31
|
+
}
|
|
32
|
+
var num = (n) => String(+n.toFixed(3));
|
|
33
|
+
function hash(s) {
|
|
34
|
+
let h = 2166136261;
|
|
35
|
+
for (let i = 0; i < s.length; i++) h = Math.imul(h ^ s.charCodeAt(i), 16777619);
|
|
36
|
+
return (h >>> 0).toString(36);
|
|
37
|
+
}
|
|
38
|
+
var node = (tag, attrs, children = []) => ({
|
|
39
|
+
tag,
|
|
40
|
+
attrs: Object.entries(attrs).filter((e) => e[1] !== void 0),
|
|
41
|
+
children
|
|
42
|
+
});
|
|
43
|
+
function transformList(value) {
|
|
44
|
+
return [...value.matchAll(/([a-z]+)\s*\(([^)]*)\)/gi)].map((m) => [m[1], (m[2].match(NUMBER) ?? []).map(Number)]);
|
|
45
|
+
}
|
|
46
|
+
function transformMatrix(value) {
|
|
47
|
+
let m = [1, 0, 0, 1, 0, 0];
|
|
48
|
+
const times = (n) => {
|
|
49
|
+
const [a, b, c, d, e, f] = m;
|
|
50
|
+
m = [a * n[0] + c * n[1], b * n[0] + d * n[1], a * n[2] + c * n[3], b * n[2] + d * n[3], a * n[4] + c * n[5] + e, b * n[4] + d * n[5] + f];
|
|
51
|
+
};
|
|
52
|
+
const rad = Math.PI / 180;
|
|
53
|
+
for (const [name, [p = 0, q, r = 0, s = 0, t = 0, u = 0]] of transformList(value)) {
|
|
54
|
+
if (name === "translate") times([1, 0, 0, 1, p, q ?? 0]);
|
|
55
|
+
else if (name === "scale") times([p, 0, 0, q ?? p, 0, 0]);
|
|
56
|
+
else if (name === "rotate") {
|
|
57
|
+
const [cos, sin] = [Math.cos(p * rad), Math.sin(p * rad)];
|
|
58
|
+
const [cx, cy] = [q ?? 0, r];
|
|
59
|
+
times([1, 0, 0, 1, cx, cy]);
|
|
60
|
+
times([cos, sin, -sin, cos, 0, 0]);
|
|
61
|
+
times([1, 0, 0, 1, -cx, -cy]);
|
|
62
|
+
} else if (name === "skewX") times([1, 0, Math.tan(p * rad), 1, 0, 0]);
|
|
63
|
+
else if (name === "skewY") times([1, Math.tan(p * rad), 0, 1, 0, 0]);
|
|
64
|
+
else if (name === "matrix") times([p, q ?? 0, r, s, t, u]);
|
|
65
|
+
}
|
|
66
|
+
return m;
|
|
67
|
+
}
|
|
68
|
+
function decompose([a, b, c, d, e, f]) {
|
|
69
|
+
const sx = Math.hypot(a, b);
|
|
70
|
+
const angle = sx ? Math.atan2(b, a) : 0;
|
|
71
|
+
const [cos, sin] = [Math.cos(angle), Math.sin(angle)];
|
|
72
|
+
const sy = -sin * c + cos * d;
|
|
73
|
+
const skew = sy ? Math.atan((cos * c + sin * d) / sy) : 0;
|
|
74
|
+
return [e, f, angle * 180 / Math.PI, skew * 180 / Math.PI, sx, sy];
|
|
75
|
+
}
|
|
76
|
+
function outline(el) {
|
|
77
|
+
const at = (name) => Number(getAttr(el, name) ?? 0);
|
|
78
|
+
switch (el.tag.toLowerCase()) {
|
|
79
|
+
case "path":
|
|
80
|
+
return getAttr(el, "d");
|
|
81
|
+
case "line":
|
|
82
|
+
return `M${at("x1")} ${at("y1")}L${at("x2")} ${at("y2")}`;
|
|
83
|
+
case "polyline":
|
|
84
|
+
case "polygon":
|
|
85
|
+
return `M${getAttr(el, "points") ?? ""}${el.tag.toLowerCase() === "polygon" ? "Z" : ""}`;
|
|
86
|
+
default:
|
|
87
|
+
return void 0;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function timing(keys, loop, repeat, discrete = false) {
|
|
91
|
+
const spline = !discrete && keys.some((k, i) => i > 0 && k.shape !== "linear");
|
|
92
|
+
return {
|
|
93
|
+
...clock(loop, repeat),
|
|
94
|
+
keyTimes: keys.map((k) => String(+(k.t / loop).toFixed(5))).join(";"),
|
|
95
|
+
calcMode: discrete ? "discrete" : spline ? "spline" : "linear",
|
|
96
|
+
keySplines: spline ? keys.slice(1).map((k) => SPLINES[k.shape]).join(";") : void 0
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
var clock = (loop, repeat) => ({
|
|
100
|
+
dur: `${+(loop / 1e3).toFixed(4)}s`,
|
|
101
|
+
repeatCount: repeat ? "indefinite" : void 0,
|
|
102
|
+
fill: repeat ? void 0 : "freeze"
|
|
103
|
+
});
|
|
104
|
+
function collapse(keys) {
|
|
105
|
+
const out = [];
|
|
106
|
+
keys.forEach((k, i) => {
|
|
107
|
+
const prev = out[out.length - 1];
|
|
108
|
+
if (prev && prev.v === k.v && (prev.t === k.t || keys[i + 1]?.v === k.v && i < keys.length - 1)) return;
|
|
109
|
+
out.push(k);
|
|
110
|
+
});
|
|
111
|
+
return out;
|
|
112
|
+
}
|
|
113
|
+
function runs(keys) {
|
|
114
|
+
const out = [];
|
|
115
|
+
for (const k of keys) {
|
|
116
|
+
const prev = out[out.length - 1];
|
|
117
|
+
if (prev?.t === k.t) out.pop();
|
|
118
|
+
if (out[out.length - 1]?.v !== k.v) out.push(k);
|
|
119
|
+
}
|
|
120
|
+
return out;
|
|
121
|
+
}
|
|
122
|
+
function svgAnimatedMarkup(motion, options = {}) {
|
|
123
|
+
const steps = options.steps ?? [];
|
|
124
|
+
const repeat = options.loop ?? true;
|
|
125
|
+
const fps = options.fps ?? 30;
|
|
126
|
+
const loop = Math.max(1, options.duration ?? svgDuration(motion, steps) + (options.hold ?? 600));
|
|
127
|
+
const animations = motion.animate ?? [];
|
|
128
|
+
const tree = svgFrameTree(motion, steps, 0);
|
|
129
|
+
if (!tree) return void 0;
|
|
130
|
+
const { svg, byId, whole } = tree;
|
|
131
|
+
const tracks = /* @__PURE__ */ new Map();
|
|
132
|
+
animations.forEach((anim) => {
|
|
133
|
+
const s = stepStart(steps, anim.step ?? 0);
|
|
134
|
+
const start = s === void 0 ? Infinity : s + (anim.delay ?? 0);
|
|
135
|
+
const add2 = (prop) => {
|
|
136
|
+
const key = `${prop === "view" ? SVG_PICTURE : anim.id}\0${prop}`;
|
|
137
|
+
tracks.set(key, [...tracks.get(key) ?? [], { anim, start }]);
|
|
138
|
+
};
|
|
139
|
+
for (const name of Object.keys(anim.attrs ?? {})) add2(`@${name}`);
|
|
140
|
+
if (anim.draw) add2("draw");
|
|
141
|
+
if (anim.count || anim.write !== void 0) add2("text");
|
|
142
|
+
if (anim.solo !== void 0) add2("solo");
|
|
143
|
+
if (anim.view !== void 0) add2("view");
|
|
144
|
+
if (anim.along) add2("along");
|
|
145
|
+
});
|
|
146
|
+
for (const list of tracks.values()) list.sort((x, y) => x.start - y.start);
|
|
147
|
+
const frames = /* @__PURE__ */ new Map();
|
|
148
|
+
const frameAt = (t) => {
|
|
149
|
+
let f = frames.get(t);
|
|
150
|
+
if (!f) frames.set(t, f = svgFrame(animations, steps, t));
|
|
151
|
+
return f;
|
|
152
|
+
};
|
|
153
|
+
const boxOf = (v) => v === null ? whole : typeof v === "string" ? void 0 : v;
|
|
154
|
+
const read = (frame, id, prop) => {
|
|
155
|
+
const f = frame.get(id);
|
|
156
|
+
if (!f) return void 0;
|
|
157
|
+
if (prop.startsWith("@")) return f.attrs[prop.slice(1)];
|
|
158
|
+
if (prop === "draw") return f.draw === void 0 ? void 0 : num(1 - f.draw);
|
|
159
|
+
if (prop === "along") return f.along && num(f.along.at);
|
|
160
|
+
if (prop === "solo") return f.solo === void 0 ? void 0 : String(f.solo);
|
|
161
|
+
if (prop === "text") return f.text;
|
|
162
|
+
if (!f.view) return void 0;
|
|
163
|
+
const [a, b] = [boxOf(f.view.from), boxOf(f.view.to)];
|
|
164
|
+
const box = a && b ? a.map((n, i) => n + (b[i] - n) * f.view.u) : b ?? a ?? whole;
|
|
165
|
+
return box?.map(num).join(" ");
|
|
166
|
+
};
|
|
167
|
+
const keyframes = (id, prop, list, sampled = false) => {
|
|
168
|
+
const shown = list.filter((c, i) => c.start < loop && !(list[i + 1] && list[i + 1].start <= c.start));
|
|
169
|
+
const value = (k, t) => read(svgFrame(shown.slice(Math.max(0, k - 1), k + 1).map((c) => c.anim), steps, t), id, prop) ?? "";
|
|
170
|
+
const keys = [];
|
|
171
|
+
const push = (t, v, shape = "linear") => keys.push({ t, v, shape });
|
|
172
|
+
if (!shown.length) return [];
|
|
173
|
+
push(0, read(frameAt(0), id, prop) ?? value(0, 0));
|
|
174
|
+
shown.forEach((c, k) => {
|
|
175
|
+
const next = Math.min(shown[k + 1]?.start ?? loop, loop);
|
|
176
|
+
const ms = c.anim.ms ?? STEP_MS;
|
|
177
|
+
const end = Math.min(c.start + ms, next);
|
|
178
|
+
push(c.start, keys[keys.length - 1].v);
|
|
179
|
+
push(c.start, value(k, c.start));
|
|
180
|
+
if (!(ms > 0)) return;
|
|
181
|
+
const ease = c.anim.ease ?? "in-out";
|
|
182
|
+
const pair = prop.startsWith("@") ? c.anim.attrs[prop.slice(1)] : void 0;
|
|
183
|
+
if (pair && !blends(pair[0], pair[1])) {
|
|
184
|
+
const at = c.start + ms * HALFWAY[ease];
|
|
185
|
+
if (at < next) {
|
|
186
|
+
push(at, value(k, c.start));
|
|
187
|
+
push(at, value(k, end));
|
|
188
|
+
}
|
|
189
|
+
} else if (!sampled && end === c.start + ms && ease !== "linear") {
|
|
190
|
+
if (ease === "in-out") push(c.start + ms / 2, value(k, c.start + ms / 2), "in");
|
|
191
|
+
push(end, value(k, end), "out");
|
|
192
|
+
} else if (!sampled && ease === "linear") push(end, value(k, end));
|
|
193
|
+
else {
|
|
194
|
+
for (let t = c.start + 1e3 / fps; t < end; t += 1e3 / fps) push(t, value(k, t));
|
|
195
|
+
push(end, value(k, end));
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
if (keys[keys.length - 1].t < loop) push(loop, keys[keys.length - 1].v);
|
|
199
|
+
return collapse(keys);
|
|
200
|
+
};
|
|
201
|
+
const sampleTimes = (list) => {
|
|
202
|
+
const times = /* @__PURE__ */ new Set();
|
|
203
|
+
for (let t = 0; t < loop; t += 1e3 / fps) times.add(+t.toFixed(3));
|
|
204
|
+
for (const c of list)
|
|
205
|
+
for (const t of [c.start, c.start + (c.anim.ms ?? STEP_MS)]) if (t < loop) times.add(t);
|
|
206
|
+
return [...times].sort((a, b) => a - b);
|
|
207
|
+
};
|
|
208
|
+
const added = /* @__PURE__ */ new Map();
|
|
209
|
+
const add = (el, ...anims) => added.set(el, [...added.get(el) ?? [], ...anims]);
|
|
210
|
+
const animate = (name, keys, values = keys.map((k) => k.v), discrete = false) => node("animate", { attributeName: name, values: values.join(";"), ...timing(keys, loop, repeat, discrete) });
|
|
211
|
+
const followers = new Set(animations.filter((a) => a.along).map((a) => a.id));
|
|
212
|
+
let viewKeys;
|
|
213
|
+
for (const [key, list] of tracks) {
|
|
214
|
+
const [id, prop] = key.split("\0");
|
|
215
|
+
const el = id === SVG_PICTURE ? svg : byId.get(id);
|
|
216
|
+
if (!el) continue;
|
|
217
|
+
const name = prop.slice(1);
|
|
218
|
+
if (prop === "text") {
|
|
219
|
+
const own = list.map((c) => c.anim);
|
|
220
|
+
const text = (t) => read(svgFrame(own, steps, t), id, prop) ?? "";
|
|
221
|
+
const shown = [];
|
|
222
|
+
let last = -1;
|
|
223
|
+
for (const t of sampleTimes(list)) {
|
|
224
|
+
const v = text(t);
|
|
225
|
+
if (shown.length && v !== shown[shown.length - 1].v) {
|
|
226
|
+
let [lo, hi] = [last, t];
|
|
227
|
+
while (hi - lo > 0.5) {
|
|
228
|
+
const mid = (lo + hi) / 2;
|
|
229
|
+
if (text(mid) === shown[shown.length - 1].v) lo = mid;
|
|
230
|
+
else hi = mid;
|
|
231
|
+
}
|
|
232
|
+
shown.push({ t: text(hi) === v ? hi : (last + t) / 2, v, shape: "linear" });
|
|
233
|
+
}
|
|
234
|
+
if (v !== shown[shown.length - 1]?.v) shown.push({ t, v, shape: "linear" });
|
|
235
|
+
last = t;
|
|
236
|
+
}
|
|
237
|
+
const texts = [...new Set(shown.map((k) => k.v))];
|
|
238
|
+
el.children = texts.map((value, i) => {
|
|
239
|
+
const keys2 = runs(shown.map((k) => ({ ...k, v: k.v === value ? "inline" : "none" })));
|
|
240
|
+
const span = node("tspan", { display: i === 0 ? void 0 : "none" }, [value]);
|
|
241
|
+
if (keys2.length > 1) span.children.push(animate("display", keys2, void 0, true));
|
|
242
|
+
return span;
|
|
243
|
+
});
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
if (prop.startsWith("@") && TRANSFORMS.has(name.toLowerCase())) {
|
|
247
|
+
if (followers.has(id) && name === "transform") continue;
|
|
248
|
+
let keys2 = keyframes(id, prop, list);
|
|
249
|
+
if (keys2.length < 2) continue;
|
|
250
|
+
const lists = keys2.map((k) => transformList(k.v));
|
|
251
|
+
const shape = (l) => l.map(([f, args]) => `${f}${args.length}`).join(" ");
|
|
252
|
+
if (lists.every((l) => shape(l) === shape(lists[0])) && !/matrix|skewY/.test(shape(lists[0]))) {
|
|
253
|
+
lists[0].forEach(
|
|
254
|
+
([type], j) => add(el, node("animateTransform", {
|
|
255
|
+
attributeName: name,
|
|
256
|
+
type,
|
|
257
|
+
additive: j ? "sum" : void 0,
|
|
258
|
+
values: lists.map((l) => l[j][1].map(num).join(" ")).join(";"),
|
|
259
|
+
...timing(keys2, loop, repeat)
|
|
260
|
+
}))
|
|
261
|
+
);
|
|
262
|
+
} else {
|
|
263
|
+
keys2 = keyframes(id, prop, list, true);
|
|
264
|
+
const parts = keys2.map((k) => decompose(transformMatrix(k.v)));
|
|
265
|
+
parts.forEach((p, i) => {
|
|
266
|
+
const before = parts[i - 1];
|
|
267
|
+
if (before) p[2] += 360 * Math.round((before[2] - p[2]) / 360);
|
|
268
|
+
});
|
|
269
|
+
const types = [
|
|
270
|
+
["translate", (p) => [p[0], p[1]]],
|
|
271
|
+
["rotate", (p) => [p[2]]],
|
|
272
|
+
["skewX", (p) => [p[3]]],
|
|
273
|
+
["scale", (p) => [p[4], p[5]]]
|
|
274
|
+
];
|
|
275
|
+
types.forEach(
|
|
276
|
+
([type, pick], j) => add(el, node("animateTransform", {
|
|
277
|
+
attributeName: name,
|
|
278
|
+
type,
|
|
279
|
+
additive: j ? "sum" : void 0,
|
|
280
|
+
values: parts.map((p) => pick(p).map(num).join(" ")).join(";"),
|
|
281
|
+
...timing(keys2, loop, repeat)
|
|
282
|
+
}))
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
continue;
|
|
286
|
+
}
|
|
287
|
+
if (prop === "along") {
|
|
288
|
+
const paths = new Set(list.map((c) => c.anim.along));
|
|
289
|
+
const pathEl = byId.get([...paths][0]);
|
|
290
|
+
const d = pathEl && outline(pathEl);
|
|
291
|
+
if (!d) continue;
|
|
292
|
+
const point = (at) => pathPointAt(d, Number(at));
|
|
293
|
+
const first = point(read(frameAt(0), id, prop) ?? "0");
|
|
294
|
+
if (first) setAttr(el, "transform", `translate(${num(first[0])} ${num(first[1])})`);
|
|
295
|
+
if (paths.size === 1 && pathEl.tag.toLowerCase() === "path") {
|
|
296
|
+
const keys2 = keyframes(id, prop, list);
|
|
297
|
+
add(
|
|
298
|
+
el,
|
|
299
|
+
node("animateTransform", { attributeName: "transform", type: "translate", values: "0 0", ...clock(loop, repeat) }),
|
|
300
|
+
node("animateMotion", { keyPoints: keys2.map((k) => k.v).join(";"), ...timing(keys2, loop, repeat) }, [
|
|
301
|
+
node("mpath", { href: `#${[...paths][0]}` })
|
|
302
|
+
])
|
|
303
|
+
);
|
|
304
|
+
} else {
|
|
305
|
+
const keys2 = sampleTimes(list).map((t) => {
|
|
306
|
+
const f = frameAt(t).get(id)?.along;
|
|
307
|
+
const p = f && byId.get(f.path) && pathPointAt(outline(byId.get(f.path)) ?? "", f.at);
|
|
308
|
+
return { t, v: p ? `${num(p[0])} ${num(p[1])}` : "0 0", shape: "linear" };
|
|
309
|
+
});
|
|
310
|
+
keys2.push({ t: loop, v: keys2[keys2.length - 1].v, shape: "linear" });
|
|
311
|
+
const ks = collapse(keys2);
|
|
312
|
+
add(el, node("animateTransform", { attributeName: "transform", type: "translate", values: ks.map((k) => k.v).join(";"), ...timing(ks, loop, repeat) }));
|
|
313
|
+
}
|
|
314
|
+
continue;
|
|
315
|
+
}
|
|
316
|
+
const keys = keyframes(id, prop, list);
|
|
317
|
+
if (keys.length < 2) continue;
|
|
318
|
+
if (prop === "solo") {
|
|
319
|
+
const shown = runs(keys);
|
|
320
|
+
let i = 0;
|
|
321
|
+
for (const child of el.children) {
|
|
322
|
+
if (typeof child === "string") continue;
|
|
323
|
+
const index = String(i++);
|
|
324
|
+
const toggles = runs(shown.map((k) => ({ ...k, v: k.v === index ? "inline" : "none" })));
|
|
325
|
+
if (toggles.length > 1) add(child, animate("display", toggles, void 0, true));
|
|
326
|
+
}
|
|
327
|
+
} else if (prop === "view") {
|
|
328
|
+
viewKeys = keys;
|
|
329
|
+
add(svg, animate("viewBox", keys));
|
|
330
|
+
} else add(el, animate(prop === "draw" ? "stroke-dashoffset" : name, keys));
|
|
331
|
+
}
|
|
332
|
+
if (viewKeys && whole) {
|
|
333
|
+
const boxes = viewKeys.map((k) => k.v.split(" ").map(Number));
|
|
334
|
+
const all = [];
|
|
335
|
+
const walk = (n) => {
|
|
336
|
+
all.push(n);
|
|
337
|
+
for (const c of n.children) if (typeof c !== "string") walk(c);
|
|
338
|
+
};
|
|
339
|
+
walk(svg);
|
|
340
|
+
const zooms = boxes.map((b) => num(b[2] / whole[2]));
|
|
341
|
+
for (const el of all.filter((n) => getAttr(n, "data-nonscaling") !== void 0)) {
|
|
342
|
+
setAttr(el, "transform", zooms[0] === "1" ? void 0 : `scale(${zooms[0]})`);
|
|
343
|
+
add(el, node("animateTransform", { attributeName: "transform", type: "scale", values: zooms.join(";"), ...timing(viewKeys, loop, repeat) }));
|
|
344
|
+
}
|
|
345
|
+
const fixed = all.filter((n) => getAttr(n, "data-fixed") !== void 0);
|
|
346
|
+
const top = fixed.filter((n) => !fixed.some((f) => f !== n && contains(f, n)));
|
|
347
|
+
if (top.length) {
|
|
348
|
+
for (const el of top) for (const n of all) n.children = n.children.filter((c) => c !== el);
|
|
349
|
+
const fit = boxes.map(([x, y, w, h]) => {
|
|
350
|
+
const k = Math.min(w / whole[2], h / whole[3]);
|
|
351
|
+
return { at: `${num(x + (w - whole[2] * k) / 2 - whole[0] * k)} ${num(y + (h - whole[3] * k) / 2 - whole[1] * k)}`, k: num(k) };
|
|
352
|
+
});
|
|
353
|
+
const layer = node("g", { transform: `translate(${fit[0].at}) scale(${fit[0].k})` }, top);
|
|
354
|
+
add(
|
|
355
|
+
layer,
|
|
356
|
+
node("animateTransform", { attributeName: "transform", type: "translate", values: fit.map((f) => f.at).join(";"), ...timing(viewKeys, loop, repeat) }),
|
|
357
|
+
node("animateTransform", { attributeName: "transform", type: "scale", additive: "sum", values: fit.map((f) => f.k).join(";"), ...timing(viewKeys, loop, repeat) })
|
|
358
|
+
);
|
|
359
|
+
svg.children.push(layer);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
for (const [el, anims] of added) el.children.push(...anims);
|
|
363
|
+
scopeIds(svg, options.idSuffix ?? hash(motion.svg + JSON.stringify(animations)));
|
|
364
|
+
setAttr(svg, "width", "100%");
|
|
365
|
+
setAttr(svg, "height", "100%");
|
|
366
|
+
setAttr(svg, "xmlns", "http://www.w3.org/2000/svg");
|
|
367
|
+
const markup = serialize(svg);
|
|
368
|
+
return /\sxlink:/.test(markup) && !/\sxmlns:xlink=/.test(markup) ? markup.replace(/^<svg/, '<svg xmlns:xlink="http://www.w3.org/1999/xlink"') : markup;
|
|
369
|
+
}
|
|
370
|
+
var contains = (outer, inner) => outer.children.some((c) => c === inner || typeof c !== "string" && contains(c, inner));
|
|
371
|
+
function scopeIds(svg, suffix) {
|
|
372
|
+
if (!suffix) return;
|
|
373
|
+
const all = [];
|
|
374
|
+
const walk = (n) => {
|
|
375
|
+
all.push(n);
|
|
376
|
+
for (const c of n.children) if (typeof c !== "string") walk(c);
|
|
377
|
+
};
|
|
378
|
+
walk(svg);
|
|
379
|
+
const referred = /* @__PURE__ */ new Set();
|
|
380
|
+
for (const n of all) {
|
|
381
|
+
const css = n.tag.toLowerCase() === "style" ? n.children.filter((c) => typeof c === "string") : [];
|
|
382
|
+
for (const [name, value] of [...n.attrs, ...css.map((c) => ["", c])]) {
|
|
383
|
+
if (/^(xlink:)?href$/i.test(name) && value.startsWith("#")) referred.add(value.slice(1));
|
|
384
|
+
for (const m of value.matchAll(URL_REF)) referred.add(m[2]);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
const ids = /* @__PURE__ */ new Map();
|
|
388
|
+
for (const n of all) {
|
|
389
|
+
const id = getAttr(n, "id");
|
|
390
|
+
if (id && referred.has(id) && !ids.has(id)) ids.set(id, `${id}-${suffix}`);
|
|
391
|
+
}
|
|
392
|
+
if (!ids.size) return;
|
|
393
|
+
const scoped = (value) => value.replace(URL_REF, (whole, quote, id) => ids.has(id) ? `url(${quote}#${ids.get(id)}${quote})` : whole);
|
|
394
|
+
for (const n of all) {
|
|
395
|
+
for (const attr of n.attrs) {
|
|
396
|
+
if (attr[0] === "id") attr[1] = ids.get(attr[1]) ?? attr[1];
|
|
397
|
+
else if (/^(xlink:)?href$/i.test(attr[0])) attr[1] = attr[1].startsWith("#") && ids.has(attr[1].slice(1)) ? `#${ids.get(attr[1].slice(1))}` : attr[1];
|
|
398
|
+
else attr[1] = scoped(attr[1]);
|
|
399
|
+
}
|
|
400
|
+
if (n.tag.toLowerCase() === "style") n.children = n.children.map((c) => typeof c === "string" ? scoped(c) : c);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
export {
|
|
405
|
+
svgAnimatedMarkup
|
|
406
|
+
};
|
|
407
|
+
//# sourceMappingURL=chunk-YBGRXVAE.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/vector/animated.ts"],"sourcesContent":["/**\n * An {@link SvgMotion} as one self-contained animated `.svg` file, with no\n * DOM and no script: its changes written as SMIL (`<animate>`,\n * `<animateTransform>`, `<animateMotion>`), so it plays on its own wherever\n * an SVG image does (an `<img src>`, a file opened directly, inline markup).\n */\n\nimport { pathPointAt } from \"./morph.js\";\nimport {\n STEP_MS,\n SVG_PICTURE,\n stepStart,\n svgFrame,\n type EaseName,\n type SvgAnimation,\n type SvgBox,\n type SvgElementFrame,\n type SvgMotion,\n} from \"./motion.js\";\nimport { getAttr, serialize, setAttr, svgFrameTree, type SvgNode } from \"./static.js\";\nimport { svgDuration } from \"./svg.js\";\n\nexport interface AnimatedSvgOptions {\n /** Loop length in ms (default: `svgDuration(motion, steps)` + `hold`). */\n duration?: number;\n /** Ms to rest on the last frame before looping (default 600, like `SvgPlayer`). */\n hold?: number;\n /** Loop forever (default true); false plays once and holds the last frame. */\n loop?: boolean;\n /** Step start times in ms, for pictures that change on steps (like `SvgPlayer`'s `steps`). */\n steps?: readonly number[];\n /**\n * Samples per second for what cannot be written exactly (counts, written\n * text, a change cut short by the next, a `matrix` transform); default 30.\n */\n fps?: number;\n /**\n * Added to the ids the picture refers to (its gradients, filters, clips,\n * paths followed), so two files inlined in one page each use their own.\n * Default: a hash of the motion, so the same motion gives the same file;\n * `\"\"` keeps ids as written.\n */\n idSuffix?: string;\n}\n\n/** How a value gets to a keyframe from the one before: the shapes `EASES` are made of. */\ntype Shape = \"linear\" | \"in\" | \"out\";\n\n/** A channel's value at a time, reached from the keyframe before along `shape`. */\ninterface Key {\n t: number;\n v: string;\n shape: Shape;\n}\n\n/** One change to a channel, when it starts. */\ninterface Change {\n anim: SvgAnimation;\n start: number;\n}\n\n/**\n * Cubic Bézier timing for each shape. `out` (1 − (1 − t)³) is exactly the\n * curve (0, 1, 1, 1), and `in-out` is `in` (t³, the curve (0, 0, 0, 1)) to\n * its middle then `out`, so eases are written exactly, not sampled.\n */\nconst SPLINES: Record<Shape, string> = { linear: \"0 0 1 1\", in: \"0.3333 0 0.6667 0\", out: \"0.3333 1 0.6667 1\" };\n\n/** When an ease is halfway (where a value that cannot blend switches), as a share of its time. */\nconst HALFWAY: Record<EaseName, number> = { linear: 0.5, \"in-out\": 0.5, out: 1 - 0.5 ** (1 / 3) };\n\nconst NUMBER = /-?(?:\\d+\\.?\\d*|\\.\\d+)(?:e[-+]?\\d+)?/gi;\nconst HEX = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i;\nconst TRANSFORMS = new Set([\"transform\", \"gradienttransform\", \"patterntransform\"]);\nconst URL_REF = /url\\(\\s*(['\"]?)#([^'\")\\s]+)\\1\\s*\\)/g;\n\n/** Whether `lerpAttr` blends two values (else it switches halfway), so SMIL can interpolate them. */\nfunction blends(a: string | number, b: string | number): boolean {\n if (typeof a === \"number\" && typeof b === \"number\") return true;\n const [sa, sb] = [String(a), String(b)];\n if (HEX.test(sa) && HEX.test(sb)) return true;\n const na = sa.match(NUMBER) ?? [];\n return na.length > 0 && na.length === (sb.match(NUMBER) ?? []).length && sa.replace(NUMBER, \"#\") === sb.replace(NUMBER, \"#\");\n}\n\nconst num = (n: number) => String(+n.toFixed(3));\n\n/** A short, stable hash of a string, for default id suffixes. */\nfunction hash(s: string): string {\n let h = 0x811c9dc5;\n for (let i = 0; i < s.length; i++) h = Math.imul(h ^ s.charCodeAt(i), 0x01000193);\n return (h >>> 0).toString(36);\n}\n\n/** An element: `<tag attrs/>`. */\nconst node = (tag: string, attrs: Record<string, string | undefined>, children: SvgNode[\"children\"] = []): SvgNode => ({\n tag,\n attrs: Object.entries(attrs).filter((e): e is [string, string] => e[1] !== undefined),\n children,\n});\n\n/**\n * The transform functions in a `transform` value, with their arguments:\n * `translate(10 20) rotate(45)` → [[\"translate\", [10, 20]], [\"rotate\", [45]]].\n */\nfunction transformList(value: string): [string, number[]][] {\n return [...value.matchAll(/([a-z]+)\\s*\\(([^)]*)\\)/gi)].map((m) => [m[1]!, (m[2]!.match(NUMBER) ?? []).map(Number)]);\n}\n\n/** A transform list as one matrix [a b c d e f]. */\nfunction transformMatrix(value: string): number[] {\n let m = [1, 0, 0, 1, 0, 0];\n const times = (n: number[]) => {\n const [a, b, c, d, e, f] = m as [number, number, number, number, number, number];\n m = [a * n[0]! + c * n[1]!, b * n[0]! + d * n[1]!, a * n[2]! + c * n[3]!, b * n[2]! + d * n[3]!, a * n[4]! + c * n[5]! + e, b * n[4]! + d * n[5]! + f];\n };\n const rad = Math.PI / 180;\n for (const [name, [p = 0, q, r = 0, s = 0, t = 0, u = 0]] of transformList(value)) {\n if (name === \"translate\") times([1, 0, 0, 1, p, q ?? 0]);\n else if (name === \"scale\") times([p, 0, 0, q ?? p, 0, 0]);\n else if (name === \"rotate\") {\n const [cos, sin] = [Math.cos(p * rad), Math.sin(p * rad)];\n const [cx, cy] = [q ?? 0, r];\n times([1, 0, 0, 1, cx, cy]);\n times([cos, sin, -sin, cos, 0, 0]);\n times([1, 0, 0, 1, -cx, -cy]);\n } else if (name === \"skewX\") times([1, 0, Math.tan(p * rad), 1, 0, 0]);\n else if (name === \"skewY\") times([1, Math.tan(p * rad), 0, 1, 0, 0]);\n else if (name === \"matrix\") times([p, q ?? 0, r, s, t, u]);\n }\n return m;\n}\n\n/** A matrix as translate · rotate · skewX · scale (degrees), the order SMIL can add them in. */\nfunction decompose([a, b, c, d, e, f]: number[]): [number, number, number, number, number, number] {\n const sx = Math.hypot(a!, b!);\n const angle = sx ? Math.atan2(b!, a!) : 0;\n const [cos, sin] = [Math.cos(angle), Math.sin(angle)];\n const sy = -sin * c! + cos * d!;\n const skew = sy ? Math.atan((cos * c! + sin * d!) / sy) : 0;\n return [e!, f!, (angle * 180) / Math.PI, (skew * 180) / Math.PI, sx, sy];\n}\n\n/** A shape's outline as a path `d`, for following it with `along`. */\nfunction outline(el: SvgNode): string | undefined {\n const at = (name: string) => Number(getAttr(el, name) ?? 0);\n switch (el.tag.toLowerCase()) {\n case \"path\":\n return getAttr(el, \"d\");\n case \"line\":\n return `M${at(\"x1\")} ${at(\"y1\")}L${at(\"x2\")} ${at(\"y2\")}`;\n case \"polyline\":\n case \"polygon\":\n return `M${getAttr(el, \"points\") ?? \"\"}${el.tag.toLowerCase() === \"polygon\" ? \"Z\" : \"\"}`;\n default:\n return undefined;\n }\n}\n\n/**\n * The timing attributes that play `keys` over the loop: `keyTimes` and,\n * where a key eases in, `keySplines`. Keys at the same time are a jump.\n */\nfunction timing(keys: readonly Key[], loop: number, repeat: boolean, discrete = false): Record<string, string | undefined> {\n const spline = !discrete && keys.some((k, i) => i > 0 && k.shape !== \"linear\");\n return {\n ...clock(loop, repeat),\n keyTimes: keys.map((k) => String(+(k.t / loop).toFixed(5))).join(\";\"),\n calcMode: discrete ? \"discrete\" : spline ? \"spline\" : \"linear\",\n keySplines: spline ? keys.slice(1).map((k) => SPLINES[k.shape]).join(\";\") : undefined,\n };\n}\n\n/** How long an animation runs, and whether it repeats or holds its end. */\nconst clock = (loop: number, repeat: boolean) => ({\n dur: `${+(loop / 1000).toFixed(4)}s`,\n repeatCount: repeat ? \"indefinite\" : undefined,\n fill: repeat ? undefined : \"freeze\",\n});\n\n/** Keys with their repeats dropped: a key between two of the same value, or a copy of the one before. */\nfunction collapse(keys: Key[]): Key[] {\n const out: Key[] = [];\n keys.forEach((k, i) => {\n const prev = out[out.length - 1];\n if (prev && prev.v === k.v && (prev.t === k.t || (keys[i + 1]?.v === k.v && i < keys.length - 1))) return;\n out.push(k);\n });\n return out;\n}\n\n/** Keys reduced to where the value changes, for a discrete animation (the last at a time wins). */\nfunction runs(keys: readonly Key[]): Key[] {\n const out: Key[] = [];\n for (const k of keys) {\n const prev = out[out.length - 1];\n if (prev?.t === k.t) out.pop();\n if (out[out.length - 1]?.v !== k.v) out.push(k);\n }\n return out;\n}\n\n/**\n * The {@link SvgMotion} as one animated SVG file that plays and loops on its\n * own, as `SvgPlayer` plays it, with no script: save it as `.svg`, put it in\n * an `<img src>`, or inline it. Each element starts as the motion's first\n * frame, so it still shows that where SMIL does not run.\n *\n * Attribute changes become one `<animate>` per attribute (`<animateTransform>`\n * per function of a `transform`), with the eases written exactly as splines;\n * `draw` animates `stroke-dashoffset`; `along` becomes `<animateMotion>` on\n * the path; `view` animates the root `viewBox` (keeping `data-fixed` and\n * `data-nonscaling` elements as the player does); `solo` toggles `display`.\n * Counts and written text are sampled at `fps`, each text shown in its own\n * `<tspan>` in turn.\n *\n * Limits: a `view` that frames an element by id stays where it is (it needs\n * layout, as in `svgFrameMarkup`); `style` and other attributes SMIL cannot\n * interpolate change in steps; ids are suffixed only where the picture\n * refers to them (CSS `#id` selectors in a `<style>` are left as written).\n * Undefined when `motion.svg` is not an `<svg>`.\n */\nexport function svgAnimatedMarkup(motion: SvgMotion, options: AnimatedSvgOptions = {}): string | undefined {\n const steps = options.steps ?? [];\n const repeat = options.loop ?? true;\n const fps = options.fps ?? 30;\n const loop = Math.max(1, options.duration ?? svgDuration(motion, steps) + (options.hold ?? 600));\n const animations = motion.animate ?? [];\n const tree = svgFrameTree(motion, steps, 0);\n if (!tree) return undefined;\n const { svg, byId, whole } = tree;\n\n // Each property's changes in the order they start, as `svgFrame` keeps them.\n const tracks = new Map<string, Change[]>();\n animations.forEach((anim) => {\n const s = stepStart(steps, anim.step ?? 0);\n const start = s === undefined ? Infinity : s + (anim.delay ?? 0);\n const add = (prop: string) => {\n const key = `${prop === \"view\" ? SVG_PICTURE : anim.id}\\u0000${prop}`;\n tracks.set(key, [...(tracks.get(key) ?? []), { anim, start }]);\n };\n for (const name of Object.keys(anim.attrs ?? {})) add(`@${name}`);\n if (anim.draw) add(\"draw\");\n if (anim.count || anim.write !== undefined) add(\"text\");\n if (anim.solo !== undefined) add(\"solo\");\n if (anim.view !== undefined) add(\"view\");\n if (anim.along) add(\"along\");\n });\n for (const list of tracks.values()) list.sort((x, y) => x.start - y.start);\n\n const frames = new Map<number, Map<string, SvgElementFrame>>();\n const frameAt = (t: number) => {\n let f = frames.get(t);\n if (!f) frames.set(t, (f = svgFrame(animations, steps, t)));\n return f;\n };\n const boxOf = (v: SvgBox | string | null) => (v === null ? whole : typeof v === \"string\" ? undefined : v);\n /** A channel's value in a frame, as written into the file. */\n const read = (frame: Map<string, SvgElementFrame>, id: string, prop: string): string | undefined => {\n const f = frame.get(id);\n if (!f) return undefined;\n if (prop.startsWith(\"@\")) return f.attrs[prop.slice(1)];\n if (prop === \"draw\") return f.draw === undefined ? undefined : num(1 - f.draw);\n if (prop === \"along\") return f.along && num(f.along.at);\n if (prop === \"solo\") return f.solo === undefined ? undefined : String(f.solo);\n if (prop === \"text\") return f.text;\n if (!f.view) return undefined;\n const [a, b] = [boxOf(f.view.from), boxOf(f.view.to)];\n const box = a && b ? a.map((n, i) => n + (b[i]! - n) * f.view!.u) : (b ?? a ?? whole);\n return box?.map(num).join(\" \");\n };\n\n /**\n * A channel's keyframes over the loop: before its first change its start,\n * then each change from its start to its end (or the next change), eased\n * exactly or (with `sampled`, or when cut short) sampled at `fps`.\n */\n const keyframes = (id: string, prop: string, list: readonly Change[], sampled = false): Key[] => {\n const shown = list.filter((c, i) => c.start < loop && !(list[i + 1] && list[i + 1]!.start <= c.start));\n // A change alone (with the one before it, where a view starts) gives its own value at any time.\n const value = (k: number, t: number) =>\n read(svgFrame(shown.slice(Math.max(0, k - 1), k + 1).map((c) => c.anim), steps, t), id, prop) ?? \"\";\n const keys: Key[] = [];\n const push = (t: number, v: string, shape: Shape = \"linear\") => keys.push({ t, v, shape });\n if (!shown.length) return [];\n push(0, read(frameAt(0), id, prop) ?? value(0, 0));\n shown.forEach((c, k) => {\n const next = Math.min(shown[k + 1]?.start ?? loop, loop);\n const ms = c.anim.ms ?? STEP_MS;\n const end = Math.min(c.start + ms, next);\n // Held until it starts, where it may jump.\n push(c.start, keys[keys.length - 1]!.v);\n push(c.start, value(k, c.start));\n if (!(ms > 0)) return;\n const ease = c.anim.ease ?? \"in-out\";\n const pair = prop.startsWith(\"@\") ? c.anim.attrs![prop.slice(1)]! : undefined;\n if (pair && !blends(pair[0], pair[1])) {\n const at = c.start + ms * HALFWAY[ease];\n if (at < next) {\n push(at, value(k, c.start));\n push(at, value(k, end));\n }\n } else if (!sampled && end === c.start + ms && ease !== \"linear\") {\n if (ease === \"in-out\") push(c.start + ms / 2, value(k, c.start + ms / 2), \"in\");\n push(end, value(k, end), \"out\");\n } else if (!sampled && ease === \"linear\") push(end, value(k, end));\n else {\n for (let t = c.start + 1000 / fps; t < end; t += 1000 / fps) push(t, value(k, t));\n push(end, value(k, end));\n }\n });\n if (keys[keys.length - 1]!.t < loop) push(loop, keys[keys.length - 1]!.v);\n return collapse(keys);\n };\n\n /** Times to sample text at: every 1/fps, and wherever a change starts or ends. */\n const sampleTimes = (list: readonly Change[]) => {\n const times = new Set<number>();\n for (let t = 0; t < loop; t += 1000 / fps) times.add(+t.toFixed(3));\n for (const c of list)\n for (const t of [c.start, c.start + (c.anim.ms ?? STEP_MS)]) if (t < loop) times.add(t);\n return [...times].sort((a, b) => a - b);\n };\n\n // What to add to each element, appended once all are worked out (so a solo's children stay as written).\n const added = new Map<SvgNode, SvgNode[]>();\n const add = (el: SvgNode, ...anims: SvgNode[]) => added.set(el, [...(added.get(el) ?? []), ...anims]);\n const animate = (name: string, keys: readonly Key[], values = keys.map((k) => k.v), discrete = false) =>\n node(\"animate\", { attributeName: name, values: values.join(\";\"), ...timing(keys, loop, repeat, discrete) });\n const followers = new Set(animations.filter((a) => a.along).map((a) => a.id));\n let viewKeys: Key[] | undefined;\n\n for (const [key, list] of tracks) {\n const [id, prop] = key.split(\"\\u0000\") as [string, string];\n const el = id === SVG_PICTURE ? svg : byId.get(id);\n if (!el) continue;\n const name = prop.slice(1);\n if (prop === \"text\") {\n // One <tspan> per text it shows, each shown in its turn.\n const own = list.map((c) => c.anim);\n const text = (t: number) => read(svgFrame(own, steps, t), id, prop) ?? \"\";\n const shown: Key[] = [];\n let last = -1;\n for (const t of sampleTimes(list)) {\n const v = text(t);\n if (shown.length && v !== shown[shown.length - 1]!.v) {\n let [lo, hi] = [last, t];\n while (hi - lo > 0.5) {\n const mid = (lo + hi) / 2;\n if (text(mid) === shown[shown.length - 1]!.v) lo = mid;\n else hi = mid;\n }\n // One change between them is placed exactly; several (a fast count) change at the middle.\n shown.push({ t: text(hi) === v ? hi : (last + t) / 2, v, shape: \"linear\" });\n }\n if (v !== shown[shown.length - 1]?.v) shown.push({ t, v, shape: \"linear\" });\n last = t;\n }\n const texts = [...new Set(shown.map((k) => k.v))];\n el.children = texts.map((value, i) => {\n const keys = runs(shown.map((k) => ({ ...k, v: k.v === value ? \"inline\" : \"none\" })));\n const span = node(\"tspan\", { display: i === 0 ? undefined : \"none\" }, [value]);\n if (keys.length > 1) span.children.push(animate(\"display\", keys, undefined, true));\n return span;\n });\n continue;\n }\n if (prop.startsWith(\"@\") && TRANSFORMS.has(name.toLowerCase())) {\n if (followers.has(id) && name === \"transform\") continue;\n let keys = keyframes(id, prop, list);\n if (keys.length < 2) continue;\n const lists = keys.map((k) => transformList(k.v));\n const shape = (l: [string, number[]][]) => l.map(([f, args]) => `${f}${args.length}`).join(\" \");\n if (lists.every((l) => shape(l) === shape(lists[0]!)) && !/matrix|skewY/.test(shape(lists[0]!))) {\n // The same functions throughout: each animated on its own, added up in order.\n lists[0]!.forEach(([type], j) =>\n add(el, node(\"animateTransform\", {\n attributeName: name,\n type,\n additive: j ? \"sum\" : undefined,\n values: lists.map((l) => l[j]![1].map(num).join(\" \")).join(\";\"),\n ...timing(keys, loop, repeat),\n })),\n );\n } else {\n // Anything else as translate · rotate · skewX · scale, sampled, with the angle kept continuous.\n keys = keyframes(id, prop, list, true);\n const parts = keys.map((k) => decompose(transformMatrix(k.v)));\n parts.forEach((p, i) => {\n const before = parts[i - 1];\n if (before) p[2] += 360 * Math.round((before[2] - p[2]) / 360);\n });\n const types: [string, (p: number[]) => number[]][] = [\n [\"translate\", (p) => [p[0]!, p[1]!]],\n [\"rotate\", (p) => [p[2]!]],\n [\"skewX\", (p) => [p[3]!]],\n [\"scale\", (p) => [p[4]!, p[5]!]],\n ];\n types.forEach(([type, pick], j) =>\n add(el, node(\"animateTransform\", {\n attributeName: name,\n type,\n additive: j ? \"sum\" : undefined,\n values: parts.map((p) => pick(p).map(num).join(\" \")).join(\";\"),\n ...timing(keys, loop, repeat),\n })),\n );\n }\n continue;\n }\n if (prop === \"along\") {\n const paths = new Set(list.map((c) => c.anim.along!));\n const pathEl = byId.get([...paths][0]!);\n const d = pathEl && outline(pathEl);\n if (!d) continue;\n const point = (at: string) => pathPointAt(d, Number(at));\n const first = point(read(frameAt(0), id, prop) ?? \"0\");\n if (first) setAttr(el, \"transform\", `translate(${num(first[0])} ${num(first[1])})`);\n if (paths.size === 1 && pathEl.tag.toLowerCase() === \"path\") {\n // The browser follows the path itself: the markup's place (for no SMIL) set aside while it does.\n const keys = keyframes(id, prop, list);\n add(\n el,\n node(\"animateTransform\", { attributeName: \"transform\", type: \"translate\", values: \"0 0\", ...clock(loop, repeat) }),\n node(\"animateMotion\", { keyPoints: keys.map((k) => k.v).join(\";\"), ...timing(keys, loop, repeat) }, [\n node(\"mpath\", { href: `#${[...paths][0]}` }),\n ]),\n );\n } else {\n // Along several paths, or a shape SMIL cannot follow: its points, sampled.\n const keys = sampleTimes(list).map((t): Key => {\n const f = frameAt(t).get(id)?.along;\n const p = f && byId.get(f.path) && pathPointAt(outline(byId.get(f.path)!) ?? \"\", f.at);\n return { t, v: p ? `${num(p[0])} ${num(p[1])}` : \"0 0\", shape: \"linear\" };\n });\n keys.push({ t: loop, v: keys[keys.length - 1]!.v, shape: \"linear\" });\n const ks = collapse(keys);\n add(el, node(\"animateTransform\", { attributeName: \"transform\", type: \"translate\", values: ks.map((k) => k.v).join(\";\"), ...timing(ks, loop, repeat) }));\n }\n continue;\n }\n const keys = keyframes(id, prop, list);\n if (keys.length < 2) continue;\n if (prop === \"solo\") {\n const shown = runs(keys);\n let i = 0;\n for (const child of el.children) {\n if (typeof child === \"string\") continue;\n const index = String(i++);\n const toggles = runs(shown.map((k) => ({ ...k, v: k.v === index ? \"inline\" : \"none\" })));\n if (toggles.length > 1) add(child, animate(\"display\", toggles, undefined, true));\n }\n } else if (prop === \"view\") {\n viewKeys = keys;\n add(svg, animate(\"viewBox\", keys));\n } else add(el, animate(prop === \"draw\" ? \"stroke-dashoffset\" : name, keys));\n }\n\n if (viewKeys && whole) {\n // As the view zooms, `data-nonscaling` elements keep their size and `data-fixed` ones their place.\n const boxes = viewKeys.map((k) => k.v.split(\" \").map(Number));\n const all: SvgNode[] = [];\n const walk = (n: SvgNode) => {\n all.push(n);\n for (const c of n.children) if (typeof c !== \"string\") walk(c);\n };\n walk(svg);\n const zooms = boxes.map((b) => num(b[2]! / whole[2]));\n for (const el of all.filter((n) => getAttr(n, \"data-nonscaling\") !== undefined)) {\n setAttr(el, \"transform\", zooms[0] === \"1\" ? undefined : `scale(${zooms[0]})`);\n add(el, node(\"animateTransform\", { attributeName: \"transform\", type: \"scale\", values: zooms.join(\";\"), ...timing(viewKeys, loop, repeat) }));\n }\n const fixed = all.filter((n) => getAttr(n, \"data-fixed\") !== undefined);\n const top = fixed.filter((n) => !fixed.some((f) => f !== n && contains(f, n)));\n if (top.length) {\n for (const el of top) for (const n of all) n.children = n.children.filter((c) => c !== el);\n // A layer that maps the whole picture onto the view as it moves (as a nested <svg> with the\n // whole viewBox would, but with transforms, which images animate where they do not re-lay out one).\n const fit = boxes.map(([x, y, w, h]) => {\n const k = Math.min(w! / whole[2], h! / whole[3]);\n return { at: `${num(x! + (w! - whole[2] * k) / 2 - whole[0] * k)} ${num(y! + (h! - whole[3] * k) / 2 - whole[1] * k)}`, k: num(k) };\n });\n const layer = node(\"g\", { transform: `translate(${fit[0]!.at}) scale(${fit[0]!.k})` }, top);\n add(\n layer,\n node(\"animateTransform\", { attributeName: \"transform\", type: \"translate\", values: fit.map((f) => f.at).join(\";\"), ...timing(viewKeys, loop, repeat) }),\n node(\"animateTransform\", { attributeName: \"transform\", type: \"scale\", additive: \"sum\", values: fit.map((f) => f.k).join(\";\"), ...timing(viewKeys, loop, repeat) }),\n );\n svg.children.push(layer);\n }\n }\n\n for (const [el, anims] of added) el.children.push(...anims);\n scopeIds(svg, options.idSuffix ?? hash(motion.svg + JSON.stringify(animations)));\n setAttr(svg, \"width\", \"100%\");\n setAttr(svg, \"height\", \"100%\");\n setAttr(svg, \"xmlns\", \"http://www.w3.org/2000/svg\");\n const markup = serialize(svg);\n // Read as XML (an image, a file), `xlink:` attributes need their namespace declared.\n return /\\sxlink:/.test(markup) && !/\\sxmlns:xlink=/.test(markup)\n ? markup.replace(/^<svg/, '<svg xmlns:xlink=\"http://www.w3.org/1999/xlink\"')\n : markup;\n}\n\nconst contains = (outer: SvgNode, inner: SvgNode): boolean =>\n outer.children.some((c) => c === inner || (typeof c !== \"string\" && contains(c, inner)));\n\n/**\n * Gives the ids the picture refers to (by `url(#…)` or `href=\"#…\"`) `-suffix`,\n * and points the references at them, as a live player does.\n */\nfunction scopeIds(svg: SvgNode, suffix: string) {\n if (!suffix) return;\n const all: SvgNode[] = [];\n const walk = (n: SvgNode) => {\n all.push(n);\n for (const c of n.children) if (typeof c !== \"string\") walk(c);\n };\n walk(svg);\n const referred = new Set<string>();\n for (const n of all) {\n const css = n.tag.toLowerCase() === \"style\" ? n.children.filter((c): c is string => typeof c === \"string\") : [];\n for (const [name, value] of [...n.attrs, ...css.map((c) => [\"\", c] as const)]) {\n if (/^(xlink:)?href$/i.test(name) && value.startsWith(\"#\")) referred.add(value.slice(1));\n for (const m of value.matchAll(URL_REF)) referred.add(m[2]!);\n }\n }\n const ids = new Map<string, string>();\n for (const n of all) {\n const id = getAttr(n, \"id\");\n if (id && referred.has(id) && !ids.has(id)) ids.set(id, `${id}-${suffix}`);\n }\n if (!ids.size) return;\n const scoped = (value: string) =>\n value.replace(URL_REF, (whole, quote: string, id: string) => (ids.has(id) ? `url(${quote}#${ids.get(id)}${quote})` : whole));\n for (const n of all) {\n for (const attr of n.attrs) {\n if (attr[0] === \"id\") attr[1] = ids.get(attr[1]) ?? attr[1];\n else if (/^(xlink:)?href$/i.test(attr[0])) attr[1] = attr[1].startsWith(\"#\") && ids.has(attr[1].slice(1)) ? `#${ids.get(attr[1].slice(1))}` : attr[1];\n else attr[1] = scoped(attr[1]);\n }\n if (n.tag.toLowerCase() === \"style\") n.children = n.children.map((c) => (typeof c === \"string\" ? scoped(c) : c));\n }\n}\n"],"mappings":"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","names":["add","keys"]}
|
package/dist/cli.js
CHANGED
|
@@ -3,16 +3,18 @@ import {
|
|
|
3
3
|
standaloneHtml,
|
|
4
4
|
standaloneSceneHtml,
|
|
5
5
|
validateScene
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-O44ZJTGG.js";
|
|
7
7
|
import {
|
|
8
8
|
simulateScene
|
|
9
9
|
} from "./chunk-WAMA45G3.js";
|
|
10
|
-
import "./chunk-
|
|
10
|
+
import "./chunk-DBTLCXKY.js";
|
|
11
|
+
import "./chunk-H6VDFBIO.js";
|
|
12
|
+
import "./chunk-RDU63CDO.js";
|
|
11
13
|
import "./chunk-EHDJ3CPJ.js";
|
|
12
|
-
import "./chunk-WMZQCUFJ.js";
|
|
13
14
|
import {
|
|
14
15
|
parseControls
|
|
15
16
|
} from "./chunk-VYOMXE6I.js";
|
|
17
|
+
import "./chunk-WMZQCUFJ.js";
|
|
16
18
|
|
|
17
19
|
// src/cli.ts
|
|
18
20
|
import { Command } from "commander";
|
|
@@ -78,7 +80,7 @@ program.command("html <shaderPath>").description("Generate a self-contained stan
|
|
|
78
80
|
exec(`open "${outputPath}"`);
|
|
79
81
|
}
|
|
80
82
|
});
|
|
81
|
-
program.command("export <targetOrShader> [extraPath] [outputPath]").description("Export shader
|
|
83
|
+
program.command("export <targetOrShader> [extraPath] [outputPath]").description("Export a shader file to video (.mp4/.webm/.mov), .gif or .png frames, or a scene to motn/lottie/fcp7/edl").option("-o, --out <outputPath>", "Output file path").option("-w, --width <width>", "Canvas width", "720").option("-h, --height <height>", "Canvas height", "720").option("--fps <fps>", "Frames per second", "30").option("-d, --duration <duration>", "Duration in seconds", "3").option("-v, --values <jsonOrFile>", "Control values as JSON string or file").option("--alpha", "Keep the shader alpha (webm, mov, gif, png)", false).option("--transparent", "The shader is an overlay: composite its alpha over --background", false).option("--background <css>", "Colour under transparent pixels without --alpha", "#000000").option("--pointer", "Act out a pointer that hovers, wanders and clicks", false).action(async (targetOrShader, extraPath, outputPath, options) => {
|
|
82
84
|
if (targetOrShader === "motn" || targetOrShader === "lottie" || targetOrShader === "fcp7" || targetOrShader === "edl") {
|
|
83
85
|
const sceneFile = extraPath;
|
|
84
86
|
if (!sceneFile) {
|
|
@@ -152,7 +154,7 @@ program.command("export <targetOrShader> [extraPath] [outputPath]").description(
|
|
|
152
154
|
const duration = parseFloat(options.duration);
|
|
153
155
|
console.log(`Rendering ${duration}s (${duration * fps} frames at ${width}x${height}, ${fps}fps) to ${options.out}...`);
|
|
154
156
|
try {
|
|
155
|
-
const { exportMotionGraphic } = await import("./recorder-
|
|
157
|
+
const { exportMotionGraphic } = await import("./recorder-CDPPTJMG.js");
|
|
156
158
|
const savedPath = await exportMotionGraphic({
|
|
157
159
|
source,
|
|
158
160
|
values,
|
|
@@ -161,6 +163,10 @@ program.command("export <targetOrShader> [extraPath] [outputPath]").description(
|
|
|
161
163
|
height,
|
|
162
164
|
fps,
|
|
163
165
|
duration,
|
|
166
|
+
alpha: options.alpha,
|
|
167
|
+
transparent: options.transparent,
|
|
168
|
+
background: options.background,
|
|
169
|
+
pointer: options.pointer ? "auto" : "none",
|
|
164
170
|
onProgress: (frame, total) => {
|
|
165
171
|
process.stdout.write(`\rRendering frame ${frame}/${total} (${Math.round(frame / total * 100)}%)`);
|
|
166
172
|
}
|
|
@@ -173,6 +179,63 @@ Export failed: ${err.message}`);
|
|
|
173
179
|
process.exit(1);
|
|
174
180
|
}
|
|
175
181
|
});
|
|
182
|
+
var collect = (value, previous) => [...previous, value];
|
|
183
|
+
program.command("effects").description("List catalog effects with what they take (image, video, svg, text, mask, path) and how they answer the pointer").option("--accepts <inputs>", "Only effects that take all of these (image, video, svg, text, mask, path; comma-separated or repeated)", collect, []).option("--interaction <ways>", "Only effects that answer the pointer in one of these ways (hover, press, click, trail, pointer)", collect, []).option("--category <category>", "Only this category").option("--kind <kind>", "shader or vector").option("--search <words>", "Words to look for in the id, name, description and tags").option("--json", "Output JSON (id, name, kind, category, description, inputs, presets)", false).action(async (options) => {
|
|
184
|
+
try {
|
|
185
|
+
const { findEffects, effectInputs } = await import("./catalog/index.js");
|
|
186
|
+
const { effectQueryFromFlags, describeEffect } = await import("./effect-26CPF5HS.js");
|
|
187
|
+
const effects = findEffects(effectQueryFromFlags(options));
|
|
188
|
+
if (options.json) {
|
|
189
|
+
console.log(JSON.stringify(effects.map((e) => ({ id: e.id, name: e.name, kind: e.kind, category: e.category, description: e.description, inputs: effectInputs(e), presets: e.presets?.map((p) => p.name) ?? [] })), null, 2));
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
if (!effects.length) {
|
|
193
|
+
console.log("No effects match.");
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
for (const e of effects) console.log(describeEffect(e));
|
|
197
|
+
console.log(`
|
|
198
|
+
${effects.length} effect${effects.length === 1 ? "" : "s"}. Render one with: flair render <id> [--image p | --text "\u2026" | \u2026] -o out.mp4`);
|
|
199
|
+
} catch (err) {
|
|
200
|
+
console.error(`Error: ${err.message}`);
|
|
201
|
+
process.exit(1);
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
program.command("render <effect>").description("Render a catalog effect, applied to a subject, to .mp4, .webm, .mov, .gif, .svg (vector effects) or .png frames").option("--image <path>", "A picture (file path or URL); repeat for effects that take two", collect, []).option("--svg <path>", "An SVG (file path, URL or markup)", collect, []).option("--text <text>", "Words, for a text effect or a text mask", collect, []).option("--font <family>", "CSS font family for --text drawn into a shader").option("--weight <weight>", "Font weight for --text drawn into a shader").option("--path <d>", "SVG path data, for a shape control", collect, []).option("--video <path>", "A video file, decoded to frames with ffmpeg", collect, []).option("--preset <name>", "A preset by name").option("--set <name=value>", "A control value (repeatable): --set uSpeed=2 --set uTint=#ff0080", collect, []).option("--size <WxH>", "Pixels, like 1280x720").option("--fps <fps>", "Frames per second", "30").option("--duration <seconds>", "Seconds (default: the effect's loop or play-through)").option("--alpha", "Keep transparency (webm, mov, gif, png, svg)", false).option("--background <css>", "Colour under transparent pixels without --alpha").option("--no-pointer", "Leave the pointer still (interactive effects otherwise get a scripted pointer)").option("-o, --out <outputPath>", "Output: .mp4, .webm, .mov, .gif, .svg, a .png pattern (out_%04d.png) or a folder").action(async (effectId, options) => {
|
|
205
|
+
try {
|
|
206
|
+
if (!options.out) throw new Error("Say where to write it: -o out.mp4 (or .webm, .mov, .gif, .svg, out_%04d.png, a folder/).");
|
|
207
|
+
const { exportEffect, parseSets, parseSize, resolveEffect, subjectsFromFlags } = await import("./effect-26CPF5HS.js");
|
|
208
|
+
const effect = resolveEffect(effectId);
|
|
209
|
+
const subjects = subjectsFromFlags(options);
|
|
210
|
+
const size = options.size ? parseSize(options.size) : void 0;
|
|
211
|
+
const fps = Number(options.fps);
|
|
212
|
+
if (!(fps > 0)) throw new Error(`--fps takes a positive number, not "${options.fps}".`);
|
|
213
|
+
const duration = options.duration === void 0 ? void 0 : Number(options.duration);
|
|
214
|
+
if (duration !== void 0 && !(duration > 0)) throw new Error(`--duration takes seconds, more than 0, not "${options.duration}".`);
|
|
215
|
+
console.log(`Rendering ${effect.id} to ${options.out}...`);
|
|
216
|
+
const saved = await exportEffect(effect, {
|
|
217
|
+
...subjects.length ? { subject: subjects } : {},
|
|
218
|
+
...options.preset ? { preset: options.preset } : {},
|
|
219
|
+
values: parseSets(effect, options.set),
|
|
220
|
+
outputPath: options.out,
|
|
221
|
+
...size ?? {},
|
|
222
|
+
fps,
|
|
223
|
+
...duration !== void 0 ? { duration } : {},
|
|
224
|
+
alpha: options.alpha,
|
|
225
|
+
...options.background ? { background: options.background } : {},
|
|
226
|
+
...options.pointer === false ? { pointer: "none" } : {},
|
|
227
|
+
onProgress: (frame, total) => {
|
|
228
|
+
if (total > 1) process.stdout.write(`\rFrame ${frame}/${total} (${Math.round(frame / total * 100)}%)`);
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
console.log(`
|
|
232
|
+
Wrote ${saved}`);
|
|
233
|
+
} catch (err) {
|
|
234
|
+
console.error(`
|
|
235
|
+
Render failed: ${err.message}`);
|
|
236
|
+
process.exit(1);
|
|
237
|
+
}
|
|
238
|
+
});
|
|
176
239
|
var sceneCmd = program.command("scene").description("Direct, validate, simulate, and render multi-shot animated scenes");
|
|
177
240
|
sceneCmd.command("validate <sceneFile>").description("Validate scene JSON structure, camera framing, and effect IDs").action((sceneFile) => {
|
|
178
241
|
const fullPath = path.resolve(process.cwd(), sceneFile);
|