PageSourceSearch

https://d3ep.com/js/sticker-engine/sticker-animations.js?v=1790389512

js d3ep.com collected 2026-09-26 02:25:28 UTC 32,474 bytes, 1,496 lines download raw bytes

1const px = (value) => `${value}px`;
2
3const transform = (scale, rotation) =>
4    `scale(${scale}) rotate(${rotation}deg)`;
5
6const transformXY = (scaleX, scaleY, rotation) =>
7    `scale(${scaleX}, ${scaleY}) rotate(${rotation}deg)`;
8
9const baseValues = (instance) => ({
10    rotation: instance.engine.rotation ?? 0,
11    scale: instance.engine.scale ?? 1,
12    opacity: instance.engine.opacity ?? 1
13});
14
15const animationOptions = (instance, fallbackEasing) => ({
16    duration: instance.engine.duration,
17    easing:
18        fallbackEasing === undefined
19            ? instance.engine.easing
20            : instance.engine.easing ?? fallbackEasing
21});
22
23StickerEngine.registerAnimation("drive", function(instance)
24{
25    const resolve = (position) =>
26        StickerEngine.resolveEnvironmentPosition(position, instance);
27
28    const origin = instance.engine.origin;
29    const destination = instance.engine.destination;
30
31    let frames;
32
33    if (
34        origin.startsWith("enter-") &&
35        destination.startsWith("exit-")
36    )
37    {
38        const edgeStart = resolve("edge-" + origin.substring(6));
39        const edgeEnd = resolve("edge-" + destination.substring(5));
40
41        const horizontal =
42            Math.abs(edgeEnd.x - edgeStart.x) >=
43            Math.abs(edgeEnd.y - edgeStart.y);
44
45        const outsideStart = { ...edgeStart };
46        const outsideEnd = { ...edgeEnd };
47
48        if (horizontal)
49        {
50            if (edgeStart.x < edgeEnd.x)
51            {
52                outsideStart.x = -instance.engine.displayWidth;
53                outsideEnd.x = window.innerWidth;
54            }
55            else
56            {
57                outsideStart.x = window.innerWidth;
58                outsideEnd.x = -instance.engine.displayWidth;
59            }
60        }
61        else if (edgeStart.y < edgeEnd.y)
62        {
63            outsideStart.y = -instance.engine.displayHeight;
64            outsideEnd.y = window.innerHeight;
65        }
66        else
67        {
68            outsideStart.y = window.innerHeight;
69            outsideEnd.y = -instance.engine.displayHeight;
70        }
71
72        frames = [
73            {
74                left: px(outsideStart.x),
75                top: px(outsideStart.y)
76            },
77            {
78                left: px(edgeStart.x),
79                top: px(edgeStart.y),
80                offset: 0.15
81            },
82            {
83                left: px(edgeEnd.x),
84                top: px(edgeEnd.y),
85                offset: 0.85
86            },
87            {
88                left: px(outsideEnd.x),
89                top: px(outsideEnd.y)
90            }
91        ];
92    }
93    else
94    {
95        frames = [
96            {
97                left: px(instance.origin.x),
98                top: px(instance.origin.y)
99            },
100            {
101                left: px(instance.destination.x),
102                top: px(instance.destination.y)
103            }
104        ];
105    }
106
107    return {
108        frames,
109        options: animationOptions(instance)
110    };
111});
112
113StickerEngine.registerAnimation("launch", function(instance)
114{
115    const start = instance.origin;
116    const end = instance.destination;
117
118    const dx = end.x - start.x;
119    const dy = end.y - start.y;
120
121    const curve = Math.min(
122        Math.max(Math.hypot(dx, dy) * 0.25, 40),
123        120
124    );
125
126    const control = {
127        x: (start.x + end.x) / 2,
128        y: (start.y + end.y) / 2
129    };
130
131    const length = Math.hypot(dx, dy) || 1;
132
133    control.x += (-dy / length) * curve;
134    control.y += (dx / length) * curve;
135
136    const frames = [];
137    const STEPS = 10;
138
139    for (let i = 0; i <= STEPS; i++)
140    {
141        const t = i / STEPS;
142        const u = 1 - t;
143
144        frames.push({
145            left: px(
146                (u * u * start.x) +
147                (2 * u * t * control.x) +
148                (t * t * end.x)
149            ),
150            top: px(
151                (u * u * start.y) +
152                (2 * u * t * control.y) +
153                (t * t * end.y)
154            ),
155            offset: t
156        });
157    }
158
159    return {
160        frames,
161        options: animationOptions(instance)
162    };
163});
164
165function createThrowAnimation(spinRotation = 0)
166{
167    return function(instance)
168    {
169        const start = instance.origin;
170        const end = instance.destination;
171
172        const dx = end.x - start.x;
173        const dy = end.y - start.y;
174        const distance = Math.hypot(dx, dy) || 1;
175
176        const perpendicularX = -dy / distance;
177        const perpendicularY = dx / distance;
178
179        const frames = [];
180        const STEPS = 30;
181
182        const base = baseValues(instance);
183
184        const MAX_WOBBLE = 8 + (Math.random() * 3);
185        const MAX_ROTATION = 8 + (Math.random() * 4);
186        const WOBBLES = 1.75 + (Math.random() * 0.75);
187        const PHASE = Math.random() * Math.PI * 2;
188
189        for (let i = 0; i <= STEPS; i++)
190        {
191            const t = i / STEPS;
192            const x = start.x + (dx * t);
193            const y = start.y + (dy * t);
194            const angle = (t * Math.PI * 2 * WOBBLES) + PHASE;
195            const strength = Math.pow(t, 1.8);
196
197            const wobble =
198                Math.sin(angle) *
199                MAX_WOBBLE *
200                strength;
201
202            const rotation =
203                base.rotation +
204                (spinRotation * t) +
205                (Math.cos(angle) * MAX_ROTATION * strength);
206
207            const scale =
208                base.scale -
209                ((base.scale - 0.05) * Math.pow(t, 1.8));
210
211            const opacity =
212                t < 0.8
213                    ? base.opacity
214                    : base.opacity * (1 - ((t - 0.8) / 0.2));
215
216            frames.push({
217                left: px(x + (perpendicularX * wobble)),
218                top: px(y + (perpendicularY * wobble)),
219                transform: transform(scale, rotation),
220                opacity,
221                offset: t
222            });
223        }
224
225        return {
226            frames,
227            options: animationOptions(instance, "linear")
228        };
229    };
230}
231
232StickerEngine.registerAnimation(
233    "throw",
234    createThrowAnimation()
235);
236
237// Keep throwtate at two complete turns (720°).
238StickerEngine.registerAnimation(
239    "throwtate",
240    createThrowAnimation(720)
241);
242
243StickerEngine.registerAnimation("drop", function(instance)
244{
245    const X_MARGIN = 200;
246
247    const start = {
248        x: instance.origin.x,
249        y: instance.origin.y
250    };
251
252    if (instance.engine.origin === "random-top")
253    {
254        start.x =
255            X_MARGIN +
256            (Math.random() * (window.innerWidth - (X_MARGIN * 2)));
257    }
258
259    const frames = [];
260    const STEPS = 40;
261    const base = baseValues(instance);
262
263    const BOUNCES = 5;
264    const DECAY = 2.4;
265    const SQUASH = 0.08;
266    const FLOOR_Y = (window.innerHeight - instance.engine.displayHeight) / 2;
267    const DROP_HEIGHT = FLOOR_Y - start.y;
268    const FALL_TIME = 0.25;
269    const FADE_TIME = 0.85;
270
271    for (let i = 0; i <= STEPS; i++)
272    {
273        const t = i / STEPS;
274
275        let y;
276        let impact = 0;
277        let rotation = base.rotation;
278
279        if (t < FALL_TIME)
280        {
281            const p = t / FALL_TIME;
282
283            y =
284                start.y +
285                (DROP_HEIGHT * Math.pow(p, 2));
286        }
287        else
288        {
289            const p = Math.min(
290                (t - FALL_TIME) /
291                (FADE_TIME - FALL_TIME),
292                1
293            );
294
295            const bounce =
296                Math.abs(
297                    Math.sin(p * Math.PI * BOUNCES)
298                ) *
299                (DROP_HEIGHT * 0.35) *
300                Math.pow(1 - p, DECAY);
301
302            y = FLOOR_Y - bounce;
303
304            impact =
305                Math.pow(
306                    Math.abs(
307                        Math.sin(p * Math.PI * BOUNCES)
308                    ),
309                    6
310                ) *
311                Math.pow(1 - p, 1.5);
312
313            rotation =
314                base.rotation +
315                (
316                    Math.sin(p * Math.PI * BOUNCES) *
317                    4 *
318                    Math.pow(1 - p, 1.5)
319                );
320        }
321
322        const scaleX =
323            base.scale *
324            (1 + (impact * SQUASH));
325
326        const scaleY =
327            base.scale *
328            (1 - (impact * SQUASH));
329
330        const opacity =
331            t < FADE_TIME
332                ? base.opacity
333                : base.opacity *
334                    (1 - ((t - FADE_TIME) / (1 - FADE_TIME)));
335
336        frames.push({
337            left: px(start.x),
338            top: px(y),
339            transform: transformXY(scaleX, scaleY, rotation),
340            opacity,
341            offset: t
342        });
343    }
344
345    return {
346        frames,
347        options: animationOptions(instance, "linear")
348    };
349});
350
351StickerEngine.registerAnimation("fall", function(instance)
352{
353    const X_MARGIN = 200;
354
355    const height =
356        instance.height ??
357        instance.element.height ??
358        128;
359
360    const x =
361        X_MARGIN +
362        (Math.random() * (window.innerWidth - (X_MARGIN * 2)));
363
364    const start = {
365        x,
366        y: -(height + 100)
367    };
368
369    const end = {
370        x,
371        y:
372            window.innerHeight -
373            StickerEngine.environment.bottomInset -
374            height
375    };
376
377    const frames = [];
378    const STEPS = 40;
379    const base = baseValues(instance);
380
381    const DROP_HEIGHT = end.y - start.y;
382    const BOUNCES = 6;
383    const DECAY = 2.2;
384    const SQUASH = 0.12;
385    const FALL_TIME = 0.65;
386    const FADE_TIME = 0.90;
387
388    for (let i = 0; i <= STEPS; i++)
389    {
390        const t = i / STEPS;
391
392        let y;
393        let impact = 0;
394        let rotation = base.rotation;
395
396        if (t < FALL_TIME)
397        {
398            const p = t / FALL_TIME;
399
400            y =
401                start.y +
402                (DROP_HEIGHT * Math.pow(p, 2.4));
403        }
404        else
405        {
406            const p = Math.min(
407                (t - FALL_TIME) /
408                (FADE_TIME - FALL_TIME),
409                1
410            );
411
412            const bounce =
413                Math.abs(
414                    Math.sin(p * Math.PI * BOUNCES)
415                ) *
416                (DROP_HEIGHT * 0.18) *
417                Math.pow(1 - p, DECAY);
418
419            y = end.y - bounce;
420
421            impact =
422                Math.pow(
423                    Math.abs(
424                        Math.sin(p * Math.PI * BOUNCES)
425                    ),
426                    6
427                ) *
428                Math.pow(1 - p, 1.4);
429
430            rotation =
431                base.rotation +
432                (
433                    Math.sin(p * Math.PI * BOUNCES) *
434                    8 *
435                    Math.pow(1 - p, 1.4)
436                );
437        }
438
439        const scaleX =
440            base.scale *
441            (1 + (impact * SQUASH));
442
443        const scaleY =
444            base.scale *
445            (1 - (impact * SQUASH));
446
447        const opacity =
448            t < FADE_TIME
449                ? base.opacity
450                : base.opacity *
451                    (1 - ((t - FADE_TIME) / (1 - FADE_TIME)));
452
453        frames.push({
454            left: px(start.x),
455            top: px(y),
456            transform: transformXY(scaleX, scaleY, rotation),
457            opacity,
458            offset: t
459        });
460    }
461
462    return {
463        frames,
464        options: animationOptions(instance, "linear")
465    };
466});
467
468StickerEngine.registerAnimation("bounce", function(instance)
469{
470    const resolve = (position) =>
471        StickerEngine.resolveEnvironmentPosition(position, instance);
472
473    let start = instance.origin;
474    let end = instance.destination;
475
476    const origin = instance.engine.origin;
477    const destination = instance.engine.destination;
478
479    if (
480        origin.startsWith("edge-") &&
481        destination.startsWith("edge-")
482    )
483    {
484        start = resolve(origin);
485        end = resolve(destination);
486    }
487
488    const dx = end.x - start.x;
489    const dy = end.y - start.y;
490
491    const frames = [];
492    const STEPS = 40;
493    const base = baseValues(instance);
494
495    const BOUNCES = 6;
496    const BOUNCE_HEIGHT = 200;
497    const DECAY = 1.5;
498    const SQUASH = 0.08;
499    const MOTION_END = 0.99;
500    const FADE_START = 0.99;
501
502    for (let i = 0; i <= STEPS; i++)
503    {
504        const t = i / STEPS;
505
506        const motion = Math.min(t, MOTION_END);
507        const progress = motion / MOTION_END;
508
509        const x =
510            start.x +
511            (dx * progress);
512
513        const groundY =
514            start.y +
515            (dy * progress);
516
517        const bounce =
518            Math.abs(
519                Math.sin(progress * Math.PI * BOUNCES)
520            ) *
521            BOUNCE_HEIGHT *
522            Math.pow(1 - progress, DECAY);
523
524        const y = groundY - bounce;
525
526        const impact =
527            Math.pow(
528                Math.abs(
529                    Math.sin(progress * Math.PI * BOUNCES)
530                ),
531                8
532            ) *
533            Math.pow(1 - progress, 1.5);
534
535        const scaleX =
536            base.scale *
537            (1 + (impact * SQUASH));
538
539        const scaleY =
540            base.scale *
541            (1 - (impact * SQUASH));
542
543        const rotation =
544            base.rotation +
545            (
546                Math.sin(progress * Math.PI * BOUNCES) *
547                10 *
548                Math.pow(1 - progress, 1.5)
549            );
550
551        const opacity =
552            t < FADE_START
553                ? base.opacity
554                : base.opacity *
555                    (1 - ((t - FADE_START) / (1 - FADE_START)));
556
557        frames.push({
558            left: px(x),
559            top: px(y),
560            transform: transformXY(scaleX, scaleY, rotation),
561            opacity,
562            offset: t
563        });
564    }
565
566    return {
567        frames,
568        options: animationOptions(instance, "linear")
569    };
570});
571
572StickerEngine.registerAnimation("fly", function(instance)
573{
574    const width =
575        instance.engine.displayWidth;
576
577    const height =
578        instance.engine.displayHeight;
579
580    const origin =
581        instance.engine.origin ??
582        "outside-left";
583
584    const leftToRight =
585        origin.includes("left");
586
587    const centreY =
588        (window.innerHeight - height) / 2;
589
590    const start = {
591        x:
592            leftToRight
593                ? -width
594                : window.innerWidth + width,
595        y: centreY
596    };
597
598    const end = {
599        x:
600            leftToRight
601                ? window.innerWidth + width
602                : -width,
603        y: centreY
604    };
605
606    const dx = end.x - start.x;
607
608    const frames = [];
609    const STEPS = 40;
610    const base = baseValues(instance);
611
612    const AMPLITUDE =
613        15 +
614        (Math.random() * 20);
615
616    const WAVES =
617        2 +
618        (Math.random() * 2);
619
620    const PHASE =
621        Math.random() *
622        Math.PI *
623        2;
624
625    const BANK =
626        5 +
627        (Math.random() * 4);
628
629    for (let i = 0; i <= STEPS; i++)
630    {
631        const t = i / STEPS;
632
633        const x =
634            start.x +
635            (dx * t);
636
637        const angle =
638            (t * Math.PI * 2 * WAVES) +
639            PHASE;
640
641        const bob =
642            Math.sin(angle) *
643            AMPLITUDE;
644
645        const rotation =
646            base.rotation +
647            (Math.cos(angle) * BANK);
648
649        frames.push({
650            left: px(x),
651            top: px(start.y + bob),
652            transform: transform(base.scale, rotation),
653            opacity: base.opacity,
654            offset: t
655        });
656    }
657
658    return {
659        frames,
660        options: {
661            duration: instance.engine.duration,
662            easing: "linear"
663        }
664    };
665});
666
667StickerEngine.registerAnimation("zoom-out", function(instance)
668{
669    const centre =
670        StickerEngine.resolvePosition(
671            "centre",
672            instance
673        );
674
675    const MARGIN = 200;
676
677    const start = {
678        x:
679            (
680                Math.random() *
681                (window.innerWidth + (MARGIN * 2))
682            ) -
683            MARGIN,
684
685        y:
686            (
687                Math.random() *
688                (window.innerHeight + (MARGIN * 2))
689            ) -
690            MARGIN
691    };
692
693    const frames = [];
694    const STEPS = 40;
695    const base = baseValues(instance);
696
697    const START_SCALE = 1.8;
698    const END_SCALE = 0.1;
699
700    const SWAY =
701        10 +
702        (Math.random() * 8);
703
704    const MAX_ROTATION =
705        8 +
706        (Math.random() * 6);
707
708    const WAVES =
709        1.5 +
710        (Math.random() * 0.5);
711
712    const PHASE =
713        Math.random() *
714        Math.PI *
715        2;
716
717    const FADE_START = 0.8;
718
719    for (let i = 0; i <= STEPS; i++)
720    {
721        const t = i / STEPS;
722
723        const angle =
724            (t * Math.PI * 2 * WAVES) +
725            PHASE;
726
727        const strength =
728            1 - t;
729
730        const sway =
731            Math.sin(angle) *
732            SWAY *
733            strength;
734
735        const rotation =
736            base.rotation +
737            (
738                Math.cos(angle) *
739                MAX_ROTATION *
740                strength
741            );
742
743        const x =
744            start.x +
745            ((centre.x - start.x) * t);
746
747        const y =
748            start.y +
749            ((centre.y - start.y) * t);
750
751        const scale =
752            START_SCALE +
753            ((END_SCALE - START_SCALE) * t);
754
755        const opacity =
756            t < FADE_START
757                ? base.opacity
758                : base.opacity *
759                    (1 - ((t - FADE_START) / (1 - FADE_START)));
760
761        frames.push({
762            left: px(x + sway),
763            top: px(y),
764            transform: transform(scale, rotation),
765            opacity,
766            offset: t
767        });
768    }
769
770    return {
771        frames,
772        options:
773            animationOptions(
774                instance,
775                "ease-in-out"
776            )
777    };
778});
779
780StickerEngine.registerAnimation("zoom-in", function(instance)
781{
782    const centre =
783        StickerEngine.resolvePosition(
784            "centre",
785            instance
786        );
787
788    const focus = {
789        x:
790            centre.x +
791            ((Math.random() - 0.5) * 300),
792
793        y:
794            centre.y +
795            ((Math.random() - 0.5) * 220)
796    };
797
798    const frames = [];
799    const STEPS = 40;
800    const base = baseValues(instance);
801
802    // API scale remains the reference size.
803    const START_SCALE =
804        base.scale *
805        0.1;
806
807    const END_SCALE =
808        base.scale *
809        1.2;
810
811    const SWAY =
812        18 +
813        (Math.random() * 10);
814
815    const MAX_ROTATION =
816        14 +
817        (Math.random() * 8);
818
819    const WAVES =
820        1.5 +
821        (Math.random() * 0.5);
822
823    const PHASE =
824        Math.random() *
825        Math.PI *
826        2;
827
828    const FADE_END = 0.2;
829
830    for (let i = 0; i <= STEPS; i++)
831    {
832        const t = i / STEPS;
833
834        const angle =
835            (t * Math.PI * 2 * WAVES) +
836            PHASE;
837
838        const strength =
839            1 -
840            Math.pow(t, 2);
841
842        const sway =
843            Math.sin(angle) *
844            SWAY *
845            strength;
846
847        const rotation =
848            base.rotation +
849            (
850                Math.cos(angle) *
851                MAX_ROTATION *
852                strength
853            );
854
855        const zoom =
856            1 -
857            Math.pow(1 - t, 4);
858
859        let scale =
860            START_SCALE +
861            (
862                (END_SCALE - START_SCALE) *
863                zoom
864            );
865
866        if (t > 0.82)
867        {
868            const p =
869                (t - 0.82) /
870                0.18;
871
872            scale +=
873                Math.sin(p * Math.PI * 4) *
874                (1 - p) *
875                (base.scale * 0.22);
876        }
877
878        const opacity =
879            t < FADE_END
880                ? base.opacity * (t / FADE_END)
881                : base.opacity;
882
883        frames.push({
884            left: px(focus.x + sway),
885            top: px(focus.y),
886            transform: transform(scale, rotation),
887            opacity,
888            offset: t
889        });
890    }
891
892    return {
893        frames,
894
895        collision(instance)
896        {
897            const rect =
898                instance.element.getBoundingClientRect();
899
900            return {
901                type: "circle",
902
903                x:
904                    rect.left +
905                    (rect.width / 2),
906
907                y:
908                    rect.top +
909                    (rect.height / 2),
910
911                radius: 24
912            };
913        },
914
915        collidesWith(other)
916        {
917            return other.engine.animation !== "zoom-in";
918        },
919
920        options:
921            animationOptions(
922                instance,
923                "ease-in-out"
924            )
925    };
926});
927
928StickerEngine.registerAnimation("shake", function(instance)
929{
930    const centre =
931        StickerEngine.resolvePosition(
932            "centre",
933            instance
934        );
935
936    const width =
937        instance.engine.displayWidth;
938
939    const height =
940        instance.engine.displayHeight;
941
942    const start = {
943        x:
944            Math.random() *
945            Math.max(
946                window.innerWidth - width,
947                0
948            ),
949
950        y:
951            Math.random() *
952            Math.max(
953                window.innerHeight - height,
954                0
955            )
956    };
957
958    const frames = [];
959    const STEPS = 60;
960    const base = baseValues(instance);
961
962    const ARRIVE_END = 0.28;
963    const SHAKE_END = 0.82;
964    const POP_PEAK = 0.90;
965
966    const START_SCALE = 0.1;
967    const SHAKE_DISTANCE = 30;
968    const SHAKE_ROTATION = 9;
969    const SHAKE_FREQUENCY = 12;
970    const POP_SCALE = base.scale * 1.5;
971    const END_SCALE = 0.05;
972
973    for (let i = 0; i <= STEPS; i++)
974    {
975        const t = i / STEPS;
976
977        let x;
978        let y;
979        let scale;
980        let rotation;
981        let opacity = base.opacity;
982
983        if (t < ARRIVE_END)
984        {
985            const p =
986                t /
987                ARRIVE_END;
988
989            const movement =
990                1 -
991                Math.pow(1 - p, 4);
992
993            x =
994                start.x +
995                ((centre.x - start.x) * movement);
996
997            y =
998                start.y +
999                ((centre.y - start.y) * movement);
1000
1001            scale =
1002                START_SCALE +
1003                ((base.scale - START_SCALE) * movement);
1004
1005            rotation =
1006                base.rotation +
1007                (
1008                    Math.sin(p * Math.PI * 2) *
1009                    12 *
1010                    (1 - p)
1011                );
1012        }
1013        else if (t < SHAKE_END)
1014        {
1015            const p =
1016                (t - ARRIVE_END) /
1017                (SHAKE_END - ARRIVE_END);
1018
1019            const angle =
1020                p *
1021                Math.PI *
1022                2 *
1023                SHAKE_FREQUENCY;
1024
1025            const strength =
1026                p < 0.8
1027                    ? 1
1028                    : 1 - ((p - 0.8) / 0.2);
1029
1030            x =
1031                centre.x +
1032                (
1033                    Math.sin(angle) *
1034                    SHAKE_DISTANCE *
1035                    strength
1036                );
1037
1038            y =
1039                centre.y +
1040                (
1041                    Math.sin(angle * 0.5) *
1042                    3 *
1043                    strength
1044                );
1045
1046            scale =
1047                base.scale +
1048                (
1049                    Math.abs(Math.sin(angle)) *
1050                    0.035 *
1051                    strength
1052                );
1053
1054            rotation =
1055                base.rotation +
1056                (
1057                    Math.cos(angle) *
1058                    SHAKE_ROTATION *
1059                    strength
1060                );
1061        }
1062        else if (t < POP_PEAK)
1063        {
1064            const p =
1065                (t - SHAKE_END) /
1066                (POP_PEAK - SHAKE_END);
1067
1068            const eased =
1069                1 -
1070                Math.pow(1 - p, 3);
1071
1072            x = centre.x;
1073            y = centre.y;
1074
1075            scale =
1076                base.scale +
1077                (
1078                    (POP_SCALE - base.scale) *
1079                    eased
1080                );
1081
1082            rotation =
1083                base.rotation +
1084                (p * 6);
1085        }
1086        else
1087        {
1088            const p =
1089                (t - POP_PEAK) /
1090                (1 - POP_PEAK);
1091
1092            x = centre.x;
1093            y = centre.y;
1094
1095            scale =
1096                POP_SCALE +
1097                (
1098                    (END_SCALE - POP_SCALE) *
1099                    Math.pow(p, 2)
1100                );
1101
1102            rotation =
1103                base.rotation +
1104                6 +
1105                (p * 10);
1106
1107            opacity =
1108                base.opacity *
1109                (1 - p);
1110        }
1111
1112        frames.push({
1113            left: px(x),
1114            top: px(y),
1115            transform: transform(scale, rotation),
1116            opacity,
1117            offset: t
1118        });
1119    }
1120
1121    return {
1122        frames,
1123
1124        options: {
1125            duration: instance.engine.duration,
1126            easing: "linear"
1127        }
1128    };
1129});
1130
1131StickerEngine.registerAnimation("swirl", function(instance)
1132{
1133    const centre =
1134        StickerEngine.resolvePosition(
1135            "centre",
1136            instance
1137        );
1138
1139    const width =
1140        instance.engine.displayWidth;
1141
1142    const height =
1143        instance.engine.displayHeight;
1144
1145    const sides = [
1146        "top",
1147        "right",
1148        "bottom",
1149        "left"
1150    ];
1151
1152    const entry =
1153        sides[
1154            Math.floor(
1155                Math.random() *
1156                sides.length
1157            )
1158        ];
1159
1160    const opposite = {
1161        top: "bottom",
1162        right: "left",
1163        bottom: "top",
1164        left: "right"
1165    };
1166
1167    const getOutsidePoint = (side) =>
1168    {
1169        switch (side)
1170        {
1171            case "top":
1172                return {
1173                    x: centre.x,
1174                    y: -height
1175                };
1176
1177            case "right":
1178                return {
1179                    x: window.innerWidth + width,
1180                    y: centre.y
1181                };
1182
1183            case "bottom":
1184                return {
1185                    x: centre.x,
1186                    y: window.innerHeight + height
1187                };
1188
1189            case "left":
1190            default:
1191                return {
1192                    x: -width,
1193                    y: centre.y
1194                };
1195        }
1196    };
1197
1198    const start =
1199        getOutsidePoint(entry);
1200
1201    const end =
1202        getOutsidePoint(opposite[entry]);
1203
1204    const frames = [];
1205    const STEPS = 60;
1206    const base = baseValues(instance);
1207
1208    const ARRIVE_END = 0.30;
1209    const SPIN_END = 0.70;
1210
1211    const spinDirection =
1212        Math.random() < 0.5
1213            ? 1
1214            : -1;
1215
1216    for (let i = 0; i <= STEPS; i++)
1217    {
1218        const t = i / STEPS;
1219
1220        let x;
1221        let y;
1222        let rotation;
1223
1224        if (t < ARRIVE_END)
1225        {
1226            const p =
1227                t /
1228                ARRIVE_END;
1229
1230            const movement =
1231                1 -
1232                Math.pow(1 - p, 4);
1233
1234            x =
1235                start.x +
1236                ((centre.x - start.x) * movement);
1237
1238            y =
1239                start.y +
1240                ((centre.y - start.y) * movement);
1241
1242            rotation =
1243                base.rotation;
1244        }
1245        else if (t < SPIN_END)
1246        {
1247            const p =
1248                (t - ARRIVE_END) /
1249                (SPIN_END - ARRIVE_END);
1250
1251            x = centre.x;
1252            y = centre.y;
1253
1254            rotation =
1255                base.rotation +
1256                (
1257                    p *
1258                    720 *
1259                    spinDirection
1260                );
1261        }
1262        else
1263        {
1264            const p =
1265                (t - SPIN_END) /
1266                (1 - SPIN_END);
1267
1268            const movement =
1269                Math.pow(p, 3);
1270
1271            x =
1272                centre.x +
1273                ((end.x - centre.x) * movement);
1274
1275            y =
1276                centre.y +
1277                ((end.y - centre.y) * movement);
1278
1279            rotation =
1280                base.rotation +
1281                (720 * spinDirection);
1282        }
1283
1284        frames.push({
1285            left: px(x),
1286            top: px(y),
1287            transform: transform(base.scale, rotation),
1288            opacity: base.opacity,
1289            offset: t
1290        });
1291    }
1292
1293    return {
1294        frames,
1295
1296        options: {
1297            duration: instance.engine.duration,
1298            easing: "linear"
1299        }
1300    };
1301});
1302
1303StickerEngine.registerAnimation("cyclone", function(instance)
1304{
1305    const centre =
1306        StickerEngine.resolvePosition(
1307            "centre",
1308            instance
1309        );
1310
1311    const frames = [];
1312    const STEPS = 80;
1313    const base = baseValues(instance);
1314
1315    const viewportRadius =
1316        Math.hypot(
1317            window.innerWidth,
1318            window.innerHeight
1319        ) /
1320        2;
1321
1322    const stickerRadius =
1323        Math.max(
1324            instance.engine.displayWidth,
1325            instance.engine.displayHeight
1326        );
1327
1328    const START_RADIUS =
1329        viewportRadius +
1330        stickerRadius +
1331        100;
1332
1333    const START_ANGLE =
1334        Math.random() *
1335        Math.PI *
1336        2;
1337
1338    const DIRECTION =
1339        Math.random() < 0.5
1340            ? 1
1341            : -1;
1342
1343    const ORBITS =
1344        3.5 +
1345        (Math.random() * 1.5);
1346
1347    const SPIRAL_END = 0.82;
1348    const POP_END = 0.88;
1349    const RECOIL_END = 0.94;
1350
1351    const POP_SCALE =
1352        base.scale *
1353        1.9;
1354
1355    const RECOIL_SCALE =
1356        base.scale *
1357        1.35;
1358
1359    const END_SCALE =
1360        base.scale *
1361        0.02;
1362
1363    for (let i = 0; i <= STEPS; i++)
1364    {
1365        const t = i / STEPS;
1366
1367        let x;
1368        let y;
1369        let scale;
1370        let opacity = base.opacity;
1371
1372        if (t < SPIRAL_END)
1373        {
1374            const p =
1375                t /
1376                SPIRAL_END;
1377
1378            const radius =
1379                START_RADIUS *
1380                Math.pow(1 - p, 1.25);
1381
1382            const angle =
1383                START_ANGLE +
1384                (
1385                    p *
1386                    Math.PI *
1387                    2 *
1388                    ORBITS *
1389                    DIRECTION
1390                );
1391
1392            x =
1393                centre.x +
1394                (Math.cos(angle) * radius);
1395
1396            y =
1397                centre.y +
1398                (Math.sin(angle) * radius);
1399
1400            scale =
1401                base.scale *
1402                (
1403                    1 +
1404                    (
1405                        Math.sin(
1406                            p *
1407                            Math.PI *
1408                            ORBITS *
1409                            2
1410                        ) *
1411                        0.025 *
1412                        p
1413                    )
1414                );
1415        }
1416        else if (t < POP_END)
1417        {
1418            const p =
1419                (t - SPIRAL_END) /
1420                (POP_END - SPIRAL_END);
1421
1422            const movement =
1423                1 -
1424                Math.pow(1 - p, 4);
1425
1426            x = centre.x;
1427            y = centre.y;
1428
1429            scale =
1430                base.scale +
1431                (
1432                    (POP_SCALE - base.scale) *
1433                    movement
1434                );
1435        }
1436        else if (t < RECOIL_END)
1437        {
1438            const p =
1439                (t - POP_END) /
1440                (RECOIL_END - POP_END);
1441
1442            const movement =
1443                p *
1444                p *
1445                (3 - (2 * p));
1446
1447            x = centre.x;
1448            y = centre.y;
1449
1450            scale =
1451                POP_SCALE +
1452                (
1453                    (RECOIL_SCALE - POP_SCALE) *
1454                    movement
1455                );
1456        }
1457        else
1458        {
1459            const p =
1460                (t - RECOIL_END) /
1461                (1 - RECOIL_END);
1462
1463            x = centre.x;
1464            y = centre.y;
1465
1466            scale =
1467                RECOIL_SCALE +
1468                (
1469                    (END_SCALE - RECOIL_SCALE) *
1470                    Math.pow(p, 1.8)
1471                );
1472
1473            opacity =
1474                base.opacity *
1475                (1 - Math.pow(p, 1.2));
1476        }
1477
1478        // Cyclone movement spirals, but the sticker image does not rotate.
1479        frames.push({
1480            left: px(x),
1481            top: px(y),
1482            transform: transform(scale, base.rotation),
1483            opacity,
1484            offset: t
1485        });
1486    }
1487
1488    return {
1489        frames,
1490
1491        options: {
1492            duration: instance.engine.duration,
1493            easing: "linear"
1494        }
1495    };
1496});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.