@sliiu/present-transition-fx 0.0.0-stage → 0.1.1

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.
Files changed (48) hide show
  1. package/COPYRIGHT +5 -0
  2. package/LICENSE +661 -0
  3. package/README.md +8 -2
  4. package/THIRD-PARTY-NOTICES.md +221 -0
  5. package/dist/cjs/2d.js +487 -0
  6. package/dist/cjs/3d.js +566 -0
  7. package/dist/cjs/geometry.js +141 -0
  8. package/dist/cjs/index.js +98 -0
  9. package/dist/cjs/morph-audit.js +603 -0
  10. package/dist/cjs/morph-match.js +103 -0
  11. package/dist/cjs/morph-path.js +649 -0
  12. package/dist/cjs/morph.js +223 -0
  13. package/dist/cjs/package.json +1 -0
  14. package/dist/cjs/registry.js +130 -0
  15. package/dist/cjs/snapshot.js +420 -0
  16. package/dist/cjs/twin.js +88 -0
  17. package/dist/cjs/types.js +2 -0
  18. package/dist/cjs/util.js +50 -0
  19. package/dist/cjs/webgl.js +271 -0
  20. package/dist/esm/2d.js +454 -0
  21. package/dist/esm/3d.js +538 -0
  22. package/dist/esm/geometry.js +127 -0
  23. package/dist/esm/index.js +6 -0
  24. package/dist/esm/morph-audit.js +558 -0
  25. package/dist/esm/morph-match.js +97 -0
  26. package/dist/esm/morph-path.js +636 -0
  27. package/dist/esm/morph.js +219 -0
  28. package/dist/esm/registry.js +91 -0
  29. package/dist/esm/snapshot.js +414 -0
  30. package/dist/esm/twin.js +84 -0
  31. package/dist/esm/types.js +1 -0
  32. package/dist/esm/util.js +43 -0
  33. package/dist/esm/webgl.js +231 -0
  34. package/dist/types/2d.d.ts +40 -0
  35. package/dist/types/3d.d.ts +38 -0
  36. package/dist/types/geometry.d.ts +38 -0
  37. package/dist/types/index.d.ts +7 -0
  38. package/dist/types/morph-audit.d.ts +127 -0
  39. package/dist/types/morph-match.d.ts +28 -0
  40. package/dist/types/morph-path.d.ts +37 -0
  41. package/dist/types/morph.d.ts +2 -0
  42. package/dist/types/registry.d.ts +6 -0
  43. package/dist/types/snapshot.d.ts +19 -0
  44. package/dist/types/twin.d.ts +2 -0
  45. package/dist/types/types.d.ts +13 -0
  46. package/dist/types/util.d.ts +12 -0
  47. package/dist/types/webgl.d.ts +5 -0
  48. package/package.json +36 -4
