# Locomotive Smooth Scroll Setup

> Locomotive Scroll v5 with GSAP ScrollTrigger, progress chrome, and parallax reveals — a polished smooth-scroll page scaffold.

**Definition:** Locomotive Smooth Scroll Setup is a scroll UI animation from collections.html. It is built with HTML, CSS, JavaScript, and GSAP, ships with a live preview, and is free to copy into personal and commercial projects.

## Facts
- Category: Scroll
- Stack: HTML, CSS, JavaScript, and GSAP
- Added: 2026-08-06
- Canonical page: https://html.bosconvertpro.com/collection/locomotive-smooth-scroll-setup
- Full-page preview: https://html.bosconvertpro.com/collection/locomotive-smooth-scroll-setup/full
- Live demo: https://html.bosconvertpro.com/demos/locomotive-smooth-scroll-setup/index.html
- Markdown mirror: https://html.bosconvertpro.com/collection/locomotive-smooth-scroll-setup/index.md
- License: https://html.bosconvertpro.com/terms

## How to use
1. Open https://html.bosconvertpro.com/collection/locomotive-smooth-scroll-setup/full to preview the animation in full screen.
2. Copy index.html, styles.css, and script.js from the code tabs on https://html.bosconvertpro.com/collection/locomotive-smooth-scroll-setup.
3. Paste the files into your project and adjust timing, easing, and content as needed.

## FAQ
### What is Locomotive Smooth Scroll Setup?

Locomotive Smooth Scroll Setup is a scroll UI animation from collections.html. Locomotive Scroll v5 with GSAP ScrollTrigger, progress chrome, and parallax reveals — a polished smooth-scroll page scaffold.

### What is Locomotive Smooth Scroll Setup built with?

Locomotive Smooth Scroll Setup is built with HTML, CSS, JavaScript, and GSAP. The source for every file is shown on the animation page and can be copied straight into your project.

### How do I use Locomotive Smooth Scroll Setup in my project?

