<section class="lorem">
  please <br/> scroll down ⬇
</section>

<section class="scroll-section">
  <div class="container">
    <div class="container_inner">
      <div class="scroll-section__inner">
        <figure class="scroll-section__figure">
          <img class="scroll-section__image" src="https://images.unsplash.com/photo-1495360010541-f48722b34f7d?ixid=MnwxMjA3fDB8MHxzZWFyY2h8Mnx8Y2F0fGVufDB8fDB8fA%3D%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=500&h=500&q=80" alt="">
        </figure>
        <figure class="scroll-section__figure">
          <img class="scroll-section__image" src="https://images.unsplash.com/photo-1491485880348-85d48a9e5312?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=500&h=500&q=80" alt="">
        </figure>
        <figure class="scroll-section__figure">
          <img class="scroll-section__image" src="https://images.unsplash.com/photo-1501474466180-4704b8607ba5?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1yZWxhdGVkfDEyfHx8ZW58MHx8fHw%3D&auto=format&fit=crop&w=500&h=500&q=80" alt="">
        </figure>
        <figure class="scroll-section__figure">
          <img class="scroll-section__image" src="https://images.unsplash.com/photo-1548366086-7f1b76106622?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=500&h=500&q=80" alt="">
        </figure>
        <figure class="scroll-section__figure">
          <img class="scroll-section__image" src="https://images.unsplash.com/photo-1548802673-380ab8ebc7b7?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1yZWxhdGVkfDE2fHx8ZW58MHx8fHw%3D&auto=format&fit=crop&w=500&h=500&q=80" alt="">
        </figure>

        <div class="scroll-section__content">
          <div class="scroll-section__text">
            Lorem, ipsum dolor sit amet consectetur adipisicing elit. Dolorum repudiandae aspernatur esse! Voluptate tenetur
          </div>
        </div>
        <div class="scroll-section__spacer"></div>
      </div>

    </div>
  </div>
</section>

<section class="lorem">
  thank you for scrolling <br/> now scroll up ⬆
</section>
*, *::before, *::after {
  box-sizing: border-box;
}

body, figure {
  margin: 0;
}

img {
  vertical-align: middle;
  max-width: 100%;
}

.container {
  width: 75%;
  margin: 0 auto;
  padding: 0 15px;
}

.lorem {
  height: 80vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  text-align: center;
  font-family: sans-serif;
  font-size: 3rem;
  background-color: #e4e4e4;
}

.scroll-section {
  padding: 70px 0;
  overflow: hidden;
  background-color: #00211e;
}

.scroll-section-spacer {
  background-color: #00211e;
}

.scroll-section__inner {
  display: flex;
}

.scroll-section__figure {
  flex-shrink: 0;
  margin-right: 30px;
  width: 70%;
}

.scroll-section__image {
  display: block;
  width: 100%;
}

.scroll-section__content {
  padding: 15px;
  width: calc(30% - 30px);
  min-width: 150px;
  flex-shrink: 0;
  align-self: center;
  background-color: #fff;
  font-size: 1.25em;
  font-family: sans-serif;
  opacity: 0;
  transition: opacity 500ms linear;
}

.scroll-section__content--visible {
  opacity: 1;
}

.scroll-section__spacer {
  width: calc(50vw - 50%);
  flex-shrink: 0;
}
const section = document.querySelector('.scroll-section');
const sectionContent = section.querySelector('.scroll-section__content');
const containerInner = section.querySelector('.container_inner');
const sectionFigures = [...section.querySelectorAll('.scroll-section__figure')];

const windowController = new ScrollMagic.Controller();
const sectionController = new ScrollMagic.Controller({
  container: section,
  vertical: false
});

const inertSectionController = inertController(sectionController, 0.07);

new ScrollMagic.Scene({
    offset: 0,
    triggerHook: 0,
    triggerElement: section,
    duration: '300%',
  })
  // .addIndicators() // add indicators (requires plugin)
  .setPin(section, { spacerClass: 'scroll-section-spacer' })
  .on('progress', (event) => {
    const scrollLeft = event.progress * (section.scrollWidth - section.offsetWidth);
    inertSectionController(scrollLeft);
    // sectionController.scrollTo(scrollLeft);
  })
  .addTo(windowController);

const figures = sectionFigures.map(figure => {
  const img = figure.querySelector('.scroll-section__image');
  const scene = new ScrollMagic.Scene({
    offset: 0,
    triggerHook: 0,
    triggerElement: figure,
    duration: figure.clientWidth,
  })
  //.addIndicators() // add indicators (requires plugin)
  .on('progress', (event) => {
    const progress = event.progress;
    const scale = lerp(0.55, 1, clamp(progress * 2, 0, 1));
    const ty = lerp(22.5, 0, clamp(progress * 2, 0, 1));
    const rot = lerp(270, 360, clamp(progress * 2, 0, 1));
    const opacity = lerp(1, 0, clamp(progress * 2 - 1, 0, 1));
    img.style.transform = `translateY(${ty}%) scale(${scale}) rotate(${rot}deg)`;
    img.style.opacity = opacity;
  })
  .progress(0)
  .addTo(sectionController);

  return { figure, img, scene }
});

function onResize() {
  const triggerHook = containerInner.offsetLeft / section.clientWidth;
  
  figures.forEach(({ scene, figure }) => {
    const figureWidth = figure.clientWidth;
    scene.triggerHook(triggerHook);
    scene.duration(figureWidth * 2);
    scene.offset(figureWidth * -1);
  });
}

onResize();
window.addEventListener('resize', onResize);

new ScrollMagic.Scene({
    offset: 150,
    triggerHook: 1,
    triggerElement: sectionContent,
  })
  .setClassToggle(sectionContent, 'scroll-section__content--visible')
  .addTo(sectionController);


// =============== utils ===============

function lerp(v0, v1, t) {
  return v0 * (1 - t) + v1 * t;
}

function clamp(val, min, max) {
  return Math.min(Math.max(val, min), max);
}

function inertController(controller, inert = 0.05) {
  let rafId = null;
  let prevpos = controller.scrollPos();
  let newpos;
  
  const loop = (now) =>{
    const smoothpos = Math.round(prevpos + (newpos - prevpos) * inert);
    controller.scrollTo(smoothpos);
    prevpos = smoothpos;
    
    if (smoothpos !== newpos) {
      rafId = requestAnimationFrame(loop);
    }
    else {
      rafId = null;
    }
  }
  
  return (pos) => {
    newpos = pos;
    cancelAnimationFrame(rafId);
    rafId = requestAnimationFrame(loop);
  }
}

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/ScrollMagic/2.0.8/ScrollMagic.min.js
  2. https://cdnjs.cloudflare.com/ajax/libs/ScrollMagic/2.0.8/plugins/debug.addIndicators.min.js