JSFiddle - React, Tailwind, and code Playground

HTML

<script src="//unpkg.com/perspective.js/lib/perspective.js"></script>

<div class="wrap" id="wrap">
  <div class="indicators">
    <div class="indicator active"></div>
    <div class="indicator"></div>
  </div>
  <div class="progress"></div>
  <div class="container" id="container2" data-scroll-stage-id="color">
    <div class="battery">
      <div class="div1" data-scroll-item-id="battery"></div>
    </div>
    <p data-scroll-item-id="text">CHARGE BATTERIES</p>
  </div>
  <div class="container" id="container4" data-scroll-stage-id="transform">
    <div class="showcase" data-scroll-item-id="showcase">
      <p>ROTATE</p>
      <p>TILL</p>
      <p>YOU</p>
      <p>SEE</p>
      <p>THE</p>
      <p>END</p>
      <p>OF</p>
      <p>THIS</p>
      <p>SENTENCE</p>
    </div>
  </div>
</div>

CSS

* {
  margin: 0;
  padding: 0;
}

html, body {
  height: 100%;
  font-family: monospace,sans-serif;
}

.wrap {
  height: 100%;
  width: 100%;
  position: relative;
}

.indicators {
  position: absolute;
  right: 20px;
  top: 50%;
  transform: translateY(-50%);
  z-index: 1;
}

.indicator {
  width: 12px;
  height: 12px;
  background-color: #bce6c1;
  border-radius: 50%;
  transition: .3s;
  cursor: pointer;
}

.indicator:first-child {
  margin-bottom: 8px;
}

.indicator:hover,
.indicator.active {
  background-color: #3d8045;
}

.progress {
  width: 0;
  height: 5px;
  position: absolute;
  bottom: 0;
  left: 0;
  transition: .3s;
  background-color: #3d8045;
  z-index: 1;
}

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

.container * {
  position: absolute;
}

p {
  font-size: 40px;
  font-weight: bold;
  color: #509b35;
  cursor: default;
}

#container1 {
  background-color: #fffaf1;
}

#container1 .div1 {
  height: 200%;
  width: 100%;
  background: url('https://raw.githubusercontent.com/Leopoldthecoder/Perspective/master/docs/examples/assets/backstage.png') 0 0 repeat;
}

#container1 .div2 {
  height: 200%;
  width: 100%;
  background: url('https://raw.githubusercontent.com/Leopoldthecoder/Perspective/master/docs/examples/assets/middlestage.png') 0 0 repeat;
  z-index: 1;
}

#container1 .div3 {
  height: 200%;
  width: 100%;
  background: url('https://raw.githubusercontent.com/Leopoldthecoder/Perspective/master/docs/examples/assets/frontstage.png') 0 0 repeat;
  z-index: 1;
}

#container1 p {
  top: 40%;
  font-size: 40px;
  width: 100%;
  text-align: center;
}

#container2 {
  background-color: #fffaf1;
}

#container2 .battery {
  width: 300px;
  height: 150px;
  background-color: transparent;
  border-radius: 20px;
  border: solid 5px #666;
  padding: 20px;
  left: 50%;
  top: 50%;
  box-sizing: border-box;
  transform: translateX(-50%) translateY(-80%);
}

#container2 .battery::after {
  content: " ";
  width:...

JavaScript

const wrap = document.querySelector('#wrap')
const scroll = new perspective.Scroll(wrap, {
  stages: [{
    "id": "color",
    "scrollNumber": 10,
    "transition": 200,
    "items": [{
      "id": "battery",
      "effects": [{
        "property": "width",
        "start": "125px",
        "end": "250px"
      }, {
        "property": "backgroundColor",
        "start": "#fd0",
        "end": "#209b35"
      }]
    }, {
      "id": "text",
      "effects": [{
        "property": "color",
        "start": "#fd0",
        "end": "#209b35"
      }]
    }]
  }, {
    "id": "transform",
    "scrollNumber": 8,
    "transition": 500,
    "items": [{
      "id": "showcase",
      "effects": [{
        "property": "transform",
        "start": "rotateX(0deg)",
        "end": "rotateX(320deg)"
      }]
    }]
  }]
})

const indicators = document.querySelectorAll('.indicator')
const progress = document.querySelector('.progress')
wrap.addEventListener('stage-change', event => {
  const current = event.detail.current
  
  progress.style.width = 100 * scroll.getStep() / current.config.scrollNumber + '%'
  if (current.id === 'transform') {
    indicators[1].classList.add('active')
    indicators[0].classList.remove('active')
  } else {
    indicators[1].classList.remove('active')
    indicators[0].classList.add('active')
  }
})

wrap.addEventListener('step-change', event => {
  const { current, activeStage } = event.detail
  progress.style.width = 100 * current / activeStage.config.scrollNumber + '%'
})

indicators[0].addEventListener('click', _ => {
  scroll.setActiveStage('color')
})
indicators[1].addEventListener('click', _ => {
  scroll.setActiveStage('transform')
})