Open the animation page (https://html.bosconvertpro.com/collection/locomotive-smooth-scroll-setup), preview it live, then copy index.html, styles.css, and script.js from the code tabs. Paste the files into your project and adjust timing, easing, and content as needed. A standalone demo runs at https://html.bosconvertpro.com/demos/locomotive-smooth-scroll-setup/index.html.

### Is Locomotive Smooth Scroll Setup free to use?

Yes. The Locomotive Smooth Scroll Setup demo code may be used in personal and commercial projects. You may not resell or redistribute the collection itself as a competing template pack. Full terms: https://html.bosconvertpro.com/terms.

## Source — index.html
````html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Atelier — Interior Design</title>
    <meta
      name="description"
      content="Interior design studio. Spaces shaped with calm, light, and material."
    />
    <link rel="preconnect" href="https://fonts.googleapis.com" />
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
    <link
      href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,400;0,500;1,400;1,500&family=Outfit:wght@300;400;500&display=swap"
      rel="stylesheet"
    />
    <link
      rel="stylesheet"
      href="https://cdn.jsdelivr.net/npm/lenis@1.2.3/dist/lenis.css"
    />
    <link rel="stylesheet" href="styles.css" />
  </head>
  <body>
    <header class="chrome">
      <span class="chrome__mark">Atelier</span>
      <span class="chrome__tag">Interior</span>
      <span class="chrome__progress" aria-hidden="true">
        <span class="chrome__progress-fill" data-progress-fill></span>
      </span>
    </header>

    <main class="page">
      <!-- Hero -->
      <section class="panel panel--hero">
        <div class="hero-copy" data-reveal>
          <p class="eyebrow">Studio</p>
          <h1 class="hero-title">
            Spaces<br />
            <em>with soul</em>
          </h1>
        </div>
        <figure class="hero-media" data-reveal>
          <img
            src="https://images.unsplash.com/photo-1618221195710-dd6b41faaea6?auto=format&fit=crop&w=1400&q=85"
            alt="Calm modern living room with soft neutrals"
            data-scroll
            data-scroll-speed="-0.08"
            width="900"
            height="1100"
            loading="eager"
          />
        </figure>
      </section>

      <!-- Full bleed room -->
      <section class="panel panel--bleed">
        <div class="bleed">
          <img
            class="bleed__img"
            src="https://images.unsplash.com/photo-1600210492486-724fe5c67fb0?auto=format&fit=crop&w=2000&q=85"
            alt="Sunlit interior with refined furniture"
            data-scroll
            data-scroll-speed="-0.45"
            width="2000"
            height="1200"
            loading="lazy"
          />
          <p class="bleed__caption" data-reveal>Residence · Natural light</p>
        </div>
      </section>

      <!-- Materials / rooms trio -->
      <section class="panel panel--grid">
        <div class="grid grid--3">
          <figure class="frame" data-scroll data-scroll-speed="0.1" data-reveal>
            <img
              src="https://images.unsplash.com/photo-1616486338812-3dadae4b4ace?auto=format&fit=crop&w=900&q=85"
              alt="Textiles and warm material palette"
              data-scroll
              data-scroll-speed="-0.06"
              width="700"
              height="900"
              loading="lazy"
            />
            <figcaption class="frame__cap">Materials</figcaption>
          </figure>
          <figure class="frame frame--mid" data-reveal>
            <img
              src="https://images.unsplash.com/photo-1586023492125-27b2c045efd7?auto=format&fit=crop&w=1000&q=85"
              alt="Minimal seating arrangement"
              data-scroll
              data-scroll-speed="-0.1"
              width="800"
              height="700"
              loading="lazy"
            />
            <figcaption class="frame__cap">Living</figcaption>
          </figure>
          <figure
            class="frame"
            data-scroll
            data-scroll-speed="-0.1"
            data-scroll-offset="-10%, -10%"
            data-reveal
          >
            <img
              src="https://images.unsplash.com/photo-1600566753190-17f0baa2a6c3?auto=format&fit=crop&w=900&q=85"
              alt="Architectural detail in concrete and wood"
              data-scroll
              data-scroll-speed="-0.05"
              width="700"
              height="900"
              loading="lazy"
            />
            <figcaption class="frame__cap">Detail</figcaption>
          </figure>
        </div>
      </section>

      <!-- Pair: kitchen + bedroom -->
      <section class="panel panel--pair">
        <div class="grid grid--2">
          <figure
            class="frame frame--wide"
            data-scroll
            data-scroll-speed="0.08"
            data-reveal
          >
            <img
              src="https://images.unsplash.com/photo-1600585154340-be6161a56a0c?auto=format&fit=crop&w=1400&q=85"
              alt="Open kitchen with natural finishes"
              data-scroll
              data-scroll-speed="-0.07"
              width="1200"
              height="800"
              loading="lazy"
            />
            <figcaption class="frame__cap">Kitchen</figcaption>
          </figure>
          <figure
            class="frame frame--wide"
            data-scroll
            data-scroll-speed="-0.08"
            data-reveal
          >
            <img
              src="https://images.unsplash.com/photo-1616594039964-ae9021a400a0?auto=format&fit=crop&w=1400&q=85"
              alt="Serene bedroom with soft bedding"
              data-scroll
              data-scroll-speed="-0.07"
              width="1200"
              height="800"
              loading="lazy"
            />
            <figcaption class="frame__cap">Bedroom</figcaption>
          </figure>
        </div>
      </section>

      <!-- Word mark -->
      <section class="panel panel--letters">
        <p class="letter-row" aria-label="Form">
          <span data-scroll data-scroll-speed="-0.28" data-scroll-offset="-25%, -25%">F</span>
          <span data-scroll data-scroll-speed="-0.16" data-scroll-offset="-15%, -15%">O</span>
          <span data-scroll data-scroll-speed="-0.06" data-scroll-offset="-5%, -5%">R</span>
          <span data-scroll data-scroll-speed="0.06">M</span>
        </p>
      </section>

      <!-- Mosaic: entry + bath + lounge -->
      <section class="panel panel--mosaic">
        <div class="mosaic">
          <figure
            class="frame frame--tall"
            data-scroll
            data-scroll-speed="0.06"
            data-reveal
          >
            <img
              src="https://images.unsplash.com/photo-1600607687920-4e2a09cf159d?auto=format&fit=crop&w=900&q=85"
              alt="Bright modern living space with soft neutrals"
              data-scroll
              data-scroll-speed="-0.08"
              width="700"
              height="1000"
              loading="lazy"
            />
            <figcaption class="frame__cap">Entry</figcaption>
          </figure>
          <div class="mosaic__stack">
            <figure class="frame" data-reveal>
              <img
                src="https://images.unsplash.com/photo-1552321554-5fefe8c9ef14?auto=format&fit=crop&w=1000&q=85"
                alt="Spa-like bathroom with stone and wood"
                data-scroll
                data-scroll-speed="-0.1"
                width="900"
                height="600"
                loading="lazy"
              />
              <figcaption class="frame__cap">Bath</figcaption>
            </figure>
            <figure
              class="frame"
              data-scroll
              data-scroll-speed="-0.05"
              data-reveal
            >
              <img
                src="https://images.unsplash.com/photo-1600566753086-00f18fb6b3ea?auto=format&fit=crop&w=1000&q=85"
                alt="Lounge corner with soft seating"
                data-scroll
                data-scroll-speed="-0.06"
                width="900"
                height="600"
                loading="lazy"
              />
              <figcaption class="frame__cap">Lounge</figcaption>
            </figure>
          </div>
        </div>
      </section>

      <!-- Close -->
      <section class="panel panel--close">
        <div class="close" data-reveal>
          <p class="close-line">Designed to be lived in.</p>
          <a class="close-link" href="mailto:hello@atelier.studio">Inquire</a>
        </div>
      </section>
    </main>

    <script src="https://cdn.jsdelivr.net/npm/locomotive-scroll@beta/bundled/locomotive-scroll.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/gsap.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/ScrollTrigger.min.js"></script>
    <script src="script.js"></script>
  </body>
</html>
````

## Source — styles.css
````css
/* ==========================================================================
   Atelier — Interior Design · Smooth Scroll Showcase
   Warm minimal studio aesthetic
   ========================================================================== */

:root {
  --bg: #f4f1ec;
  --bg-deep: #ebe6de;
  --ink: #1c1915;
  --ink-soft: rgba(28, 25, 21, 0.5);
  --ink-faint: rgba(28, 25, 21, 0.28);
  --line: rgba(28, 25, 21, 0.08);
  --accent: #8b7355;
  --accent-soft: #a89278;
  --pad: clamp(1.25rem, 4vw, 3rem);
  --max: 1180px;
  --radius: 2px;
  --font: "Outfit", system-ui, sans-serif;
  --serif: "Cormorant Garamond", Georgia, serif;
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  scroll-behavior: initial;
  scrollbar-width: none;
}

html,
body {
  margin: 0;
  min-height: 100%;
}

body {
  color: var(--ink);
  background: var(--bg);
  font-family: var(--font);
  font-size: 16px;
  font-weight: 400;
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: clip;
}

body::-webkit-scrollbar {
  display: none;
}

img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border: 0;
  -webkit-user-drag: none;
  user-select: none;
}

