AirPlane Scroll Animation

we created a project about an airplane scroll animation guiding template and used a scroll trigger tool to animate the plane while scrolling.

In this post, we will animate an airplane using scroll Trigger.

Scroll Trigger is a very interesting tool that You can animate anything with while scrolling effect.

we created a project about an airplane guiding template and used a scroll trigger tool to animate the plane while scrolling.

HTML Code:

<div class="content">
	<div class="loading">Loading</div>
	<div class="trigger"></div>
	<div class="section">

		<h1>Airplanes.</h1>
		<h3>The beginners guide.</h3>
		<p>You've probably forgotten what these are.</p>
		<!-- 		<div class="phonetic">/ ˈɛərˌpleɪn /</div> -->
		<div class="scroll-cta">Scroll</div>
	</div>

	<div class="section right">
		<h2>They're kinda like buses...</h2>
	</div>

	<div class="ground-container">
		<div class="parallax ground"></div>
		<div class="section right">
			<h2>..except they leave the ground.</h2>
			<p>Saaay what!?.</p>
		</div>

		<div class="section">
			<h2>They fly through the sky.</h2>
			<p>For realsies!</p>
		</div>

		<div class="section right">
			<h2>Defying all known physical laws.</h2>
			<p>It's actual magic!</p>
		</div>
		<div class="parallax clouds"></div>
	</div>

	<div class="blueprint">
		<svg width="100%" height="100%" viewbox="0 0 100 100">
			<line id="line-length" x1="10" y1="80" x2="90" y2="80" stroke-width="0.5"></line>
			<path id="line-wingspan" d="M10 50, L40 35, M60 35 L90 50" stroke-width="0.5"></path>
			<circle id="circle-phalange" cx="60" cy="60" r="15" fill="transparent" stroke-width="0.5"></circle>
		</svg>
		<div class="section dark ">
			<h2>The facts and figures.</h2>
			<p>Lets get into the nitty gritty...</p>
		</div>
		<div class="section dark length">
			<h2>Length.</h2>
			<p>Long.</p>
		</div>
		<div class="section dark wingspan">
			<h2>Wing Span.</h2>
			<p>I dunno, longer than a cat probably.</p>
		</div>
		<div class="section dark phalange">
			<h2>Left Phalange</h2>
			<p>Missing</p>
		</div>
		<div class="section dark">
			<h2>Engines</h2>
			<p>Turbine funtime</p>
		</div>
		<!-- 		<div class="section"></div> -->
	</div>
	<div class="sunset">
		<div class="section"></div>
		<div class="section end">
			<h2>Fin.</h2>
			<ul class="credits">
				<li>Plane model by <a href="https://poly.google.com/view/8ciDd9k8wha" target="_blank">Google</a></li>
				<li>Animated using <a href="https://greensock.com/scrolltrigger/" target="_blank">GSAP ScrollTrigger</a></li>
			</ul>
		</div>
	</div>
</div>

CSS Code:

@import url("https://fonts.googleapis.com/css2?family=Libre+Baskerville:ital,wght@0,400;0,700;1,400&display=swap");
svg {
  z-index: 100;
}

:root {
  --padding: 10vmin;
  --color-background: #d0cbc7;
  --font-size-large: 8vw;
  --font-size-medium: 4vw;
  --font-size-normal: 2vw;
}
@media only screen and (min-width: 800px) {
  :root {
    --font-size-large: 64px;
    --font-size-medium: 32px;
    --font-size-normal: 16px;
  }
}
@media only screen and (max-width: 500px) {
  :root {
    --font-size-large: 40px;
    --font-size-medium: 20px;
    --font-size-normal: 14px;
  }
}

a {
  color: white;
}

ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

li {
  margin-top: 10px;
}

html,
body {
  margin: 0;
  min-height: 100%;
  min-width: 100%;
  font-family: "Libre Baskerville", serif;
  background-color: var(--color-background);
  font-weight: 400;
  font-size: var(--font-size-normal);
  overflow-x: hidden;
}

canvas {
  position: fixed;
  z-index: 10;
  top: 0;
  left: 0;
  z-index: 2;
  pointer-events: none;
  visibility: hidden;
  opacity: 0;
}

.solid {
  -webkit-clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%);
          clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%);
}

.wireframe {
  -webkit-clip-path: polygon(0% 100%, 100% 100%, 100% 100%, 0% 100%);
          clip-path: polygon(0% 100%, 100% 100%, 100% 100%, 0% 100%);
}

