pixi-effects 0.9.0 → 0.10.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 +15 -0
- package/README.md +6 -6
- package/ai/SKILL.md +2 -1
- package/ai/reference/cheatsheet.md +13 -5
- package/ai/reference/pitfalls.md +2 -2
- package/ai/reference/recipes.md +123 -2
- package/ai/template.html +3 -3
- package/dist/{Base-CSIulyIq.d.cts → Base-CwUxTfja.d.cts} +1 -1
- package/dist/{Base-DVgwyIUj.d.ts → Base-CyvSLoCP.d.ts} +1 -1
- package/dist/Composition-EKVTUYCI.cjs +14 -0
- package/dist/{Composition-CM62XJKT.cjs.map → Composition-EKVTUYCI.cjs.map} +1 -1
- package/dist/Composition-NJCOMGD7.js +5 -0
- package/dist/{Composition-RJDSQYTV.js.map → Composition-NJCOMGD7.js.map} +1 -1
- package/dist/Controller.cjs +34 -0
- package/dist/Controller.cjs.map +1 -1
- package/dist/Controller.d.cts +12 -2
- package/dist/Controller.d.ts +12 -2
- package/dist/Controller.js +34 -0
- package/dist/Controller.js.map +1 -1
- package/dist/{Movie-QMlFyHkf.d.ts → Movie-puD9oZPg.d.ts} +1 -1
- package/dist/{Movie-qGHp15c_.d.cts → Movie-w3GliuP3.d.cts} +1 -1
- package/dist/{chunk-PDBDDGG5.cjs → chunk-4WJUSDJJ.cjs} +103 -30
- package/dist/chunk-4WJUSDJJ.cjs.map +1 -0
- package/dist/{chunk-FNKSXBKB.js → chunk-JAMNDBXW.js} +193 -14
- package/dist/chunk-JAMNDBXW.js.map +1 -0
- package/dist/{chunk-AGMNSJJH.cjs → chunk-S3ZI4MKS.cjs} +196 -12
- package/dist/chunk-S3ZI4MKS.cjs.map +1 -0
- package/dist/{chunk-O4AJYUPK.js → chunk-WDGAVOMS.js} +85 -12
- package/dist/chunk-WDGAVOMS.js.map +1 -0
- package/dist/index.cjs +309 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +231 -5
- package/dist/index.d.ts +231 -5
- package/dist/index.js +282 -11
- package/dist/index.js.map +1 -1
- package/dist/three.cjs +5 -5
- package/dist/three.d.cts +2 -2
- package/dist/three.d.ts +2 -2
- package/dist/three.js +1 -1
- package/dist/{types-oJijbn-K.d.ts → types-BXu28nJj.d.cts} +26 -2
- package/dist/{types-oJijbn-K.d.cts → types-BXu28nJj.d.ts} +26 -2
- package/docs/api.md +1 -0
- package/docs/dsl.md +108 -2
- package/llms-full.txt +249 -12
- package/package.json +1 -1
- package/dist/Composition-CM62XJKT.cjs +0 -14
- package/dist/Composition-RJDSQYTV.js +0 -5
- package/dist/chunk-AGMNSJJH.cjs.map +0 -1
- package/dist/chunk-FNKSXBKB.js.map +0 -1
- package/dist/chunk-O4AJYUPK.js.map +0 -1
- package/dist/chunk-PDBDDGG5.cjs.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
3
|
+
var chunk4WJUSDJJ_cjs = require('./chunk-4WJUSDJJ.cjs');
|
|
4
|
+
var chunkS3ZI4MKS_cjs = require('./chunk-S3ZI4MKS.cjs');
|
|
5
5
|
var chunkUQBGW5DO_cjs = require('./chunk-UQBGW5DO.cjs');
|
|
6
6
|
var PIXI = require('pixi.js');
|
|
7
7
|
var gsap = require('gsap');
|
|
@@ -843,16 +843,16 @@ function expandTransitions(spec) {
|
|
|
843
843
|
if (toUses > 1) {
|
|
844
844
|
throw new Error(`pixi-effects: ${tag} sequence "${t.to}" is used as \`to\` in more than one transition`);
|
|
845
845
|
}
|
|
846
|
-
const tStart =
|
|
846
|
+
const tStart = chunkS3ZI4MKS_cjs.resolveAt(t.at, parentDuration);
|
|
847
847
|
const tEnd = tStart + t.duration;
|
|
848
848
|
const fromSeq = fromEntry.seq;
|
|
849
|
-
const fromStart =
|
|
849
|
+
const fromStart = chunkS3ZI4MKS_cjs.resolveAt(fromSeq.at, parentDuration);
|
|
850
850
|
const fromEnd = fromStart + (fromSeq.duration ?? parentDuration);
|
|
851
851
|
if (tStart < fromStart || tEnd > fromEnd) {
|
|
852
852
|
throw new Error(`pixi-effects: ${tag} window [${tStart}, ${tEnd}] is not covered by \`from\` "${t.from}" (lives [${fromStart}, ${fromEnd}], so it ends at ${fromEnd})`);
|
|
853
853
|
}
|
|
854
854
|
const toSeq = toEntry.seq;
|
|
855
|
-
const toStart =
|
|
855
|
+
const toStart = chunkS3ZI4MKS_cjs.resolveAt(toSeq.at, parentDuration);
|
|
856
856
|
const toEnd = toStart + (toSeq.duration ?? parentDuration);
|
|
857
857
|
if (tStart < toStart || tEnd > toEnd) {
|
|
858
858
|
throw new Error(`pixi-effects: ${tag} window [${tStart}, ${tEnd}] is not covered by \`to\` "${t.to}" (lives [${toStart}, ${toEnd}], so it starts at ${toStart})`);
|
|
@@ -1173,12 +1173,12 @@ function inspectScene(root, frame, time, canvas, opts = {}) {
|
|
|
1173
1173
|
blending.add(w.to);
|
|
1174
1174
|
}
|
|
1175
1175
|
}
|
|
1176
|
-
comp.layers().forEach(({ seq, display, threeD }, i) => {
|
|
1176
|
+
comp.layers().forEach(({ seq, display, threeD, carriers }, i) => {
|
|
1177
1177
|
const t = seq.target;
|
|
1178
1178
|
const name = seq.spec.name;
|
|
1179
1179
|
const label = name ?? `${seq.spec.type}#${i}`;
|
|
1180
|
-
const alpha = t?.alpha ?? 1;
|
|
1181
|
-
const alive = threeD ? display.visible : t?.renderable ?? true;
|
|
1180
|
+
const alpha = (t?.alpha ?? 1) * carriers.reduce((a, c) => a * (c.target?.alpha ?? 1), 1);
|
|
1181
|
+
const alive = (threeD ? display.visible : t?.renderable ?? true) && carriers.every((c) => c.target?.renderable ?? true);
|
|
1182
1182
|
const visible = parentVisible && alive && alpha > 0;
|
|
1183
1183
|
let bounds = null;
|
|
1184
1184
|
if (!insideThreeD) {
|
|
@@ -1192,10 +1192,17 @@ function inspectScene(root, frame, time, canvas, opts = {}) {
|
|
|
1192
1192
|
onCanvas = inter === 0 && area > 0 ? "none" : inter >= area - 1e-6 ? "full" : "partial";
|
|
1193
1193
|
if (area === 0) onCanvas = "none";
|
|
1194
1194
|
}
|
|
1195
|
-
const keys =
|
|
1196
|
-
const
|
|
1197
|
-
|
|
1198
|
-
|
|
1195
|
+
const keys = chunkS3ZI4MKS_cjs.collectPropKeys(seq.spec);
|
|
1196
|
+
const carried = carriers.some((c) => {
|
|
1197
|
+
const k = chunkS3ZI4MKS_cjs.collectPropKeys(c.spec);
|
|
1198
|
+
return (c.spec.keyframes ?? []).length > 0 && (k.has("x") || k.has("y") || k.has("rotation") || k.has("scale"));
|
|
1199
|
+
});
|
|
1200
|
+
const moving = parentMoving || carried || (seq.spec.keyframes ?? []).length > 0 && (keys.has("x") || keys.has("y"));
|
|
1201
|
+
const zeroScale = (o) => {
|
|
1202
|
+
const s = o?.scale;
|
|
1203
|
+
return !!s && (s.x === 0 || s.y === 0);
|
|
1204
|
+
};
|
|
1205
|
+
const zero = parentZero || zeroScale(t) || carriers.some((c) => zeroScale(c.target));
|
|
1199
1206
|
const info = { path: prefix + label, name, type: seq.spec.type, threeD, visible, alpha, moving, bounds, onCanvas };
|
|
1200
1207
|
layers.push(info);
|
|
1201
1208
|
let shown = bounds ? clip(bounds, view) : null;
|
|
@@ -1208,7 +1215,7 @@ function inspectScene(root, frame, time, canvas, opts = {}) {
|
|
|
1208
1215
|
const group = parentScene ?? (name !== void 0 && blending.has(name) ? name : void 0);
|
|
1209
1216
|
if (group) scene.set(info, group);
|
|
1210
1217
|
if (zero || seq.showsNothingYet) scaledToNothing.add(info);
|
|
1211
|
-
if (seq instanceof
|
|
1218
|
+
if (seq instanceof chunk4WJUSDJJ_cjs.CompositionSequence) walk2(seq, prefix + label + "/", insideThreeD || threeD, visible, group, moving, zero);
|
|
1212
1219
|
});
|
|
1213
1220
|
};
|
|
1214
1221
|
walk2(root, "", false, true);
|
|
@@ -1268,10 +1275,10 @@ function walk(comp, parentStart, parentEnd, depth, prefix, rows, transitions) {
|
|
|
1268
1275
|
const start = parentStart + (seq.at ?? 0);
|
|
1269
1276
|
const end = Math.min(parentEnd, seq.duration !== void 0 ? start + seq.duration : parentEnd);
|
|
1270
1277
|
const span = end - start;
|
|
1271
|
-
const keys = (seq.spec.keyframes ?? []).map((kf) => round(start +
|
|
1278
|
+
const keys = (seq.spec.keyframes ?? []).map((kf) => round(start + chunkS3ZI4MKS_cjs.resolveAt(kf.at, span))).sort((a, b) => a - b).slice(0, MAX_KEYS);
|
|
1272
1279
|
const row = { path: prefix + name, name, type: seq.spec.type, depth, start: round(start), end: round(end), keys, detail: detailOf(seq) };
|
|
1273
1280
|
const inner = [];
|
|
1274
|
-
const isComp = seq instanceof
|
|
1281
|
+
const isComp = seq instanceof chunk4WJUSDJJ_cjs.CompositionSequence;
|
|
1275
1282
|
if (isComp) walk(seq, start, end, depth + 1, prefix + name + "/", inner, transitions);
|
|
1276
1283
|
entries.push({ row, inner, groupable: !isComp });
|
|
1277
1284
|
});
|
|
@@ -1328,7 +1335,8 @@ var COLORS = {
|
|
|
1328
1335
|
audio: "#ff7aa8",
|
|
1329
1336
|
composition: "#8ea4c8",
|
|
1330
1337
|
three: "#ff9f68",
|
|
1331
|
-
camera: "#b0b0b0"
|
|
1338
|
+
camera: "#b0b0b0",
|
|
1339
|
+
null: "#b0b0b0"
|
|
1332
1340
|
};
|
|
1333
1341
|
var esc = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
1334
1342
|
var num = (n) => String(Math.round(n * 100) / 100);
|
|
@@ -1610,7 +1618,7 @@ var Movie = class {
|
|
|
1610
1618
|
height: options.composition.height ?? this.height,
|
|
1611
1619
|
duration: options.composition.duration ?? this.duration
|
|
1612
1620
|
} : void 0;
|
|
1613
|
-
await
|
|
1621
|
+
await chunkS3ZI4MKS_cjs.ensureFilterLibrary(seededComposition);
|
|
1614
1622
|
const userComposition = seededComposition ? expandTransitions(seededComposition) : void 0;
|
|
1615
1623
|
const rootSeqSpec = {
|
|
1616
1624
|
type: "composition",
|
|
@@ -1620,7 +1628,7 @@ var Movie = class {
|
|
|
1620
1628
|
...userComposition
|
|
1621
1629
|
};
|
|
1622
1630
|
if (userComposition) carryTransitionWindows(userComposition, rootSeqSpec);
|
|
1623
|
-
const composition = new
|
|
1631
|
+
const composition = new chunk4WJUSDJJ_cjs.CompositionSequence(rootSeqSpec, null, rootShape);
|
|
1624
1632
|
await composition.build();
|
|
1625
1633
|
this._rootSequence = composition;
|
|
1626
1634
|
if (composition.target) root.addChild(composition.target);
|
|
@@ -2119,17 +2127,17 @@ function orbit(opts) {
|
|
|
2119
2127
|
throw new Error("pixi-effects: orbit() cannot combine `radius` with `dollyZoom` \u2014 the radius follows the animated fov");
|
|
2120
2128
|
}
|
|
2121
2129
|
const [cx, cy] = opts.center ?? [width / 2, height / 2];
|
|
2122
|
-
const fixedR = opts.radius ??
|
|
2130
|
+
const fixedR = opts.radius ?? chunkS3ZI4MKS_cjs.homeDistance(height, fov ?? chunkS3ZI4MKS_cjs.DEFAULT_FOV);
|
|
2123
2131
|
const start = opts.start ?? -degrees / 2;
|
|
2124
2132
|
const steps = Math.max(1, Math.round(duration * stepsPerSecond));
|
|
2125
2133
|
const easeFn = parseEase(ease);
|
|
2126
2134
|
const dollyEase = dolly ? parseEase(dolly.ease ?? ease) : null;
|
|
2127
2135
|
const pos = (i) => {
|
|
2128
2136
|
const p = i / steps;
|
|
2129
|
-
const a = (start + degrees * easeFn(p)) *
|
|
2137
|
+
const a = (start + degrees * easeFn(p)) * chunkS3ZI4MKS_cjs.DEG;
|
|
2130
2138
|
if (!dolly) return { x: cx + fixedR * Math.sin(a), z: fixedR * Math.cos(a) };
|
|
2131
2139
|
const f = dolly.from + (dolly.to - dolly.from) * dollyEase(p);
|
|
2132
|
-
const R =
|
|
2140
|
+
const R = chunkS3ZI4MKS_cjs.homeDistance(height, f);
|
|
2133
2141
|
return { x: cx + R * Math.sin(a), z: R * Math.cos(a), fov: f };
|
|
2134
2142
|
};
|
|
2135
2143
|
const keyframes = [];
|
|
@@ -2156,6 +2164,269 @@ function orbit(opts) {
|
|
|
2156
2164
|
return spec;
|
|
2157
2165
|
}
|
|
2158
2166
|
|
|
2167
|
+
// src/presets/followPath.ts
|
|
2168
|
+
var KEYS = ["d", "at", "duration", "ease", "from", "to", "orient", "rotate", "frameRate"];
|
|
2169
|
+
var MAX_STEPS = 2e3;
|
|
2170
|
+
function followPath(opts) {
|
|
2171
|
+
chunkUQBGW5DO_cjs.warnUnknownOptions("followPath()", opts, KEYS);
|
|
2172
|
+
const { d, at = 0, duration, ease = "none", from = 0, to = 1, orient = false, rotate = 0, frameRate = 30 } = opts;
|
|
2173
|
+
if (typeof d !== "string" || d.trim() === "") throw new Error('followPath(): d must be SVG path data, e.g. "M 100 600 C 300 100 900 100 1180 600"');
|
|
2174
|
+
if (!(Number.isFinite(duration) && duration > 0)) throw new Error(`followPath(): duration must be a positive number of seconds, got ${duration}`);
|
|
2175
|
+
if (!(Number.isFinite(frameRate) && frameRate > 0)) throw new Error(`followPath(): frameRate must be a positive number (samples per second), got ${frameRate}`);
|
|
2176
|
+
for (const [n, v] of [["from", from], ["to", to]]) {
|
|
2177
|
+
if (!(Number.isFinite(v) && v >= 0 && v <= 1)) throw new Error(`followPath(): ${n} must be a fraction of the path between 0 and 1, got ${v}`);
|
|
2178
|
+
}
|
|
2179
|
+
const steps = Math.max(1, Math.round(duration * frameRate));
|
|
2180
|
+
if (steps > MAX_STEPS) throw new Error(`followPath(): ${steps} samples is too many (max ${MAX_STEPS}); lower frameRate or duration`);
|
|
2181
|
+
const segments = [];
|
|
2182
|
+
let total = 0;
|
|
2183
|
+
for (const line of chunkS3ZI4MKS_cjs.flattenSvgPath(d)) {
|
|
2184
|
+
const p = line.closed ? [...line.pts, line.pts[0], line.pts[1]] : line.pts;
|
|
2185
|
+
for (let i = 2; i < p.length; i += 2) {
|
|
2186
|
+
const len = Math.hypot(p[i] - p[i - 2], p[i + 1] - p[i - 1]);
|
|
2187
|
+
if (len === 0) continue;
|
|
2188
|
+
segments.push({ x0: p[i - 2], y0: p[i - 1], x1: p[i], y1: p[i + 1], start: total, len });
|
|
2189
|
+
total += len;
|
|
2190
|
+
}
|
|
2191
|
+
}
|
|
2192
|
+
if (!(total > 0)) throw new Error(`followPath(): the path "${d}" has no length (it needs at least two different points)`);
|
|
2193
|
+
const find = (s) => {
|
|
2194
|
+
let lo = 0, hi = segments.length - 1;
|
|
2195
|
+
while (lo < hi) {
|
|
2196
|
+
const mid = lo + hi >> 1;
|
|
2197
|
+
if (segments[mid].start + segments[mid].len < s) lo = mid + 1;
|
|
2198
|
+
else hi = mid;
|
|
2199
|
+
}
|
|
2200
|
+
return segments[lo];
|
|
2201
|
+
};
|
|
2202
|
+
const at_ = (fraction) => {
|
|
2203
|
+
const s = Math.min(Math.max(fraction, 0), 1) * total;
|
|
2204
|
+
const g = find(s);
|
|
2205
|
+
const t = Math.min(Math.max((s - g.start) / g.len, 0), 1);
|
|
2206
|
+
return { x: g.x0 + (g.x1 - g.x0) * t, y: g.y0 + (g.y1 - g.y0) * t, heading: Math.atan2(g.y1 - g.y0, g.x1 - g.x0) * 180 / Math.PI };
|
|
2207
|
+
};
|
|
2208
|
+
const shape = parseEase(ease);
|
|
2209
|
+
const round2 = (v) => Math.round(v * 1e6) / 1e6;
|
|
2210
|
+
let turn = 0;
|
|
2211
|
+
const sample = (k) => {
|
|
2212
|
+
const p = from + (to - from) * shape(k / steps);
|
|
2213
|
+
const pt = at_(p);
|
|
2214
|
+
const out2 = { x: round2(pt.x), y: round2(pt.y) };
|
|
2215
|
+
if (orient) {
|
|
2216
|
+
let h = pt.heading + rotate;
|
|
2217
|
+
if (k === 0) turn = h;
|
|
2218
|
+
else {
|
|
2219
|
+
let delta = h - turn;
|
|
2220
|
+
delta -= 360 * Math.round(delta / 360);
|
|
2221
|
+
turn += delta;
|
|
2222
|
+
}
|
|
2223
|
+
out2.rotation = round2(turn);
|
|
2224
|
+
}
|
|
2225
|
+
return out2;
|
|
2226
|
+
};
|
|
2227
|
+
const out = [{ at, set: sample(0) }];
|
|
2228
|
+
const step = duration / steps;
|
|
2229
|
+
for (let k = 1; k <= steps; k++) out.push({ at: round2(at + (k - 1) * step), to: sample(k), duration: round2(step), ease: "none" });
|
|
2230
|
+
return out;
|
|
2231
|
+
}
|
|
2232
|
+
|
|
2233
|
+
// src/presets/stagger.ts
|
|
2234
|
+
var STAGGER_KEYS = ["each", "amount", "from", "grid", "ease", "seed"];
|
|
2235
|
+
var FROM_NAMES = ["start", "end", "center", "edges", "random"];
|
|
2236
|
+
function stagger(items, options = {}) {
|
|
2237
|
+
const isCount = typeof items === "number";
|
|
2238
|
+
const n = isCount ? items : items.length;
|
|
2239
|
+
if (!Number.isInteger(n) || n < 0) throw new Error(`stagger(): count must be a whole number of items, got ${n}`);
|
|
2240
|
+
chunkUQBGW5DO_cjs.warnUnknownOptions("stagger()", options, STAGGER_KEYS);
|
|
2241
|
+
const { each, amount, from = "start", grid, ease = "none", seed = 0 } = options;
|
|
2242
|
+
if (each !== void 0 && amount !== void 0) throw new Error("stagger(): give `each` (seconds between neighbours) or `amount` (seconds in total), not both");
|
|
2243
|
+
if (each !== void 0 && !(Number.isFinite(each) && each >= 0)) throw new Error(`stagger(): each must be a number of seconds >= 0, got ${each}`);
|
|
2244
|
+
if (amount !== void 0 && !(Number.isFinite(amount) && amount >= 0)) throw new Error(`stagger(): amount must be a number of seconds >= 0, got ${amount}`);
|
|
2245
|
+
if (typeof from === "string" && !FROM_NAMES.includes(from)) {
|
|
2246
|
+
throw new Error(`stagger(): from "${from}" is not one of ${FROM_NAMES.map((f) => `"${f}"`).join(", ")} or an item index`);
|
|
2247
|
+
}
|
|
2248
|
+
if (typeof from === "number" && !(Number.isInteger(from) && from >= 0 && from < Math.max(n, 1))) throw new Error(`stagger(): from ${from} is not an index of the ${n} items`);
|
|
2249
|
+
if (grid && !(Array.isArray(grid) && grid.length === 2 && grid.every((g) => Number.isInteger(g) && g > 0) && grid[0] * grid[1] >= n)) {
|
|
2250
|
+
throw new Error(`stagger(): grid must be [columns, rows] and hold all ${n} items, got ${JSON.stringify(grid)}`);
|
|
2251
|
+
}
|
|
2252
|
+
const dist = distances(n, from, grid, seed);
|
|
2253
|
+
const max = dist.reduce((m, d) => Math.max(m, d), 0);
|
|
2254
|
+
const total = amount !== void 0 ? amount : (each ?? 0.1) * max;
|
|
2255
|
+
const shape = parseEase(ease);
|
|
2256
|
+
const delays = dist.map((d) => max === 0 ? 0 : Math.round(total * shape(d / max) * 1e6) / 1e6);
|
|
2257
|
+
if (isCount) return delays;
|
|
2258
|
+
return items.map((layer, i) => ({ ...layer, at: Math.round(((layer.at ?? 0) + delays[i]) * 1e6) / 1e6 }));
|
|
2259
|
+
}
|
|
2260
|
+
function distances(n, from, grid, seed) {
|
|
2261
|
+
if (n === 0) return [];
|
|
2262
|
+
if (from === "random") {
|
|
2263
|
+
const order = Array.from({ length: n }, (_, i) => i);
|
|
2264
|
+
const r = chunkS3ZI4MKS_cjs.random(seed);
|
|
2265
|
+
for (let i = n - 1; i > 0; i--) {
|
|
2266
|
+
const j = Math.floor(r() * (i + 1));
|
|
2267
|
+
[order[i], order[j]] = [order[j], order[i]];
|
|
2268
|
+
}
|
|
2269
|
+
return order;
|
|
2270
|
+
}
|
|
2271
|
+
if (!grid) {
|
|
2272
|
+
const mid = (n - 1) / 2;
|
|
2273
|
+
return Array.from({ length: n }, (_, i) => {
|
|
2274
|
+
switch (from) {
|
|
2275
|
+
case "start":
|
|
2276
|
+
return i;
|
|
2277
|
+
case "end":
|
|
2278
|
+
return n - 1 - i;
|
|
2279
|
+
case "center":
|
|
2280
|
+
return Math.abs(i - mid);
|
|
2281
|
+
case "edges":
|
|
2282
|
+
return mid - Math.abs(i - mid);
|
|
2283
|
+
default:
|
|
2284
|
+
return Math.abs(i - from);
|
|
2285
|
+
}
|
|
2286
|
+
});
|
|
2287
|
+
}
|
|
2288
|
+
const [cols, rows] = grid;
|
|
2289
|
+
const at = (i) => ({ x: i % cols, y: Math.floor(i / cols) });
|
|
2290
|
+
const origin = from === "start" ? { x: 0, y: 0 } : from === "end" ? { x: cols - 1, y: rows - 1 } : from === "center" || from === "edges" ? { x: (cols - 1) / 2, y: (rows - 1) / 2 } : at(from);
|
|
2291
|
+
const d = Array.from({ length: n }, (_, i) => Math.hypot(at(i).x - origin.x, at(i).y - origin.y));
|
|
2292
|
+
if (from !== "edges") return d;
|
|
2293
|
+
const far = Math.max(...d);
|
|
2294
|
+
return d.map((v) => far - v);
|
|
2295
|
+
}
|
|
2296
|
+
|
|
2297
|
+
// src/presets/wiggle.ts
|
|
2298
|
+
var WIGGLE_KEYS = ["at", "duration", "freq", "seed", "ease", "props"];
|
|
2299
|
+
var MAX_STEPS2 = 2e3;
|
|
2300
|
+
function wiggle(opts) {
|
|
2301
|
+
chunkUQBGW5DO_cjs.warnUnknownOptions("wiggle()", opts, WIGGLE_KEYS);
|
|
2302
|
+
const { at = 0, duration, freq = 3, seed = 0, ease = "sine.inOut", props } = opts;
|
|
2303
|
+
if (!(Number.isFinite(duration) && duration > 0)) throw new Error(`wiggle(): duration must be a positive number of seconds, got ${duration}`);
|
|
2304
|
+
if (!(Number.isFinite(freq) && freq > 0)) throw new Error(`wiggle(): freq must be a positive number (steps per second), got ${freq}`);
|
|
2305
|
+
const names = Object.keys(props ?? {});
|
|
2306
|
+
if (names.length === 0) throw new Error("wiggle(): props is empty; name at least one property, e.g. props: { x: { around: 100, amp: 8 } }");
|
|
2307
|
+
for (const n of names) {
|
|
2308
|
+
const p = props[n];
|
|
2309
|
+
if (!Number.isFinite(p.amp)) throw new Error(`wiggle(): props.${n}.amp must be a number, got ${p.amp}`);
|
|
2310
|
+
if (p.around === void 0 || p.around === null || p.around === "") throw new Error(`wiggle(): props.${n}.around is missing`);
|
|
2311
|
+
}
|
|
2312
|
+
const steps = Math.ceil(duration * freq - 1e-9);
|
|
2313
|
+
if (steps > MAX_STEPS2) throw new Error(`wiggle(): ${steps} steps is too many (max ${MAX_STEPS2}); lower freq or duration`);
|
|
2314
|
+
const set = {};
|
|
2315
|
+
for (const n of names) set[n] = props[n].around;
|
|
2316
|
+
const out = [{ at, set }];
|
|
2317
|
+
const stepLen = duration / steps;
|
|
2318
|
+
for (let s = 0; s < steps; s++) {
|
|
2319
|
+
const to = {};
|
|
2320
|
+
names.forEach((n, pi) => {
|
|
2321
|
+
const p = props[n];
|
|
2322
|
+
if (s === steps - 1) {
|
|
2323
|
+
to[n] = p.around;
|
|
2324
|
+
return;
|
|
2325
|
+
}
|
|
2326
|
+
const off = (chunkS3ZI4MKS_cjs.rand(seed * 7919 + pi * 104729 + s * 31 + 1) * 2 - 1) * p.amp;
|
|
2327
|
+
to[n] = typeof p.around === "number" ? p.around + off : `(${p.around}) ${off < 0 ? "-" : "+"} ${Math.abs(off)}`;
|
|
2328
|
+
});
|
|
2329
|
+
out.push({ at: at + s * stepLen, to, duration: stepLen, ease });
|
|
2330
|
+
}
|
|
2331
|
+
return out;
|
|
2332
|
+
}
|
|
2333
|
+
|
|
2334
|
+
// src/presets/animateText.ts
|
|
2335
|
+
var KEYS2 = ["by", "x", "y", "align", "name", "at", "duration", "in", "out", "stagger", "idle", "styleFor"];
|
|
2336
|
+
var PRESETS = {
|
|
2337
|
+
rise: { from: { y: 40, alpha: 0 }, duration: 0.5, ease: "back.out(2)" },
|
|
2338
|
+
drop: { from: { y: -50, alpha: 0 }, duration: 0.7, ease: "bounce.out" },
|
|
2339
|
+
fade: { from: { alpha: 0 }, duration: 0.5, ease: "power1.out" },
|
|
2340
|
+
pop: { from: { scale: 0, alpha: 0 }, duration: 0.45, ease: "back.out(2.4)" },
|
|
2341
|
+
zoom: { from: { scale: 2.5, alpha: 0 }, duration: 0.6, ease: "power3.out" },
|
|
2342
|
+
slide: { from: { x: -60, alpha: 0 }, duration: 0.5, ease: "power3.out" },
|
|
2343
|
+
spin: { from: { rotation: -90, scale: 0, alpha: 0 }, duration: 0.6, ease: "back.out(1.7)" }
|
|
2344
|
+
};
|
|
2345
|
+
var PRESET_NAMES = Object.keys(PRESETS);
|
|
2346
|
+
function animateText(text, style, options) {
|
|
2347
|
+
chunkUQBGW5DO_cjs.warnUnknownOptions("animateText()", options, KEYS2);
|
|
2348
|
+
const { by = "chars", x = 0, y = 0, align = "left", name = "text", at = 0, duration, idle, styleFor } = options;
|
|
2349
|
+
if (!(Number.isFinite(duration) && duration > 0)) throw new Error(`animateText(): duration must be a positive number of seconds (how long until the last piece is gone), got ${duration}`);
|
|
2350
|
+
const pieces = splitText(text, style, { by, x, y, align });
|
|
2351
|
+
if (pieces.length === 0) return [];
|
|
2352
|
+
const lineHeight = measureText("M", style).height;
|
|
2353
|
+
const inTween = options.in === false ? null : resolveTween(options.in ?? "rise", "in");
|
|
2354
|
+
const outTween = options.out === void 0 || options.out === false ? null : resolveTween(options.out, "out");
|
|
2355
|
+
const delays = stagger(pieces.length, options.stagger ?? { each: 0.04 });
|
|
2356
|
+
const wave = Math.max(...delays);
|
|
2357
|
+
const need = (inTween?.duration ?? 0) + (outTween?.duration ?? 0) + wave;
|
|
2358
|
+
if (duration < need - 1e-9) {
|
|
2359
|
+
throw new Error(`animateText(): duration ${duration} is too short for this wave: the entrance${outTween ? ", the exit" : ""} and the stagger need at least ${+need.toFixed(3)} s`);
|
|
2360
|
+
}
|
|
2361
|
+
const end = at + duration;
|
|
2362
|
+
return pieces.map((p, i) => {
|
|
2363
|
+
const cx = p.x + p.width / 2, cy = p.y + lineHeight / 2;
|
|
2364
|
+
const rest = { x: cx, y: cy, alpha: 1, scale: 1, scaleX: 1, scaleY: 1, rotation: 0 };
|
|
2365
|
+
const start = at + delays[i];
|
|
2366
|
+
const len = end - start;
|
|
2367
|
+
const keyframes = [];
|
|
2368
|
+
const place = (key, v) => key === "x" || key === "y" ? rest[key] + v : v;
|
|
2369
|
+
if (inTween) {
|
|
2370
|
+
keyframes.push({
|
|
2371
|
+
at: 0,
|
|
2372
|
+
duration: inTween.duration,
|
|
2373
|
+
ease: inTween.ease,
|
|
2374
|
+
from: Object.fromEntries(Object.entries(inTween.from).map(([k, v]) => [k, place(k, v)])),
|
|
2375
|
+
to: Object.fromEntries(Object.keys(inTween.from).map((k) => [k, inTween.to[k] ?? rest[k]]))
|
|
2376
|
+
});
|
|
2377
|
+
}
|
|
2378
|
+
let idleEnd = len;
|
|
2379
|
+
if (outTween) {
|
|
2380
|
+
const begin = outTween.duration + (wave - delays[i]);
|
|
2381
|
+
idleEnd = len - begin;
|
|
2382
|
+
keyframes.push({
|
|
2383
|
+
at: -begin,
|
|
2384
|
+
duration: outTween.duration,
|
|
2385
|
+
ease: outTween.ease,
|
|
2386
|
+
from: Object.fromEntries(Object.keys(outTween.from).map((k) => [k, outTween.to[k] ?? rest[k]])),
|
|
2387
|
+
to: Object.fromEntries(Object.entries(outTween.from).map(([k, v]) => [k, place(k, v)]))
|
|
2388
|
+
});
|
|
2389
|
+
}
|
|
2390
|
+
if (idle) {
|
|
2391
|
+
const props = {};
|
|
2392
|
+
for (const k of ["x", "y", "rotation", "scale"]) if (idle[k] !== void 0) props[k] = { around: rest[k], amp: idle[k] };
|
|
2393
|
+
const freq = idle.freq ?? 1;
|
|
2394
|
+
const from = inTween?.duration ?? 0;
|
|
2395
|
+
if (Object.keys(props).length > 0 && idleEnd - from >= 1 / freq) {
|
|
2396
|
+
keyframes.push(...wiggle({ at: from, duration: idleEnd - from, freq, seed: (idle.seed ?? 0) * 1e3 + i, props }));
|
|
2397
|
+
}
|
|
2398
|
+
}
|
|
2399
|
+
return {
|
|
2400
|
+
type: "text",
|
|
2401
|
+
name: `${name}-${i}`,
|
|
2402
|
+
text: p.text,
|
|
2403
|
+
style: styleFor ? { ...style, ...styleFor(p) } : style,
|
|
2404
|
+
at: start,
|
|
2405
|
+
duration: len,
|
|
2406
|
+
initial: { x: cx, y: cy, anchorX: 0.5, anchorY: 0.5 },
|
|
2407
|
+
keyframes
|
|
2408
|
+
};
|
|
2409
|
+
});
|
|
2410
|
+
}
|
|
2411
|
+
function resolveTween(spec, which) {
|
|
2412
|
+
const t = typeof spec === "string" ? { preset: spec } : spec;
|
|
2413
|
+
if (t.preset !== void 0 && !(t.preset in PRESETS)) {
|
|
2414
|
+
const guess = chunkUQBGW5DO_cjs.suggestName(String(t.preset), PRESET_NAMES);
|
|
2415
|
+
throw new Error(`animateText(): ${which} "${t.preset}" is not a preset${guess ? `; did you mean "${guess}"?` : ""} (presets: ${PRESET_NAMES.map((n) => `"${n}"`).join(", ")})`);
|
|
2416
|
+
}
|
|
2417
|
+
const base = t.preset ? PRESETS[t.preset] : void 0;
|
|
2418
|
+
const from = { ...base?.from ?? {}, ...t.from ?? {} };
|
|
2419
|
+
const to = t.to ?? {};
|
|
2420
|
+
const known = /* @__PURE__ */ new Set(["x", "y", "alpha", "scale", "scaleX", "scaleY", "rotation"]);
|
|
2421
|
+
for (const k of Object.keys(from)) {
|
|
2422
|
+
if (!known.has(k) && to[k] === void 0) throw new Error(`animateText(): ${which}.from has "${k}", which has no resting value; give ${which}.to: { ${k}: \u2026 }`);
|
|
2423
|
+
}
|
|
2424
|
+
if (Object.keys(from).length === 0) throw new Error(`animateText(): ${which} needs a preset or a from`);
|
|
2425
|
+
let ease = t.ease ?? base?.ease ?? "power2.out";
|
|
2426
|
+
if (which === "out" && t.ease === void 0) ease = ease.replace(".out", ".in");
|
|
2427
|
+
return { from, to: { ...to }, duration: t.duration ?? base?.duration ?? 0.5, ease };
|
|
2428
|
+
}
|
|
2429
|
+
|
|
2159
2430
|
// src/transforms/withFade.ts
|
|
2160
2431
|
function withFade(spec, opts) {
|
|
2161
2432
|
chunkUQBGW5DO_cjs.warnUnknownOptions("withFade()", opts, ["in", "out"]);
|
|
@@ -2176,15 +2447,31 @@ function withFade(spec, opts) {
|
|
|
2176
2447
|
return spec;
|
|
2177
2448
|
}
|
|
2178
2449
|
|
|
2450
|
+
Object.defineProperty(exports, "noise", {
|
|
2451
|
+
enumerable: true,
|
|
2452
|
+
get: function () { return chunkS3ZI4MKS_cjs.noise; }
|
|
2453
|
+
});
|
|
2454
|
+
Object.defineProperty(exports, "rand", {
|
|
2455
|
+
enumerable: true,
|
|
2456
|
+
get: function () { return chunkS3ZI4MKS_cjs.rand; }
|
|
2457
|
+
});
|
|
2458
|
+
Object.defineProperty(exports, "random", {
|
|
2459
|
+
enumerable: true,
|
|
2460
|
+
get: function () { return chunkS3ZI4MKS_cjs.random; }
|
|
2461
|
+
});
|
|
2179
2462
|
Object.defineProperty(exports, "registerSequenceType", {
|
|
2180
2463
|
enumerable: true,
|
|
2181
|
-
get: function () { return
|
|
2464
|
+
get: function () { return chunkS3ZI4MKS_cjs.registerSequenceType; }
|
|
2182
2465
|
});
|
|
2183
2466
|
exports.Movie = Movie;
|
|
2467
|
+
exports.animateText = animateText;
|
|
2468
|
+
exports.followPath = followPath;
|
|
2184
2469
|
exports.kenBurns = kenBurns;
|
|
2185
2470
|
exports.measureText = measureText;
|
|
2186
2471
|
exports.orbit = orbit;
|
|
2187
2472
|
exports.splitText = splitText;
|
|
2473
|
+
exports.stagger = stagger;
|
|
2474
|
+
exports.wiggle = wiggle;
|
|
2188
2475
|
exports.withFade = withFade;
|
|
2189
2476
|
//# sourceMappingURL=index.cjs.map
|
|
2190
2477
|
//# sourceMappingURL=index.cjs.map
|