h1,
p,
figure,
figcaption {
  margin: 0;
}

a {
  color: inherit;
  text-decoration: none;
}

/* ---------- Chrome ---------- */

.chrome {
  position: fixed;
  inset: 0 0 auto;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 3.5rem;
  padding: 0 var(--pad);
  pointer-events: none;
}

.chrome__mark {
  font-family: var(--serif);
  font-size: 1.35rem;
  font-weight: 500;
  letter-spacing: 0.01em;
  line-height: 1;
}

.chrome__tag {
  font-size: 0.6875rem;
  font-weight: 400;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.chrome__progress {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
  background: var(--line);
}

.chrome__progress-fill {
  display: block;
  width: 0%;
  height: 100%;
  background: var(--accent);
  will-change: width;
}

/* ---------- Page ---------- */

.page {
  position: relative;
}

.panel {
  position: relative;
  width: 100%;
  padding: var(--pad);
}

/* ---------- Frames ---------- */

.frame {
  position: relative;
  overflow: hidden;
  border-radius: var(--radius);
  background: var(--bg-deep);
  aspect-ratio: 4 / 5;
}

.frame img {
  position: absolute;
  inset: -8% 0;
  width: 100%;
  height: 116%;
  filter: saturate(0.92) contrast(1.02);
}

.frame__cap {
  position: absolute;
  left: 0.85rem;
  bottom: 0.75rem;
  z-index: 2;
  font-size: 0.625rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: #faf8f4;
  text-shadow: 0 1px 8px rgba(0, 0, 0, 0.35);
  pointer-events: none;
}

.frame--mid {
  aspect-ratio: 5 / 4;
  align-self: center;
}

.frame--wide {
  aspect-ratio: 16 / 11;
}

.frame--tall {
  aspect-ratio: 3 / 4;
  height: 100%;
  min-height: 28rem;
}

/* ---------- Hero ---------- */

.panel--hero {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(2rem, 5vw, 4rem);
  align-items: center;
  min-height: 100vh;
  max-width: calc(var(--max) + var(--pad) * 2);
  margin: 0 auto;
  padding-top: 5.5rem;
  padding-bottom: 4rem;
}

.hero-copy {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}

.eyebrow {
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--accent);
}