.content {
  position: relative;
  z-index: 1;
}
.content .trigger {
  position: absolute;
  top: 0;
  height: 100%;
}
.content .section {
  position: relative;
  padding: var(--padding);
  --pad2: calc(var(--padding) * 2);
  width: calc(100vw - var(--pad2));
  height: calc(100vh - var(--pad2));
  margin: 0 auto;
  z-index: 2;
}
.content .section.dark {
  color: white;
  background-color: black;
}
.content .section.right {
  text-align: right;
}
.content .blueprint {
  position: relative;
  background-color: #131c2a;
  background-image: linear-gradient(rgba(255, 255, 255, 0.1) 1px, transparent 1px), linear-gradient(90deg, rgba(255, 255, 255, 0.1) 1px, transparent 1px), linear-gradient(rgba(255, 255, 255, 0.05) 1px, transparent 1px), linear-gradient(90deg, rgba(255, 255, 255, 0.05) 1px, transparent 1px);
  background-size: 100px 100px, 100px 100px, 20px 20px, 20px 20px;
  background-position: -2px -2px, -2px -2px, -1px -1px, -1px -1px;
  background-attachment: fixed;
}
.content .blueprint svg {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  stroke: white;
  pointer-events: none;
  visibility: hidden;
}
.content .blueprint .dark {
  background-color: transparent;
}
.content .ground-container {
  position: relative;
  overflow: hidden;
}
.content .ground-container .parallax {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: -100px;
  background-repeat: no-repeat;
  background-position: top center;
  background-size: cover;
  transform-origin: top center;
}
.content .ground-container .ground {
  z-index: -1;
  background-image: url("https://assets.codepen.io/557388/background-reduced.jpg");
}
.content .ground-container .clouds {
  z-index: 2;
  background-image: url("https://assets.codepen.io/557388/clouds.png");
}
.content .scroll-cta,
.content .credits {
  position: absolute;
  bottom: var(--padding);
}
.content .scroll-cta {
  font-size: var(--font-size-medium);
  opacity: 0;
}
.content .sunset {
  background: url("https://assets.codepen.io/557388/sunset-reduced.jpg") no-repeat top center;
  background-size: cover;
  transform-origin: top center;
}
.content h1,
.content h2 {
  font-size: var(--font-size-large);
  margin: 0vmin 0 2vmin 0;
  font-weight: 700;
  display: inline;
}
.content h3 {
  font-size: var(--font-size-medium);
  font-weight: 400;
  margin: 0;
}
.content .end h2 {
  margin-bottom: 50vh;
}
.content .loading {
  position: fixed;
  width: 100vw;
  height: 100vh;
  top: 0;
  left: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--font-size-medium);
}

JavaScript Code:

function _defineProperty(obj, key, value) {if (key in obj) {Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true });} else {obj[key] = value;}return obj;} // clearing the console (just a CodePen thing)

console.clear();

// there are 3 parts to this
//
// Scene:           Setups and manages threejs rendering
// loadModel:       Loads the 3d obj file
// setupAnimation:  Creates all the GSAP
//                  animtions and scroll triggers
//
// first we call loadModel, once complete we call
// setupAnimation which creates a new Scene

