|
|
@@ -1,243 +0,0 @@
|
|
|
-const loader = document.querySelector(".loader");
|
|
|
-const glow = document.querySelector(".mouse-glow");
|
|
|
-const navToggle = document.querySelector(".nav-toggle");
|
|
|
-const navlinks = document.querySelector(".navlinks");
|
|
|
-const modal = document.querySelector(".trailer-modal");
|
|
|
-const modalVideo = modal?.querySelector("video");
|
|
|
-const endingModal = document.querySelector(".ending-modal");
|
|
|
-const endingModalVideo = endingModal?.querySelector("video");
|
|
|
-const trailerVideo = document.querySelector(".trailer__video");
|
|
|
-const bioModal = document.querySelector(".bio-modal");
|
|
|
-const bioTitle = bioModal?.querySelector("h2");
|
|
|
-const bioText = bioModal?.querySelector(".bio-modal__text");
|
|
|
-
|
|
|
-const biographies = {
|
|
|
- walter: {
|
|
|
- title: "Уолтер Уайт",
|
|
|
- text: "Школьный учитель химии узнает о смертельном диагнозе и начинает варить метамфетамин, чтобы оставить деньги семье. Постепенно мотивация меняется: Уолт уже не просто выживает, а строит империю, уничтожает конкурентов, манипулирует Джесси и становится Хайзенбергом. Его главный вклад в сюжет — превращение обычного человека в центр преступной системы, которую он сам же и разрушает.",
|
|
|
- },
|
|
|
- jesse: {
|
|
|
- title: "Джесси Пинкман",
|
|
|
- text: "Бывший ученик Уолта и его первый партнер в производстве. Джесси проходит путь от мелкого дилера до человека, который видит настоящую цену империи Хайзенберга. Через него сериал показывает совесть, зависимость, вину и попытку вырваться из мира, где взрослые используют его как расходный материал.",
|
|
|
- },
|
|
|
- gus: {
|
|
|
- title: "Густаво Фринг",
|
|
|
- text: "Владелец Los Pollos Hermanos и один из самых опасных игроков наркорынка. Гус дает Уолту промышленный масштаб, лабораторию и систему сбыта, но требует абсолютной дисциплины. Его противостояние с Уолтом превращает сериал из истории выживания в войну интеллектов.",
|
|
|
- },
|
|
|
- saul: {
|
|
|
- title: "Сол Гудман",
|
|
|
- text: "Криминальный адвокат, который легализует хаос вокруг Уолта и Джесси: связи, отмывание денег, фальшивые легенды, исчезновение людей. Сол делает преступную империю управляемой с юридической стороны и постоянно напоминает, что в этом мире у всего есть цена.",
|
|
|
- },
|
|
|
- mike: {
|
|
|
- title: "Майк Эрмантраут",
|
|
|
- text: "Бывший полицейский, fixer и правая рука Гуса. Майк отвечает за порядок, безопасность и грязную работу, но живет по собственному кодексу. Его конфликт с Уолтом показывает разницу между профессиональной преступностью и эго человека, которому всегда нужно побеждать.",
|
|
|
- },
|
|
|
-};
|
|
|
-
|
|
|
-window.addEventListener("load", () => {
|
|
|
- if (loader) setTimeout(() => loader.classList.add("is-hidden"), 900);
|
|
|
-});
|
|
|
-
|
|
|
-document.addEventListener("mousemove", (event) => {
|
|
|
- if (!glow) return;
|
|
|
- glow.style.left = `${event.clientX}px`;
|
|
|
- glow.style.top = `${event.clientY}px`;
|
|
|
-});
|
|
|
-
|
|
|
-if (navToggle && navlinks) {
|
|
|
- navToggle.addEventListener("click", () => {
|
|
|
- navlinks.classList.toggle("is-open");
|
|
|
- document.body.classList.toggle("menu-open", navlinks.classList.contains("is-open"));
|
|
|
- });
|
|
|
-}
|
|
|
-
|
|
|
-document.querySelectorAll(".navlinks a").forEach((link) => {
|
|
|
- link.addEventListener("click", () => {
|
|
|
- navlinks.classList.remove("is-open");
|
|
|
- document.body.classList.remove("menu-open");
|
|
|
- });
|
|
|
-});
|
|
|
-
|
|
|
-const openTrailer = () => {
|
|
|
- if (!modal || !modalVideo) return;
|
|
|
- modal.classList.add("is-open");
|
|
|
- modal.setAttribute("aria-hidden", "false");
|
|
|
- modalVideo.currentTime = 0;
|
|
|
- modalVideo.play();
|
|
|
-};
|
|
|
-
|
|
|
-const closeTrailer = () => {
|
|
|
- if (!modal || !modalVideo) return;
|
|
|
- modal.classList.remove("is-open");
|
|
|
- modal.setAttribute("aria-hidden", "true");
|
|
|
- modalVideo.pause();
|
|
|
-};
|
|
|
-
|
|
|
-const openEnding = () => {
|
|
|
- if (!endingModal || !endingModalVideo) return;
|
|
|
- endingModal.classList.add("is-open");
|
|
|
- endingModal.setAttribute("aria-hidden", "false");
|
|
|
- endingModalVideo.currentTime = 0;
|
|
|
- endingModalVideo.play();
|
|
|
-};
|
|
|
-
|
|
|
-const closeEnding = () => {
|
|
|
- if (!endingModal || !endingModalVideo) return;
|
|
|
- endingModal.classList.remove("is-open");
|
|
|
- endingModal.setAttribute("aria-hidden", "true");
|
|
|
- endingModalVideo.pause();
|
|
|
-};
|
|
|
-
|
|
|
-const openBio = (key) => {
|
|
|
- const bio = biographies[key];
|
|
|
- if (!bio || !bioModal || !bioTitle || !bioText) return;
|
|
|
- bioTitle.textContent = bio.title;
|
|
|
- bioText.textContent = bio.text;
|
|
|
- bioModal.classList.add("is-open");
|
|
|
- bioModal.setAttribute("aria-hidden", "false");
|
|
|
-};
|
|
|
-
|
|
|
-const closeBio = () => {
|
|
|
- if (!bioModal) return;
|
|
|
- bioModal.classList.remove("is-open");
|
|
|
- bioModal.setAttribute("aria-hidden", "true");
|
|
|
-};
|
|
|
-
|
|
|
-document.querySelectorAll("[data-open-trailer], [data-play-trailer]").forEach((button) => {
|
|
|
- button.addEventListener("click", openTrailer);
|
|
|
-});
|
|
|
-
|
|
|
-document.querySelectorAll("[data-open-ending]").forEach((button) => {
|
|
|
- button.addEventListener("click", openEnding);
|
|
|
-});
|
|
|
-
|
|
|
-modal?.querySelector(".modal-close")?.addEventListener("click", closeTrailer);
|
|
|
-document.querySelector(".ending-close")?.addEventListener("click", closeEnding);
|
|
|
-document.querySelector(".bio-close")?.addEventListener("click", closeBio);
|
|
|
-modal?.addEventListener("click", (event) => {
|
|
|
- if (event.target === modal) closeTrailer();
|
|
|
-});
|
|
|
-endingModal?.addEventListener("click", (event) => {
|
|
|
- if (event.target === endingModal) closeEnding();
|
|
|
-});
|
|
|
-bioModal?.addEventListener("click", (event) => {
|
|
|
- if (event.target === bioModal) closeBio();
|
|
|
-});
|
|
|
-
|
|
|
-document.querySelectorAll("[data-bio]").forEach((button) => {
|
|
|
- button.addEventListener("click", () => openBio(button.dataset.bio));
|
|
|
-});
|
|
|
-
|
|
|
-document.addEventListener("keydown", (event) => {
|
|
|
- if (event.key === "Escape" && modal?.classList.contains("is-open")) closeTrailer();
|
|
|
- if (event.key === "Escape" && endingModal?.classList.contains("is-open")) closeEnding();
|
|
|
- if (event.key === "Escape" && bioModal?.classList.contains("is-open")) closeBio();
|
|
|
-});
|
|
|
-
|
|
|
-if (window.Lenis) {
|
|
|
- const lenis = new Lenis({ lerp: 0.08, wheelMultiplier: 0.85 });
|
|
|
- const raf = (time) => {
|
|
|
- lenis.raf(time);
|
|
|
- requestAnimationFrame(raf);
|
|
|
- };
|
|
|
- requestAnimationFrame(raf);
|
|
|
-}
|
|
|
-
|
|
|
-if (window.Swiper) {
|
|
|
- new Swiper(".character-swiper", {
|
|
|
- slidesPerView: 1.08,
|
|
|
- spaceBetween: 18,
|
|
|
- centeredSlides: false,
|
|
|
- pagination: { el: ".swiper-pagination", clickable: true },
|
|
|
- breakpoints: {
|
|
|
- 760: { slidesPerView: 2.15, spaceBetween: 22 },
|
|
|
- 1120: { slidesPerView: 3.18, spaceBetween: 26 },
|
|
|
- },
|
|
|
- });
|
|
|
-}
|
|
|
-
|
|
|
-if (window.gsap) {
|
|
|
- gsap.registerPlugin(ScrollTrigger);
|
|
|
-
|
|
|
- gsap.from(".reveal", {
|
|
|
- y: 42,
|
|
|
- opacity: 0,
|
|
|
- duration: 1.15,
|
|
|
- stagger: 0.16,
|
|
|
- ease: "power3.out",
|
|
|
- delay: 0.55,
|
|
|
- });
|
|
|
-
|
|
|
- gsap.utils.toArray(".section__head, .glass-card, .support-card, .timeline__item, .dea__grid, .ending__caption, .legacy__image, .legacy__copy").forEach((element) => {
|
|
|
- gsap.from(element, {
|
|
|
- scrollTrigger: { trigger: element, start: "top 82%" },
|
|
|
- y: 70,
|
|
|
- opacity: 0,
|
|
|
- duration: 0.95,
|
|
|
- ease: "power3.out",
|
|
|
- });
|
|
|
- });
|
|
|
-
|
|
|
- gsap.to(".hero__video", {
|
|
|
- scrollTrigger: { trigger: ".hero", start: "top top", end: "bottom top", scrub: true },
|
|
|
- scale: 1.18,
|
|
|
- yPercent: 10,
|
|
|
- });
|
|
|
-
|
|
|
- gsap.to(".trailer__video", {
|
|
|
- scrollTrigger: {
|
|
|
- trigger: ".trailer",
|
|
|
- start: "top 65%",
|
|
|
- onEnter: () => trailerVideo?.play(),
|
|
|
- onLeaveBack: () => trailerVideo?.pause(),
|
|
|
- },
|
|
|
- });
|
|
|
-
|
|
|
- gsap.utils.toArray(".formula").forEach((formula, index) => {
|
|
|
- gsap.to(formula, {
|
|
|
- scrollTrigger: { trigger: ".lab", start: "top bottom", end: "bottom top", scrub: true },
|
|
|
- xPercent: index % 2 ? -24 : 24,
|
|
|
- yPercent: index % 2 ? 40 : -35,
|
|
|
- });
|
|
|
- });
|
|
|
-}
|
|
|
-
|
|
|
-const canvas = document.getElementById("particles");
|
|
|
-const ctx = canvas.getContext("2d");
|
|
|
-let particles = [];
|
|
|
-
|
|
|
-function resizeCanvas() {
|
|
|
- canvas.width = window.innerWidth;
|
|
|
- canvas.height = window.innerHeight;
|
|
|
- particles = Array.from({ length: Math.min(90, Math.floor(window.innerWidth / 16)) }, () => ({
|
|
|
- x: Math.random() * canvas.width,
|
|
|
- y: Math.random() * canvas.height,
|
|
|
- r: Math.random() * 1.7 + 0.35,
|
|
|
- vx: (Math.random() - 0.5) * 0.25,
|
|
|
- vy: Math.random() * -0.35 - 0.05,
|
|
|
- a: Math.random() * 0.5 + 0.15,
|
|
|
- }));
|
|
|
-}
|
|
|
-
|
|
|
-function drawParticles() {
|
|
|
- ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
|
- particles.forEach((particle) => {
|
|
|
- particle.x += particle.vx;
|
|
|
- particle.y += particle.vy;
|
|
|
- if (particle.y < -10) particle.y = canvas.height + 10;
|
|
|
- if (particle.x < -10) particle.x = canvas.width + 10;
|
|
|
- if (particle.x > canvas.width + 10) particle.x = -10;
|
|
|
-
|
|
|
- ctx.beginPath();
|
|
|
- ctx.arc(particle.x, particle.y, particle.r, 0, Math.PI * 2);
|
|
|
- ctx.fillStyle = `rgba(215, 255, 54, ${particle.a})`;
|
|
|
- ctx.shadowBlur = 12;
|
|
|
- ctx.shadowColor = "rgba(21, 255, 128, 0.8)";
|
|
|
- ctx.fill();
|
|
|
- });
|
|
|
- requestAnimationFrame(drawParticles);
|
|
|
-}
|
|
|
-
|
|
|
-resizeCanvas();
|
|
|
-drawParticles();
|
|
|
-window.addEventListener("resize", resizeCanvas);
|