.hero-title {
  font-family: var(--serif);
  font-size: clamp(3.25rem, 8vw, 5.75rem);
  font-weight: 400;
  letter-spacing: -0.02em;
  line-height: 0.95;
  color: var(--ink);
}

.hero-title em {
  font-style: italic;
  color: var(--accent);
}

.hero-media {
  position: relative;
  width: 100%;
  max-width: 26rem;
  margin-left: auto;
  aspect-ratio: 4 / 5;
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--bg-deep);
}

.hero-media img {
  position: absolute;
  inset: -8% 0;
  height: 116%;
  filter: saturate(0.9) contrast(1.03);
}

/* ---------- Full bleed ---------- */

.panel--bleed {
  padding: 0;
  height: 100vh;
  overflow: hidden;
}

.bleed {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
}

.bleed__img {
  position: absolute;
  inset: -18% 0;
  width: 100%;
  height: 136%;
  object-fit: cover;
  filter: brightness(0.88) saturate(0.9);
}

.bleed__caption {
  position: absolute;
  left: var(--pad);
  bottom: var(--pad);
  z-index: 2;
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(250, 248, 244, 0.9);
  text-shadow: 0 1px 10px rgba(0, 0, 0, 0.3);
}

/* ---------- Grids ---------- */

.panel--grid,
.panel--pair,
.panel--mosaic {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  max-width: calc(var(--max) + var(--pad) * 2);
  margin: 0 auto;
}

.grid {
  display: grid;
  width: 100%;
  gap: clamp(0.75rem, 2vw, 1.15rem);
}

.grid--3 {
  grid-template-columns: repeat(3, minmax(0, 1fr));
  align-items: end;
}

.grid--3 .frame:nth-child(2) {
  transform: translateY(-5vh);
}

.grid--2 {
  grid-template-columns: 1fr 1fr;
}

/* ---------- Mosaic ---------- */

.mosaic {
  display: grid;
  grid-template-columns: 1.1fr 1fr;
  gap: clamp(0.75rem, 2vw, 1.15rem);
  width: 100%;
  align-items: stretch;
}

.mosaic__stack {
  display: grid;
  grid-template-rows: 1fr 1fr;
  gap: clamp(0.75rem, 2vw, 1.15rem);
}

.mosaic__stack .frame {
  aspect-ratio: auto;
  min-height: 12rem;
  height: 100%;
}

/* ---------- Letters ---------- */

.panel--letters {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 55vh;
  padding-block: 10vh;
  overflow: clip;
  background: linear-gradient(
    180deg,
    var(--bg) 0%,
    var(--bg-deep) 50%,
    var(--bg) 100%
  );
}

.letter-row {
  display: flex;
  gap: 0.08em;
  font-family: var(--serif);
  font-size: clamp(5rem, 18vw, 12rem);
  font-weight: 400;
  letter-spacing: -0.02em;
  line-height: 0.9;
  color: var(--ink);
  user-select: none;
}

