Skip to main content
The mission page showcases Adosa Group’s values, philosophy, and commitment to clients through an immersive scroll experience.

Route

  • Path: /mision (Spanish) or /en/mision (English)
  • File: src/pages/[...lang]/mision.astro
  • Type: Static page with scroll-driven animations

Page Structure

Hero Section

Video background hero with mission statement:
src/pages/[...lang]/mision.astro
<GlobalBackground
  heroMedia="/video/mision.mp4"
  sectionBackgrounds={["/images/bg/pared.jpg", "/images/bg/playa.jpg"]}
/>

<section id="hero-mision" class="section-fullscreen hero-section">
  <div class="container hero-container">
    <div class="hero-text-wrapper">
      <div class="line-mask">
        <h1 class="hero-title">{HERO_TITLE}</h1>
        <h2 class="hero-subtitle">{HERO_SUBTITLE}</h2>
      </div>
    </div>
  </div>
</section>
Content:
const HERO_TITLE = isEn ? "Our Mission" : "Nuestra Misión";
const HERO_SUBTITLE = isEn
  ? "Creating lasting relationships and success stories"
  : "Creando relaciones duraderas e historias de éxito";

ScrollGallery Section

Interactive scroll-driven gallery with text and images:
<section
  class="section-fullscreen content-section bubble-wrapper"
  data-has-scroll-gallery
>
  <ScrollGallery slides={SLIDES} textPosition="left" />
</section>

Slides Data

const SLIDES = [
  {
    text: isEn
      ? "<h2>Values that last</h2><p>We build relationships based on trust and long-term commitment.</p>"
      : "<h2>Valores que perduran</h2><p>Construimos relaciones basadas en la confianza y el compromiso a largo plazo.</p>",
    image: "/images/bg/calle-oficina.jpg",
    imageAlt: isEn ? "Business values" : "Valores empresariales",
  },
  {
    text: isEn
      ? "<h2>A different real estate agency</h2><p>When we say we are different, it's because we aspire to be your allies, your interests become ours.</p>"
      : "<h2>Una inmobiliaria diferente</h2><p>Cuando nos referimos a que somos diferentes, es porque aspiramos a ser tus aliados, tus intereses se transforman en los nuestros.</p>",
    image: "/images/bg/complex.jpg",
    imageAlt: isEn ? "Excellence" : "Excelencia",
  },
  {
    text: isEn
      ? "<h2>Authentic commitment</h2><p>Your success is our success, often that means being honest even when the truth is not what you expect.</p>"
      : "<h2>Compromiso auténtico</h2><p>Tu éxito es nuestro éxito, muchas veces eso implica ser honestos incluso cuando la verdad no es la que esperas.</p>",
    image: "/images/bg/paseo.jpg",
    imageAlt: isEn ? "Commitment" : "Compromiso",
  },
  {
    text: isEn
      ? "<h2>Adosa Family</h2><p>Because of this, clients who decide to trust us become part of the family. A relationship that lasts through the years.</p>"
      : "<h2>Familia Adosa</h2><p>Debido a esto, los clientes que deciden confiar en nosotros, se convierten en parte de la familia. Una relación que perdura en los años.</p>",
    image: "/images/bg/comida.jpg",
    imageAlt: isEn ? "Family" : "Familia",
  },
];

ScrollGallery Component

The ScrollGallery component creates a horizontal scrolling experience:
src/components/ScrollGallery.astro
<div class="scroll-gallery" data-text-position={textPosition}>
  <div class="gallery-track">
    {
      slides.map((slide, index) => (
        <div class="gallery-panel">
          <div class="panel-text" set:html={slide.text} />
          <div class="panel-image">
            <img src={slide.image} alt={slide.imageAlt} />
          </div>
        </div>
      ))
    }
  </div>
</div>
Scroll Animation:
gsap.to(".gallery-track", {
  x: () => -(trackWidth - windowWidth),
  ease: "none",
  scrollTrigger: {
    trigger: ".scroll-gallery",
    start: "top top",
    end: () => `+=${trackWidth}`,
    scrub: 1,
    pin: true,
  },
});

Final Content Section

Static section with text and image:
<section class="section-fullscreen content-section bubble-wrapper">
  <div class="container content-grid vertical-layout">
    <div class="text-col">
      <h2 class="section-title text-reveal">
        {isEn ? "A DIFFERENT Agency." : "Una Agencia DIFERENTE."}
      </h2>
      <h2 class="section-subtitle text-reveal" data-delay="0.3">
        {
          isEn
            ? "We forge trust relationships,"
            : "Forjamos relaciones de confianza,"
        }
      </h2>
      <h2 class="section-subtitle text-reveal" data-delay="0.6">
        {
          isEn
            ? "leaving a positive footprint in the world."
            : "dejando una huella positiva en el mundo."
        }
      </h2>
    </div>

    <div class="images-col">
      <div class="image-wrapper parallax-img-container">
        <img
          src="/images/bg/oficina.jpg"
          alt="Valores"
          class="parallax-img"
        />
      </div>
    </div>
  </div>
</section>

Vertical Layout

Stacks text above image:
.content-grid.vertical-layout {
  grid-template-columns: 1fr;
  gap: 3rem;
  justify-items: start;
}

.content-grid.vertical-layout .images-col {
  height: 80vh;
  width: 100%;
}

.content-grid.vertical-layout .text-col {
  text-align: left;
  width: 100%;
  max-width: 900px;
}

Animations

Hero Animation