package/dist/cjs/2d.js ADDED
@@ -0,0 +1,487 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.wedge = exports.strips = exports.comb = exports.prestige = exports.fracture = exports.shred = exports.honeycomb = exports.glitter = exports.flash = exports.reveal = exports.fall = exports.random = exports.plus = exports.diamond = exports.circle = exports.wheelReverse = exports.wheel = exports.newsflash = exports.dissolve = exports.randomBar = exports.checker = exports.blinds = exports.zoom = exports.split = exports.wipe = exports.uncover = exports.cover = exports.push = exports.cut = exports.fade = void 0;
4
+ const geometry_1 = require("./geometry");
5
+ const twin_1 = require("./twin");
6
+ const util_1 = require("./util");
7
+ const fade = async (ctx) => {
8
+ const a = ctx.ghost.animate([{ opacity: 1 }, { opacity: 0 }], { duration: (0, util_1.ms)(ctx), easing: (0, util_1.easing)(ctx), fill: "forwards" });
9
+ await (0, util_1.runAll)([a]);
10
+ };
11
+ exports.fade = fade;
12
+ const cut = async () => {
13
+ // instant
14
+ };
15
+ exports.cut = cut;
16
+ const push = async (ctx) => {
17
+ const { dx, dy } = (0, util_1.dirVec)(String(ctx.params.dir ?? "left"), ctx.stageSize.w, ctx.stageSize.h);
18
+ const sBase = ctx.stage.style.transform || "";
19
+ const gBase = ctx.ghost.style.transform || "";
20
+ const a = ctx.stage.animate([{ transform: `translate(${dx}px, ${dy}px) ${sBase}` }, { transform: sBase }], { duration: (0, util_1.ms)(ctx), easing: (0, util_1.easing)(ctx), fill: "forwards" });
21
+ const b = ctx.ghost.animate([{ transform: gBase }, { transform: `translate(${-dx}px, ${-dy}px) ${gBase}` }], { duration: (0, util_1.ms)(ctx), easing: (0, util_1.easing)(ctx), fill: "forwards" });
22
+ await (0, util_1.runAll)([a, b]);
23
+ };
24
+ exports.push = push;
25
+ const cover = async (ctx) => {
26
+ const { dx, dy } = (0, util_1.dirVec)(String(ctx.params.dir ?? "left"), ctx.stageSize.w, ctx.stageSize.h);
27
+ const sBase = ctx.stage.style.transform || "";
28
+ const a = ctx.stage.animate([{ transform: `translate(${dx}px, ${dy}px) ${sBase}` }, { transform: sBase }], { duration: (0, util_1.ms)(ctx), easing: (0, util_1.easing)(ctx), fill: "forwards" });
29
+ await (0, util_1.runAll)([a]);
30
+ };
31
+ exports.cover = cover;
32
+ const uncover = async (ctx) => {
33
+ const { dx, dy } = (0, util_1.dirVec)(String(ctx.params.dir ?? "left"), ctx.stageSize.w, ctx.stageSize.h);
34
+ const gBase = ctx.ghost.style.transform || "";
35
+ const a = ctx.ghost.animate([{ transform: gBase }, { transform: `translate(${-dx}px, ${-dy}px) ${gBase}` }], { duration: (0, util_1.ms)(ctx), easing: (0, util_1.easing)(ctx), fill: "forwards" });
36
+ await (0, util_1.runAll)([a]);
37
+ };
38
+ exports.uncover = uncover;
39
+ const wipe = async (ctx) => {
40
+ const dir = String(ctx.params.dir ?? "left");
41
+ const clipStart = wipeClip(dir, true);
42
+ const clipEnd = wipeClip(dir, false);
43
+ const a = ctx.stage.animate([{ clipPath: clipStart }, { clipPath: clipEnd }], { duration: (0, util_1.ms)(ctx), easing: (0, util_1.easing)(ctx), fill: "forwards" });
44
+ await (0, util_1.runAll)([a], () => {
45
+ ctx.stage.style.clipPath = "";
46
+ });
47
+ };
48
+ exports.wipe = wipe;
49
+ const split = async (ctx) => {
50
+ const motion = (0, geometry_1.splitMotion)(ctx.params.orient, ctx.params.dir);
51
+ if (motion.kind === "meet") {
52
+ await splitMeet(ctx, motion.axis);
53
+ return;
54
+ }
55
+ const a = ctx.stage.animate([{ clipPath: motion.clip }, { clipPath: "inset(0 0 0 0)" }], { duration: (0, util_1.ms)(ctx), easing: (0, util_1.easing)(ctx), fill: "forwards" });
56
+ await (0, util_1.runAll)([a], () => {
57
+ ctx.stage.style.clipPath = "";
58
+ });
59
+ };
60
+ exports.split = split;
61
+ const zoom = async (ctx) => {
62
+ const out = String(ctx.params.dir ?? "in") === "out";
63
+ const sBase = ctx.stage.style.transform || "";
64
+ const startScale = out ? 1.7 : 0.3;
65
+ const a = ctx.stage.animate([
66
+ { transform: `${sBase} scale(${startScale})`, opacity: 0 },
67
+ { transform: sBase, opacity: 1 },
68
+ ], { duration: (0, util_1.ms)(ctx), easing: (0, util_1.easing)(ctx), fill: "forwards" });
69
+ const b = ctx.ghost.animate([{ opacity: 1 }, { opacity: 0 }], { duration: (0, util_1.ms)(ctx), easing: (0, util_1.easing)(ctx), fill: "forwards" });
70
+ await (0, util_1.runAll)([a, b]);
71
+ };
72
+ exports.zoom = zoom;
73
+ const blinds = async (ctx) => {
74
+ const horiz = String(ctx.params.orient ?? "horz") !== "vert";
75
+ return runContentBands(ctx, 6, horiz, "together");
76
+ };
77
+ exports.blinds = blinds;
78
+ const checker = async (ctx) => {
79
+ const horiz = String(ctx.params.orient ?? "horz") !== "vert";
80
+ return runChecker(ctx, horiz);
81
+ };
82
+ exports.checker = checker;
83
+ const randomBar = async (ctx) => {
84
+ const horiz = String(ctx.params.orient ?? "horz") !== "vert";
85
+ return runContentBands(ctx, 10, horiz, "random");
86
+ };
87
+ exports.randomBar = randomBar;
88
+ /** 旧页切成小格,按固定乱序一块块消失。着色器快照失败时用这条。 */
89
+ const dissolve = async (ctx) => {
90
+ const cols = 10;
91
+ const rows = 6;
92
+ const cells = [];
93
+ for (let r = 0; r < rows; r++) {
94
+ for (let c = 0; c < cols; c++) {
95
+ const top = (r / rows) * 100;
96
+ const bottom = ((rows - r - 1) / rows) * 100;
97
+ const left = (c / cols) * 100;
98
+ const right = ((cols - c - 1) / cols) * 100;
99
+ cells.push((0, twin_1.mountTwin)(ctx.ghost, `inset(${top}% ${right}% ${bottom}% ${left}%)`));
100
+ }
101
+ }
102
+ const prev = ctx.ghost.style.visibility;
103
+ ctx.ghost.style.visibility = "hidden";
104
+ const dur = (0, util_1.ms)(ctx);
105
+ const n = cells.length;
106
+ const anims = cells.map((el, i) => {
107
+ const rank = (i * 17 + 5) % n;
108
+ return el.animate([{ opacity: 1 }, { opacity: 0 }], { duration: Math.max(80, dur * 0.22), delay: (rank / n) * dur * 0.78, easing: "linear", fill: "forwards" });
109
+ });
110
+ await (0, util_1.runAll)(anims, () => (0, twin_1.dropTwins)(cells, ctx.ghost, prev));
111
+ };
112
+ exports.dissolve = dissolve;
113
+ const newsflash = async (ctx) => {
114
+ const sBase = ctx.stage.style.transform || "";
115
+ const a = ctx.stage.animate([
116
+ { transform: `${sBase} translate(-100%, -100%) scale(0.1) rotate(-540deg)`, opacity: 0 },
117
+ { transform: sBase, opacity: 1 },
118
+ ], { duration: (0, util_1.ms)(ctx), easing: util_1.STD_EASE, fill: "forwards" });
119
+ await (0, util_1.runAll)([a]);
120
+ };
121
+ exports.newsflash = newsflash;
122
+ async function runWheel(ctx, reverse) {
123
+ const n = (0, geometry_1.wheelSpokes)(ctx.params.pattern);
124
+ const a = ctx.stage.animate([{ clipPath: (0, geometry_1.wheelPolygon)(n, 0, reverse) }, { clipPath: (0, geometry_1.wheelPolygon)(n, 1, reverse) }], { duration: (0, util_1.ms)(ctx), easing: (0, util_1.easing)(ctx), fill: "forwards" });
125
+ await (0, util_1.runAll)([a], () => {
126
+ ctx.stage.style.clipPath = "";
127
+ });
128
+ }
129
+ const wheel = (ctx) => runWheel(ctx, false);
130
+ exports.wheel = wheel;
131
+ const wheelReverse = (ctx) => runWheel(ctx, true);
132
+ exports.wheelReverse = wheelReverse;
133
+ const circle = async (ctx) => {
134
+ const a = ctx.stage.animate([
135
+ { clipPath: "circle(0% at 50% 50%)" },
136
+ { clipPath: "circle(75% at 50% 50%)" },
137
+ ], { duration: (0, util_1.ms)(ctx), easing: (0, util_1.easing)(ctx), fill: "forwards" });
138
+ await (0, util_1.runAll)([a], () => {
139
+ ctx.stage.style.clipPath = "";
140
+ });
141
+ };
142
+ exports.circle = circle;
143
+ const diamond = async (ctx) => {
144
+ const a = ctx.stage.animate([
145
+ { clipPath: "polygon(50% 50%, 50% 50%, 50% 50%, 50% 50%)" },
146
+ { clipPath: "polygon(50% -10%, 110% 50%, 50% 110%, -10% 50%)" },
147
+ ], { duration: (0, util_1.ms)(ctx), easing: (0, util_1.easing)(ctx), fill: "forwards" });
148
+ await (0, util_1.runAll)([a], () => {
149
+ ctx.stage.style.clipPath = "";
150
+ });
151
+ };
152
+ exports.diamond = diamond;
153
+ const plus = async (ctx) => {
154
+ const a = ctx.stage.animate([
155
+ { clipPath: "polygon(50% 50%, 50% 50%, 50% 50%, 50% 50%, 50% 50%, 50% 50%, 50% 50%, 50% 50%, 50% 50%, 50% 50%, 50% 50%, 50% 50%)" },
156
+ { clipPath: "polygon(33% 0%, 67% 0%, 67% 33%, 100% 33%, 100% 67%, 67% 67%, 67% 100%, 33% 100%, 33% 67%, 0% 67%, 0% 33%, 33% 33%)" },
157
+ ], { duration: (0, util_1.ms)(ctx), easing: (0, util_1.easing)(ctx), fill: "forwards" });
158
+ await (0, util_1.runAll)([a], () => {
159
+ ctx.stage.style.clipPath = "";
160
+ });
161
+ };
162
+ exports.plus = plus;
163
+ const random = async (ctx) => {
164
+ const opts = [exports.fade, exports.push, exports.wipe, exports.split, exports.dissolve];
165
+ const pick = opts[Math.floor(Math.random() * opts.length)] ?? exports.fade;
166
+ await pick(ctx);
167
+ };
168
+ exports.random = random;
169
+ const fall = async (ctx) => {
170
+ const sBase = ctx.stage.style.transform || "";
171
+ const gBase = ctx.ghost.style.transform || "";
172
+ const a = ctx.stage.animate([
173
+ { transform: `${sBase} translateY(-100%)`, opacity: 0 },
174
+ { transform: sBase, opacity: 1 },
175
+ ], { duration: (0, util_1.ms)(ctx), easing: "cubic-bezier(0.22, 1, 0.36, 1)", fill: "forwards" });
176
+ const b = ctx.ghost.animate([
177
+ { transform: gBase, opacity: 1 },
178
+ { transform: `${gBase} translateY(100%) rotate(8deg)`, opacity: 0 },
179
+ ], { duration: (0, util_1.ms)(ctx), easing: "cubic-bezier(0.55, 0, 0.55, 0.2)", fill: "forwards" });
180
+ await (0, util_1.runAll)([a, b]);
181
+ };
182
+ exports.fall = fall;
183
+ const reveal = async (ctx) => {
184
+ const toRight = String(ctx.params.dir ?? "left") === "right";
185
+ const gBase = ctx.ghost.style.transform || "";
186
+ const slide = toRight ? "translateX(22%)" : "translateX(-22%)";
187
+ const clipEnd = toRight ? "inset(0 0 0 100%)" : "inset(0 100% 0 0)";
188
+ const a = ctx.ghost.animate([
189
+ { transform: gBase, clipPath: "inset(0 0 0 0)", opacity: 1, filter: "brightness(1)" },
190
+ { transform: `${slide} ${gBase}`, clipPath: clipEnd, opacity: 0, filter: "brightness(0.2)" },
191
+ ], { duration: (0, util_1.ms)(ctx), easing: util_1.STD_EASE, fill: "forwards" });
192
+ await (0, util_1.runAll)([a], () => {
193
+ ctx.ghost.style.clipPath = "";
194
+ });
195
+ };
196
+ exports.reveal = reveal;
197
+ const flash = async (ctx) => {
198
+ const flashEl = ctx.ghost.ownerDocument.createElement("div");
199
+ flashEl.style.cssText = "position:absolute;inset:0;background:#fff;opacity:0;pointer-events:none;z-index:10";
200
+ ctx.ghost.parentElement?.appendChild(flashEl);
201
+ const dur = (0, util_1.ms)(ctx);
202
+ const a = flashEl.animate([{ opacity: 0 }, { opacity: 1, offset: 0.4 }, { opacity: 0 }], { duration: dur, easing: LINEAR_INOUT, fill: "forwards" });
203
+ const b = ctx.ghost.animate([{ opacity: 1 }, { opacity: 0, offset: 0.5 }, { opacity: 0 }], { duration: dur, easing: LINEAR_INOUT, fill: "forwards" });
204
+ await (0, util_1.runAll)([a, b], () => {
205
+ flashEl.remove();
206
+ });
207
+ };
208
+ exports.flash = flash;
209
+ function applyTileMask(el, mask) {
210
+ el.style.webkitMaskImage = mask;
211
+ el.style.maskImage = mask;
212
+ el.style.webkitMaskRepeat = "repeat";
213
+ el.style.maskRepeat = "repeat";
214
+ el.style.webkitMaskPosition = "center";
215
+ el.style.maskPosition = "center";
216
+ }
217
+ function clearTileMask(el) {
218
+ el.style.maskImage = "";
219
+ el.style.webkitMaskImage = "";
220
+ el.style.maskSize = "";
221
+ el.style.webkitMaskSize = "";
222
+ el.style.maskPosition = "";
223
+ el.style.webkitMaskPosition = "";
224
+ el.style.maskRepeat = "";
225
+ el.style.webkitMaskRepeat = "";
226
+ }
227
+ /** 菱形或六边形沿方向扫过,同时旧页闪几下。pattern 来自 OOXML hexagon / diamond。 */
228
+ const glitter = async (ctx) => {
229
+ const pattern = ctx.params.pattern === "hexagon" ? "hexagon" : "diamond";
230
+ const sweep = (0, geometry_1.glitterSweep)(String(ctx.params.dir ?? "left"));
231
+ applyTileMask(ctx.stage, (0, geometry_1.cellMask)(pattern));
232
+ const dur = (0, util_1.ms)(ctx);
233
+ const a = ctx.stage.animate([
234
+ { maskSize: "0% 0%", maskPosition: sweep.from, webkitMaskSize: "0% 0%", webkitMaskPosition: sweep.from },
235
+ { maskSize: "16% 16%", maskPosition: sweep.to, webkitMaskSize: "16% 16%", webkitMaskPosition: sweep.to },
236
+ ], { duration: dur, easing: (0, util_1.easing)(ctx), fill: "forwards" });
237
+ const b = ctx.ghost.animate([
238
+ { opacity: 1, filter: "brightness(1)" },
239
+ { opacity: 0.85, filter: "brightness(2.6)", offset: 0.25 },
240
+ { opacity: 0.45, filter: "brightness(1.15)", offset: 0.55 },
241
+ { opacity: 0, filter: "brightness(2.2)" },
242
+ ], { duration: dur, easing: (0, util_1.easing)(ctx), fill: "forwards" });
243
+ await (0, util_1.runAll)([a, b], () => clearTileMask(ctx.stage));
244
+ };
245
+ exports.glitter = glitter;
246
+ /** 疏六边形从中心铺开,格子之间留缝,不闪。 */
247
+ const honeycomb = async (ctx) => {
248
+ applyTileMask(ctx.stage, (0, geometry_1.cellMask)("honeycomb"));
249
+ const a = ctx.stage.animate([
250
+ { maskSize: "0% 0%", webkitMaskSize: "0% 0%" },
251
+ { maskSize: "34% 34%", webkitMaskSize: "34% 34%" },
252
+ ], { duration: (0, util_1.ms)(ctx), easing: (0, util_1.easing)(ctx), fill: "forwards" });
253
+ await (0, util_1.runAll)([a], () => clearTileMask(ctx.stage));
254
+ };
255
+ exports.honeycomb = honeycomb;
256
+ /** 斜向细条撕开。向外从中心铺开新页,向内让旧页的细条收到中心。 */
257
+ const shred = async (ctx) => {
258
+ const inward = ctx.params.dir === "in";
259
+ const mask = "repeating-linear-gradient(108deg, #000 0 7px, transparent 7px 12px)";
260
+ const host = inward ? ctx.ghost : ctx.stage;
261
+ host.style.webkitMaskImage = mask;
262
+ host.style.maskImage = mask;
263
+ host.style.webkitMaskRepeat = "repeat";
264
+ host.style.maskRepeat = "repeat";
265
+ host.style.webkitMaskPosition = "center";
266
+ host.style.maskPosition = "center";
267
+ const from = inward ? "160% 160%" : "0% 0%";
268
+ const to = inward ? "0% 0%" : "160% 160%";
269
+ const a = host.animate([
270
+ { maskSize: from, webkitMaskSize: from },
271
+ { maskSize: to, webkitMaskSize: to },
272
+ ], { duration: (0, util_1.ms)(ctx), easing: (0, util_1.easing)(ctx), fill: "forwards" });
273
+ await (0, util_1.runAll)([a], () => {
274
+ host.style.maskImage = "";
275
+ host.style.webkitMaskImage = "";
276
+ host.style.maskSize = "";
277
+ host.style.webkitMaskSize = "";
278
+ host.style.maskPosition = "";
279
+ host.style.webkitMaskPosition = "";
280
+ });
281
+ };
282
+ exports.shred = shred;
283
+ /** 旧页切成小块飞散,新页从稍大缩回。 */
284
+ const fracture = async (ctx) => {
285
+ const cols = 4;
286
+ const rows = 3;
287
+ const shards = [];
288
+ for (let r = 0; r < rows; r++) {
289
+ for (let c = 0; c < cols; c++) {
290
+ const top = (r / rows) * 100;
291
+ const bottom = ((rows - r - 1) / rows) * 100;
292
+ const left = (c / cols) * 100;
293
+ const right = ((cols - c - 1) / cols) * 100;
294
+ shards.push((0, twin_1.mountTwin)(ctx.ghost, `inset(${top}% ${right}% ${bottom}% ${left}%)`));
295
+ }
296
+ }
297
+ const prev = ctx.ghost.style.visibility;
298
+ ctx.ghost.style.visibility = "hidden";
299
+ const sBase = ctx.stage.style.transform || "";
300
+ const dur = (0, util_1.ms)(ctx);
301
+ const anims = [
302
+ ctx.stage.animate([
303
+ { transform: `${sBase} scale(1.08)`, opacity: 0 },
304
+ { transform: sBase, opacity: 1 },
305
+ ], { duration: dur, easing: (0, util_1.easing)(ctx), fill: "forwards" }),
306
+ ];
307
+ shards.forEach((el, i) => {
308
+ const c = i % cols;
309
+ const r = Math.floor(i / cols);
310
+ const dx = (c - (cols - 1) / 2) * 36;
311
+ const dy = (r - (rows - 1) / 2) * 28;
312
+ const rot = (i % 2 === 0 ? 1 : -1) * (14 + (i % 5) * 8);
313
+ const base = el.style.transform || "";
314
+ anims.push(el.animate([
315
+ { transform: base, opacity: 1 },
316
+ { transform: `translate(${dx}%, ${dy}%) rotate(${rot}deg) ${base}`, opacity: 0 },
317
+ ], { duration: dur, easing: (0, util_1.easing)(ctx), fill: "forwards" }));
318
+ });
319
+ await (0, util_1.runAll)(anims, () => (0, twin_1.dropTwins)(shards, ctx.ghost, prev));
320
+ };
321
+ exports.fracture = fracture;
322
+ /** 旧页向左掀起,一道高光扫过新页。 */
323
+ const prestige = async (ctx) => {
324
+ const parent = ctx.stage.parentElement;
325
+ const prevPerspective = parent?.style.perspective ?? "";
326
+ const prevStyle = parent?.style.transformStyle ?? "";
327
+ if (parent) {
328
+ parent.style.perspective = "1400px";
329
+ parent.style.transformStyle = "preserve-3d";
330
+ }
331
+ const doc = ctx.stage.ownerDocument;
332
+ const sheen = doc.createElement("div");
333
+ sheen.style.cssText = "position:absolute;inset:0;overflow:hidden;pointer-events:none;z-index:8";
334
+ const bar = doc.createElement("div");
335
+ bar.style.cssText = "position:absolute;top:-8%;bottom:-8%;width:18%;background:linear-gradient(90deg,transparent,rgba(255,255,255,.78),transparent)";
336
+ sheen.appendChild(bar);
337
+ parent?.appendChild(sheen);
338
+ ctx.ghost.style.transformOrigin = "left center";
339
+ ctx.ghost.style.transformStyle = "preserve-3d";
340
+ const gBase = ctx.ghost.style.transform || "";
341
+ const sBase = ctx.stage.style.transform || "";
342
+ const dur = (0, util_1.ms)(ctx);
343
+ const a = ctx.ghost.animate([
344
+ { transform: gBase, opacity: 1, filter: "brightness(1)" },
345
+ { transform: `rotateY(-22deg) scale(0.94) ${gBase}`, opacity: 0, filter: "brightness(1.45)" },
346
+ ], { duration: dur, easing: (0, util_1.easing)(ctx), fill: "forwards" });
347
+ const b = ctx.stage.animate([
348
+ { opacity: 0, transform: `${sBase} scale(1.02)`, filter: "brightness(1.2)" },
349
+ { opacity: 1, transform: sBase, filter: "brightness(1)" },
350
+ ], { duration: dur, easing: (0, util_1.easing)(ctx), fill: "forwards" });
351
+ const c = bar.animate([{ transform: "translateX(-140%)" }, { transform: "translateX(640%)" }], { duration: dur, easing: "linear", fill: "forwards" });
352
+ await (0, util_1.runAll)([a, b, c], () => {
353
+ sheen.remove();
354
+ ctx.ghost.style.transformOrigin = "";
355
+ ctx.ghost.style.transformStyle = "";
356
+ if (parent) {
357
+ parent.style.perspective = prevPerspective;
358
+ parent.style.transformStyle = prevStyle;
359
+ }
360
+ });
361
+ };
362
+ exports.prestige = prestige;
363
+ /** 梳齿交错抽走旧页。水平是上下两排齿,垂直是左右两排齿。 */
364
+ const comb = async (ctx) => {
365
+ const vert = String(ctx.params.orient ?? "horz") === "vert";
366
+ return runContentBands(ctx, 8, !vert, "comb");
367
+ };
368
+ exports.comb = comb;
369
+ /** 斜向宽带从指定角扫过。 */
370
+ const strips = async (ctx) => {
371
+ const [start, mid, end] = (0, geometry_1.stripsClips)(String(ctx.params.dir ?? "bottomRight"));
372
+ const a = ctx.stage.animate([{ clipPath: start }, { clipPath: mid, offset: 0.55 }, { clipPath: end }], { duration: (0, util_1.ms)(ctx), easing: (0, util_1.easing)(ctx), fill: "forwards" });
373
+ await (0, util_1.runAll)([a], () => {
374
+ ctx.stage.style.clipPath = "";
375
+ });
376
+ };
377
+ exports.strips = strips;
378
+ function pieClip(portion) {
379
+ const steps = 24;
380
+ const pts = ["50% 50%"];
381
+ const p = Math.min(1, Math.max(0, portion));
382
+ for (let i = 0; i <= steps; i++) {
383
+ const ang = -Math.PI / 2 + p * (i / steps) * Math.PI * 2;
384
+ const x = 50 + Math.cos(ang) * 80;
385
+ const y = 50 + Math.sin(ang) * 80;
386
+ pts.push(`${x.toFixed(2)}% ${y.toFixed(2)}%`);
387
+ }
388
+ return `polygon(${pts.join(",")})`;
389
+ }
390
+ /** 从中心张开一块扇形,和整圆轮子分开。 */
391
+ const wedge = async (ctx) => {
392
+ const a = ctx.stage.animate([{ clipPath: pieClip(0) }, { clipPath: pieClip(1) }], { duration: (0, util_1.ms)(ctx), easing: (0, util_1.easing)(ctx), fill: "forwards" });
393
+ await (0, util_1.runAll)([a], () => {
394
+ ctx.stage.style.clipPath = "";
395
+ });
396
+ };
397
+ exports.wedge = wedge;
398
+ const LINEAR_INOUT = "cubic-bezier(0.4, 0, 0.6, 1)";
399
+ function wipeClip(dir, start) {
400
+ switch (dir) {
401
+ case "left":
402
+ return start ? "inset(0 0 0 100%)" : "inset(0 0 0 0)";
403
+ case "right":
404
+ return start ? "inset(0 100% 0 0)" : "inset(0 0 0 0)";
405
+ case "up":
406
+ return start ? "inset(100% 0 0 0)" : "inset(0 0 0 0)";
407
+ case "down":
408
+ return start ? "inset(0 0 100% 0)" : "inset(0 0 0 0)";
409
+ default:
410
+ return start ? "inset(0 0 0 100%)" : "inset(0 0 0 0)";
411
+ }
412
+ }
413
+ async function splitMeet(ctx, axis) {
414
+ const left = (0, twin_1.mountTwin)(ctx.stage, axis === "x" ? "inset(0 50% 0 0)" : "inset(0 0 50% 0)");
415
+ const right = (0, twin_1.mountTwin)(ctx.stage, axis === "x" ? "inset(0 0 0 50%)" : "inset(50% 0 0 0)");
416
+ const prev = ctx.stage.style.visibility;
417
+ ctx.stage.style.visibility = "hidden";
418
+ const base = ctx.stage.style.transform || "";
419
+ const fromA = axis === "x" ? "translateX(-50%)" : "translateY(-50%)";
420
+ const fromB = axis === "x" ? "translateX(50%)" : "translateY(50%)";
421
+ const dur = (0, util_1.ms)(ctx);
422
+ const ease = (0, util_1.easing)(ctx);
423
+ await (0, util_1.runAll)([
424
+ left.animate([{ transform: `${fromA} ${base}` }, { transform: base }], { duration: dur, easing: ease, fill: "forwards" }),
425
+ right.animate([{ transform: `${fromB} ${base}` }, { transform: base }], { duration: dur, easing: ease, fill: "forwards" }),
426
+ ], () => (0, twin_1.dropTwins)([left, right], ctx.stage, prev));
427
+ }
428
+ async function runContentBands(ctx, count, horizontal, order) {
429
+ const bands = [];
430
+ for (let i = 0; i < count; i++) {
431
+ const clip = horizontal
432
+ ? `inset(${(i / count) * 100}% 0 ${((count - i - 1) / count) * 100}% 0)`
433
+ : `inset(0 ${((count - i - 1) / count) * 100}% 0 ${(i / count) * 100}%)`;
434
+ bands.push((0, twin_1.mountTwin)(ctx.ghost, clip));
435
+ }
436
+ const prev = ctx.ghost.style.visibility;
437
+ ctx.ghost.style.visibility = "hidden";
438
+ const dur = (0, util_1.ms)(ctx);
439
+ const ease = (0, util_1.easing)(ctx);
440
+ const seq = order === "random" ? shuffle(count) : bands.map((_, i) => i);
441
+ const anims = seq.map((idx, k) => {
442
+ const el = bands[idx];
443
+ const base = el.style.transform || "";
444
+ if (order === "comb") {
445
+ const out = horizontal
446
+ ? idx % 2 === 0 ? "translateY(-100%)" : "translateY(100%)"
447
+ : idx % 2 === 0 ? "translateX(-100%)" : "translateX(100%)";
448
+ return el.animate([{ transform: base }, { transform: `${out} ${base}` }], { duration: dur, easing: ease, fill: "forwards", delay: (idx % 2) * dur * 0.08 });
449
+ }
450
+ const squash = horizontal ? "scaleY(0)" : "scaleX(0)";
451
+ const delay = order === "together" ? 0 : (k / count) * dur * 0.55;
452
+ const duration = order === "together" ? dur : dur * 0.45;
453
+ return el.animate([{ transform: base }, { transform: `${squash} ${base}` }], { duration, easing: ease, fill: "forwards", delay });
454
+ });
455
+ await (0, util_1.runAll)(anims, () => (0, twin_1.dropTwins)(bands, ctx.ghost, prev));
456
+ }
457
+ function shuffle(n) {
458
+ const a = Array.from({ length: n }, (_, i) => i);
459
+ for (let i = a.length - 1; i > 0; i--) {
460
+ const j = Math.floor(Math.random() * (i + 1));
461
+ [a[i], a[j]] = [a[j], a[i]];
462
+ }
463
+ return a;
464
+ }
465
+ async function runChecker(ctx, horizontal) {
466
+ const cols = horizontal ? 8 : 5;
467
+ const rows = horizontal ? 5 : 8;
468
+ const cells = [];
469
+ for (let r = 0; r < rows; r++) {
470
+ for (let c = 0; c < cols; c++) {
471
+ const top = (r / rows) * 100;
472
+ const bottom = ((rows - r - 1) / rows) * 100;
473
+ const left = (c / cols) * 100;
474
+ const right = ((cols - c - 1) / cols) * 100;
475
+ cells.push((0, twin_1.mountTwin)(ctx.ghost, `inset(${top}% ${right}% ${bottom}% ${left}%)`));
476
+ }
477
+ }
478
+ const prev = ctx.ghost.style.visibility;
479
+ ctx.ghost.style.visibility = "hidden";
480
+ const dur = (0, util_1.ms)(ctx);
481
+ const anims = [];
482
+ cells.forEach((el, i) => {
483
+ const even = (Math.floor(i / cols) + (i % cols)) % 2 === 0;
484
+ anims.push(el.animate([{ opacity: 1 }, { opacity: 0 }], { duration: dur * 0.55, fill: "forwards", easing: util_1.STD_EASE, delay: even ? 0 : dur * 0.4 }));
485
+ });
486
+ await (0, util_1.runAll)(anims, () => (0, twin_1.dropTwins)(cells, ctx.ghost, prev));
487
+ }