.letter-row span {
  position: relative;
  display: inline-block;
}

/* ---------- Close ---------- */

.panel--close {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 65vh;
  padding-bottom: 5rem;
}

.close {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.75rem;
  text-align: center;
}

.close-line {
  font-family: var(--serif);
  font-size: clamp(1.85rem, 4.5vw, 3rem);
  font-weight: 400;
  letter-spacing: -0.02em;
  font-style: italic;
  color: var(--ink);
}

.close-link {
  display: inline-flex;
  align-items: center;
  padding: 0.85rem 1.75rem;
  border: 1px solid var(--ink);
  border-radius: 100px;
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  transition:
    background 0.35s var(--ease),
    color 0.35s var(--ease);
}

.close-link:hover {
  background: var(--ink);
  color: var(--bg);
}

/* ---------- Reveal ---------- */

[data-reveal] {
  will-change: transform, opacity;
}

/* ---------- Responsive ---------- */

@media (max-width: 900px) {
  .panel--hero {
    grid-template-columns: 1fr;
    gap: 2.5rem;
    min-height: auto;
    padding-top: 6rem;
    padding-bottom: 3rem;
  }

  .hero-media {
    max-width: 18rem;
    margin: 0;
  }

  .grid--3 {
    grid-template-columns: 1fr;
    max-width: 20rem;
    margin: 0 auto;
  }

  .grid--3 .frame:nth-child(2) {
    transform: none;
  }

  .grid--2 {
    grid-template-columns: 1fr;
  }

  .mosaic {
    grid-template-columns: 1fr;
  }

  .frame--tall {
    min-height: 22rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  [data-reveal] {
    opacity: 1 !important;
    transform: none !important;
  }

  .close-link {
    transition: none;
  }
}
````

## Source — script.js
````javascript
/**
 * Atelier — Interior Design portfolio
 * Locomotive Scroll v5 + GSAP ScrollTrigger
 */

(() => {
  "use strict";

  gsap.registerPlugin(ScrollTrigger);

  const locomotiveScroll = new LocomotiveScroll({
    lenisOptions: {
      lerp: 0.09,
      duration: 1.25,
      easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)),
      smoothWheel: true,
      syncTouch: false,
    },
  });

  const lenis = locomotiveScroll.lenis;
  if (lenis) lenis.on("scroll", ScrollTrigger.update);

  window.locomotiveScroll = locomotiveScroll;

  const progressFill = document.querySelector("[data-progress-fill]");

  ScrollTrigger.create({
    start: 0,
    end: "max",
    onUpdate: (self) => {
      if (progressFill) {
        progressFill.style.width = `${(self.progress * 100).toFixed(2)}%`;
      }
    },
  });

  const reduceMotion = window.matchMedia(
    "(prefers-reduced-motion: reduce)"
  ).matches;

  if (!reduceMotion) {
    gsap.utils.toArray("[data-reveal]").forEach((el) => {
      gsap.fromTo(
        el,
        { autoAlpha: 0, y: 28 },
        {
          autoAlpha: 1,
          y: 0,
          duration: 0.95,
          ease: "power3.out",
          scrollTrigger: {
            trigger: el,
            start: "top 90%",
            once: true,
          },
        }
      );
    });

    const hero = document.querySelectorAll(".panel--hero [data-reveal]");
    hero.forEach((el) => {
      ScrollTrigger.getAll()
        .filter((st) => st.trigger === el)
        .forEach((st) => st.kill());
    });

    gsap
      .timeline({ defaults: { ease: "power3.out" } })
      .fromTo(
        hero,
        { autoAlpha: 0, y: 24 },
        { autoAlpha: 1, y: 0, duration: 1.05, stagger: 0.14, delay: 0.12 }
      );
  }

  const refresh = () => {
    ScrollTrigger.refresh();
    if (typeof locomotiveScroll.resize === "function") {
      locomotiveScroll.resize();
    }
  };

  window.addEventListener("load", refresh);

  document.querySelectorAll("img").forEach((img) => {
    if (img.complete) return;
    img.addEventListener("load", () => ScrollTrigger.refresh(), {
      once: true,
    });
  });
})();
````