class Scene {
  constructor(model) {_defineProperty(this, "render",







































































    () => {
      for (var ii = 0; ii < this.views.length; ++ii) {if (window.CP.shouldStopExecution(3)) break;if (window.CP.shouldStopExecution(0)) break;
        var view = this.views[ii];
        var camera = view.camera;

        var bottom = Math.floor(this.h * view.bottom);
        var height = Math.floor(this.h * view.height);

        this.renderer.setViewport(0, 0, this.w, this.h);
        this.renderer.setScissor(0, bottom, this.w, height);
        this.renderer.setScissorTest(true);

        camera.aspect = this.w / this.h;
        this.renderer.render(this.scene, camera);
      }window.CP.exitedLoop(3);window.CP.exitedLoop(0);
    });_defineProperty(this, "onResize",

    () => {
      this.w = window.innerWidth;
      this.h = window.innerHeight;

      for (var ii = 0; ii < this.views.length; ++ii) {if (window.CP.shouldStopExecution(4)) break;if (window.CP.shouldStopExecution(1)) break;
        var view = this.views[ii];
        var camera = view.camera;
        camera.aspect = this.w / this.h;
        let camZ = (screen.width - this.w * 1) / 3;
        camera.position.z = camZ < 180 ? 180 : camZ;
        camera.updateProjectionMatrix();
      }window.CP.exitedLoop(4);window.CP.exitedLoop(1);

      this.renderer.setSize(this.w, this.h);
      this.render();
    });this.views = [{ bottom: 0, height: 1 }, { bottom: 0, height: 0 }];this.renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });this.renderer.setSize(window.innerWidth, window.innerHeight);this.renderer.shadowMap.enabled = true;this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;this.renderer.setPixelRatio(window.devicePixelRatio);document.body.appendChild(this.renderer.domElement); // scene
    this.scene = new THREE.Scene();for (var _ii = 0; _ii < this.views.length; ++_ii) {if (window.CP.shouldStopExecution(2)) break;var _view = this.views[_ii];var _camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 2000);_camera.position.fromArray([0, 0, 180]);_camera.layers.disableAll();_camera.layers.enable(_ii);_view.camera = _camera;_camera.lookAt(new THREE.Vector3(0, 5, 0));} //light
    window.CP.exitedLoop(2);this.light = new THREE.PointLight(0xffffff, 0.75);this.light.position.z = 150;this.light.position.x = 70;this.light.position.y = -20;this.scene.add(this.light);this.softLight = new THREE.AmbientLight(0xffffff, 1.5);this.scene.add(this.softLight); // group
    this.onResize();window.addEventListener("resize", this.onResize, false);var edges = new THREE.EdgesGeometry(model.children[0].geometry);let line = new THREE.LineSegments(edges);line.material.depthTest = false;line.material.opacity = 0.5;line.material.transparent = true;line.position.x = 0.5;line.position.z = -1;line.position.y = 0.2;this.modelGroup = new THREE.Group();model.layers.set(0);line.layers.set(1);this.modelGroup.add(model);this.modelGroup.add(line);this.scene.add(this.modelGroup);}}function loadModel() {
  gsap.registerPlugin(ScrollTrigger);
  gsap.registerPlugin(DrawSVGPlugin);
  gsap.set("#line-length", { drawSVG: 0 });
  gsap.set("#line-wingspan", { drawSVG: 0 });
  gsap.set("#circle-phalange", { drawSVG: 0 });

  var object;

  function onModelLoaded() {
    object.traverse(function (child) {
      let mat = new THREE.MeshPhongMaterial({
        color: 0x171511,
        specular: 0xd0cbc7,
        shininess: 5,
        flatShading: true });

      child.material = mat;
    });

    setupAnimation(object);
  }

  var manager = new THREE.LoadingManager(onModelLoaded);
  manager.onProgress = (item, loaded, total) => console.log(item, loaded, total);

  var loader = new THREE.OBJLoader(manager);
  loader.load(
  "https://assets.codepen.io/557388/1405+Plane_1.obj",
  function (obj) {
    object = obj;
  });

}

