PageSourceSearch

https://www.discourse.org/a/js/homepage-hero-animation.js?1790174693181339485

js discourse.org collected 2026-09-24 06:55:05 UTC 2,563 bytes, 103 lines download raw bytes

1document.addEventListener("DOMContentLoaded", function () {
2  if (typeof gsap === "undefined") {
3    // eslint-disable-next-line no-console
4    console.warn("GSAP not loaded");
5    return;
6  }
7
8  const scrollTriggerAvailable =
9    typeof ScrollTriggerUtils !== "undefined" && ScrollTriggerUtils.register();
10
11  const heroSection = document.querySelector(".hero-section");
12  if (!heroSection) {
13    return;
14  }
15
16  const mainIcons = document.querySelectorAll(".hero-icons .floating-icon");
17  const heroIconsBg = document.querySelector(".hero-icons-bg");
18  const backgroundIcons = document.querySelectorAll(
19    ".hero-icons-bg .floating-icon"
20  );
21
22  // Foreground icons
23  if (mainIcons.length > 0) {
24    mainIcons.forEach((icon) => {
25      gsap.set(icon, {
26        transformOrigin: "center center",
27        scale: 0.8,
28        opacity: 0,
29      });
30
31      gsap.to(icon, {
32        opacity: 1,
33        scale: 1,
34        duration: 2,
35        ease: "back.out(1.2)",
36        delay: Math.random() * 0.4,
37        force3D: true,
38      });
39    });
40  }
41
42  // Scroll parallax for foreground icons
43  if (scrollTriggerAvailable && mainIcons.length > 0) {
44    mainIcons.forEach((icon, index) => {
45      const speeds = [0.2, 0.3, 0.4, 0.4, 0.3, 0.2];
46      const speed = speeds[index % speeds.length];
47
48      gsap.to(icon, {
49        y: -300 * speed,
50        ease: "none",
51        scrollTrigger: {
52          trigger: heroSection,
53          start: "top top",
54          end: "bottom top",
55          scrub: 1,
56          invalidateOnRefresh: true,
57        },
58      });
59    });
60  }
61
62  // Background icons
63  if (heroIconsBg && backgroundIcons.length > 0) {
64    gsap.to(heroIconsBg, {
65      opacity: 1,
66      duration: 1.5,
67      ease: "power2.out",
68      delay: 0.3,
69    });
70
71    if (scrollTriggerAvailable) {
72      backgroundIcons.forEach((icon, index) => {
73        const backgroundSpeeds = [0.1, 0.15, 0.12, 0.18, 0.13, 0.16];
74        const speed = backgroundSpeeds[index % backgroundSpeeds.length];
75
76        gsap.to(icon, {
77          y: -200 * speed,
78          ease: "none",
79          scrollTrigger: {
80            trigger: heroSection,
81            start: "top top",
82            end: "bottom top",
83            scrub: 1,
84            invalidateOnRefresh: true,
85          },
86        });
87      });
88    }
89  }
90
91  // Logos entrance
92  const logoItems = document.querySelectorAll(".logos-wrapper .logo-item");
93  if (logoItems.length > 0) {
94    gsap.to(logoItems, {
95      opacity: 1,
96      y: 0,
97      duration: 1.2,
98      ease: "power2.out",
99      stagger: 0.1,
100      delay: 0,
101    });
102  }
103});

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.