function playHeroAnimation() {
  const tl = gsap.timeline({
    defaults: { ease: "power3.out", duration: 1.2 },
  });
  tl.to(".hero-title", { y: 0, opacity: 1, delay: 0.2 })
    .to(".hero-subtitle", { y: 0, opacity: 1, delay: 0 }, "<0.15");
}

if ((window as any).__pageReady) {
  playHeroAnimation();
} else {
  window.addEventListener("page-ready", playHeroAnimation, { once: true });
}

Bubble Effect (Desktop)

Sections scale up as they enter viewport:
const mm = gsap.matchMedia();
mm.add("(min-width: 769px)", () => {
  const sections = document.querySelectorAll(".bubble-wrapper");

  sections.forEach((section, index) => {
    gsap.fromTo(
      section,
      { scale: 0.92, borderRadius: "40px" },
      {
        scale: 1,
        borderRadius: "0px",
        duration: 1,
        ease: "power2.out",
        scrollTrigger: {
          trigger: section,
          start: "top 90%",
          end: "center center",
          scrub: 1,
        },
      }
    );

    // Background change
    ScrollTrigger.create({
      trigger: section,
      start: "top center",
      end: "bottom center",
      onEnter: () => window.dispatchEvent(
        new CustomEvent("bg-change", { detail: { index } })
      ),
      onEnterBack: () => window.dispatchEvent(
        new CustomEvent("bg-change", { detail: { index } })
      ),
    });
  });
});

Parallax Images

const parallaxImgs = document.querySelectorAll(".parallax-img");
parallaxImgs.forEach((img) => {
  gsap.fromTo(
    img,
    { y: "-15%" },
    {
      y: "15%",
      ease: "none",
      scrollTrigger: {
        trigger: img.parentElement,
        start: "top bottom",
        end: "bottom top",
        scrub: true,
      },
    }
  );
});

Text Reveal

Text elements fade in and slide up:
import { createTextSwipeAnimation } from "../../utils/textSwipeAnimation";

const contentSections = document.querySelectorAll(".bubble-wrapper");
contentSections.forEach((section, index) => {
  const texts = section.querySelectorAll(".text-reveal");
  if (texts.length > 0) {
    section.classList.add(`reveal-section-${index}`);
    createTextSwipeAnimation(
      `.reveal-section-${index} .text-reveal`,
      section
    );
  }
});

Hero ScrollTrigger

Returns to hero video when scrolling back:
ScrollTrigger.create({
  trigger: ".hero-section",
  start: "top center",
  end: "bottom center",
  onEnter: () => {
    window.dispatchEvent(
      new CustomEvent("bg-change", { detail: { index: null } })
    );
  },
  onEnterBack: () => {
    window.dispatchEvent(
      new CustomEvent("bg-change", { detail: { index: null } })
    );
  },
});

Styling

Section Layout

.section-fullscreen {
  min-height: 90vh;
  width: 100vw;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  padding: 4rem;
  box-sizing: border-box;
}

.hero-section {
  align-items: flex-end;
  padding-bottom: 6rem;
}

Bubble Wrapper

.bubble-wrapper {
  will-change: transform, border-radius;
  overflow: hidden;
  background-color: var(--color-1);
}

Content Grid

.content-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6rem;
  align-items: center;
  width: 100%;
}

.text-col {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.section-title {
  font-family: var(--font-heading);
  font-size: 3.5rem;
  color: var(--color-4);
  line-height: 1.2;
  margin: 0;
  font-weight: 400;
}

.section-subtitle {
  font-size: 2.5rem;
  font-weight: 400;
  color: var(--color-4);
}

Parallax Container

.images-col {
  position: relative;
  height: 80vh;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.image-wrapper {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
}

.parallax-img {
  width: 100%;
  height: 140%;
  object-fit: cover;
  position: absolute;
  top: -20%;
  left: 0;
}

Mobile Responsiveness

@media (max-width: 768px) {
  /* Exclude ScrollGallery sections from height reduction */
  .section-fullscreen.content-section:not([data-has-scroll-gallery]) {
    min-height: auto;
    padding: 1.5rem;
    padding-bottom: 3rem;
  }

  .hero-title {
    font-size: 2.5rem;
  }
  
  .content-grid {
    grid-template-columns: 1fr;
    gap: 3rem;
    text-align: left;
  }
  
  .section-title {
    font-size: 2rem;
  }

  .content-grid.vertical-layout .images-col {
    position: static;
    height: auto;
    display: block;
    margin-top: 2rem;
  }

  .image-wrapper {
    position: relative;
    width: 100%;
    height: 300px;
  }
}

Background Management

The page uses GlobalBackground to manage video and image backgrounds that change as user scrolls:
<GlobalBackground
  heroMedia="/video/mision.mp4"
  sectionBackgrounds={[
    "/images/bg/pared.jpg",
    "/images/bg/playa.jpg"
  ]}
/>
Backgrounds are triggered via bg-change custom events coordinated with ScrollTrigger.

Key Features

  • Video hero with animated text
  • Horizontal scroll gallery with 4 value statements
  • Bubble effect on section entry (desktop)
  • Parallax image movement
  • Text reveal animations
  • Dynamic background changes
  • Fully responsive design
  • ScrollGallery.astro - Horizontal scroll gallery
  • GlobalBackground.astro - Video/image background manager
  • EmptySection.astro - Spacing section
  • Navigation.astro - Top navigation
  • Footer.astro - Site footer
  • src/utils/textSwipeAnimation.ts - Text reveal animation helper
  • src/i18n/utils.ts - Internationalization utilities

Build docs developers (and LLMs) love