function setupAnimation(model) {
  let scene = new Scene(model);
  let plane = scene.modelGroup;

  gsap.fromTo(
  "canvas",
  { x: "50%", autoAlpha: 0 },
  { duration: 1, x: "0%", autoAlpha: 1 });

  gsap.to(".loading", { autoAlpha: 0 });
  gsap.to(".scroll-cta", { opacity: 1 });
  gsap.set("svg", { autoAlpha: 1 });

  let tau = Math.PI * 2;

  gsap.set(plane.rotation, { y: tau * -0.25 });
  gsap.set(plane.position, { x: 80, y: -32, z: -60 });

  scene.render();

  var sectionDuration = 1;
  gsap.fromTo(
  scene.views[1],
  { height: 1, bottom: 0 },
  {
    height: 0,
    bottom: 1,
    ease: "none",
    scrollTrigger: {
      trigger: ".blueprint",
      scrub: true,
      start: "bottom bottom",
      end: "bottom top" } });




  gsap.fromTo(
  scene.views[1],
  { height: 0, bottom: 0 },
  {
    height: 1,
    bottom: 0,
    ease: "none",
    scrollTrigger: {
      trigger: ".blueprint",
      scrub: true,
      start: "top bottom",
      end: "top top" } });




  gsap.to(".ground", {
    y: "30%",
    scrollTrigger: {
      trigger: ".ground-container",
      scrub: true,
      start: "top bottom",
      end: "bottom top" } });



  gsap.from(".clouds", {
    y: "25%",
    scrollTrigger: {
      trigger: ".ground-container",
      scrub: true,
      start: "top bottom",
      end: "bottom top" } });



  gsap.to("#line-length", {
    drawSVG: 100,
    scrollTrigger: {
      trigger: ".length",
      scrub: true,
      start: "top bottom",
      end: "top top" } });



  gsap.to("#line-wingspan", {
    drawSVG: 100,
    scrollTrigger: {
      trigger: ".wingspan",
      scrub: true,
      start: "top 25%",
      end: "bottom 50%" } });



  gsap.to("#circle-phalange", {
    drawSVG: 100,
    scrollTrigger: {
      trigger: ".phalange",
      scrub: true,
      start: "top 50%",
      end: "bottom 100%" } });



  gsap.to("#line-length", {
    opacity: 0,
    drawSVG: 0,
    scrollTrigger: {
      trigger: ".length",
      scrub: true,
      start: "top top",
      end: "bottom top" } });



  gsap.to("#line-wingspan", {
    opacity: 0,
    drawSVG: 0,
    scrollTrigger: {
      trigger: ".wingspan",
      scrub: true,
      start: "top top",
      end: "bottom top" } });



  gsap.to("#circle-phalange", {
    opacity: 0,
    drawSVG: 0,
    scrollTrigger: {
      trigger: ".phalange",
      scrub: true,
      start: "top top",
      end: "bottom top" } });



  let tl = new gsap.timeline({
    onUpdate: scene.render,
    scrollTrigger: {
      trigger: ".content",
      scrub: true,
      start: "top top",
      end: "bottom bottom" },

    defaults: { duration: sectionDuration, ease: "power2.inOut" } });


  let delay = 0;

  tl.to(".scroll-cta", { duration: 0.25, opacity: 0 }, delay);
  tl.to(plane.position, { x: -10, ease: "power1.in" }, delay);

  delay += sectionDuration;

  tl.to(
  plane.rotation,
  { x: tau * 0.25, y: 0, z: -tau * 0.05, ease: "power1.inOut" },
  delay);

  tl.to(plane.position, { x: -40, y: 0, z: -60, ease: "power1.inOut" }, delay);

  delay += sectionDuration;

  tl.to(
  plane.rotation,
  { x: tau * 0.25, y: 0, z: tau * 0.05, ease: "power3.inOut" },
  delay);

  tl.to(plane.position, { x: 40, y: 0, z: -60, ease: "power2.inOut" }, delay);

  delay += sectionDuration;

  tl.to(
  plane.rotation,
  { x: tau * 0.2, y: 0, z: -tau * 0.1, ease: "power3.inOut" },
  delay);

  tl.to(plane.position, { x: -40, y: 0, z: -30, ease: "power2.inOut" }, delay);

  delay += sectionDuration;

  tl.to(plane.rotation, { x: 0, z: 0, y: tau * 0.25 }, delay);
  tl.to(plane.position, { x: 0, y: -10, z: 50 }, delay);

  delay += sectionDuration;
  delay += sectionDuration;

  tl.to(
  plane.rotation,
  { x: tau * 0.25, y: tau * 0.5, z: 0, ease: "power4.inOut" },
  delay);

  tl.to(plane.position, { z: 30, ease: "power4.inOut" }, delay);

  delay += sectionDuration;

  tl.to(
  plane.rotation,
  { x: tau * 0.25, y: tau * 0.5, z: 0, ease: "power4.inOut" },
  delay);

  tl.to(plane.position, { z: 60, x: 30, ease: "power4.inOut" }, delay);

  delay += sectionDuration;

  tl.to(
  plane.rotation,
  { x: tau * 0.35, y: tau * 0.75, z: tau * 0.6, ease: "power4.inOut" },
  delay);

  tl.to(plane.position, { z: 100, x: 20, y: 0, ease: "power4.inOut" }, delay);

  delay += sectionDuration;

  tl.to(
  plane.rotation,
  { x: tau * 0.15, y: tau * 0.85, z: -tau * 0, ease: "power1.in" },
  delay);

  tl.to(plane.position, { z: -150, x: 0, y: 0, ease: "power1.inOut" }, delay);

  delay += sectionDuration;

  tl.to(
  plane.rotation,
  {
    duration: sectionDuration,
    x: -tau * 0.05,
    y: tau,
    z: -tau * 0.1,
    ease: "none" },

  delay);

  tl.to(
  plane.position,
  { duration: sectionDuration, x: 0, y: 30, z: 320, ease: "power1.in" },
  delay);


  tl.to(
  scene.light.position,
  { duration: sectionDuration, x: 0, y: 0, z: 0 },
  delay);

}

loadModel();

Thank You!

Share your love
Default image
Coding Hindi
Articles: 38

Leave a Reply

Your email address will not be published.

I'm not a robot *Captcha loading...

10 Best Chrome Extensions for Developers in 2022. 10 Best Free C Programming Courses to Take in 2022 9 Most Useful Tools For Instagram Growth.[2022] What is an operating system ? How to Make Money Online from Instagram in India?