I can't get this demo to work on my computer in three.js and cannon.js from sandbox

383 Views Asked by At

Here is the demo but it always says that I am missing the modules whereas I have all the dependancies : https://tympanus.net/codrops/2020/02/11/how-to-create-a-physics-based-3d-cloth-with-cannon-js-and-three-js/

Would anyone know how to code it on your computer from the sandbox example?

In all my js files calling 'three'; i get "Uncaught SyntaxError: Cannot use import statement outside a module".

<!DOCTYPE html>
<html>
  <head>
    <title>Physics Slideshow - 03</title>
    <meta charset="UTF-8" />
  </head>

  <body>
    <div id="app">
      <section class="container">
        <article class="tile">
          <figure class="tile__figure">
            <img
              src="https://images.unsplash.com/photo-1541737923-4dc81f2d1d41?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=3334&q=80"
              class="tile__image"
              alt="My image"
              width="400"
            />
          </figure>
        </article>
      </section>

      <canvas id="stage"></canvas>
    </div>

    <script src="src/index.js"></script>
  </body>
</html>

<—— figure.js——>

import * as THREE from "three";
import C from "cannon";

const size = 8;
const mass = 1;

export default class Figure {
  constructor(scene, world) {
    this.$image = document.querySelector(".tile__image");
    this.$image.style.opacity = 0;

    this.scene = scene;
    this.world = world;

    this.loader = new THREE.TextureLoader();

    this.image = this.loader.load(this.$image.src);

    this.sizes = new THREE.Vector2(0, 0);
    this.offset = new THREE.Vector2(0, 0);
    this.bufferV = new THREE.Vector3();
    this.bufferV2 = new C.Vec3();

    this.getSizes();

    this.createMesh();
    this.createStitches();
  }

  getSizes() {
    const { width, height, top, left } = this.$image.getBoundingClientRect();

    this.sizes.set(width, height);
    this.offset.set(
      left - window.innerWidth / 2 + width / 2,
      -top + window.innerHeight / 2 - height / 2
    );
  }

  createMesh() {
    this.geometry = new THREE.PlaneBufferGeometry(1, 1, size, size);
    this.material = new THREE.MeshBasicMaterial({
      map: this.image
    });

    this.mesh = new THREE.Mesh(this.geometry, this.material);

    this.mesh.position.set(this.offset.x, this.offset.y, 0);
    this.mesh.scale.set(this.sizes.x, this.sizes.y, 1);

    this.scene.add(this.mesh);
  }

  createStitches() {
    const particleShape = new C.Particle();
    const { position } = this.geometry.attributes;
    const { x: width, y: height } = this.sizes;

    this.stitches = [];

    for (let i = 0; i < position.count; i++) {
      const row = Math.floor(i / (size + 1));

      const pos = new C.Vec3(
        position.getX(i) * width,
        position.getY(i) * height,
        position.getZ(i)
      );

      const stitch = new C.Body({
        mass: row === 0 ? 0 : mass / position.count,
        linearDamping: 0.8,
        position: pos,
        shape: particleShape
      });

      this.stitches.push(stitch);
      this.world.addBody(stitch);
    }

    for (let i = 0; i < position.count; i++) {
      const col = i % (size + 1);
      const row = Math.floor(i / (size + 1));

      if (col < size) this.connect(i, i + 1);
      if (row < size) this.connect(i, i + size + 1);
    }
  }

  connect(i, j) {
    const c = new C.DistanceConstraint(this.stitches[i], this.stitches[j]);

    this.world.addConstraint(c);
  }

  applyWind(wind) {
    const { position } = this.geometry.attributes;

    for (let i = 0; i < position.count; i++) {
      const stitch = this.stitches[i];

      const windNoise = wind.flowfield[i];
      const tempPosPhysic = this.bufferV2.set(
        windNoise.x,
        windNoise.y,
        windNoise.z
      );

      stitch.applyForce(tempPosPhysic, C.Vec3.ZERO);
    }
  }

  update() {
    const { position } = this.geometry.attributes;
    const { x: width, y: height } = this.sizes;

    for (let i = 0; i < position.count; i++) {
      const p = this.bufferV.copy(this.stitches[i].position);

      position.setXYZ(i, p.x / width, p.y / height, p.z);
    }

    position.needsUpdate = true;
  }
}

<—— scene.js——>

import * as THREE from "three";
import Figure from "./Figure";
import Wind from "./Wind";
import C from "cannon";

const perspective = 800;

export default class Scene {
  constructor() {
    this.container = document.getElementById("stage");

    this.scene = new THREE.Scene();
    this.world = new C.World();
    this.world.gravity.set(0, -1000, 0);

    this.renderer = new THREE.WebGLRenderer({
      canvas: this.container,
      alpha: true
    });

    this.renderer.setSize(window.innerWidth, window.innerHeight);
    this.renderer.setPixelRatio(window.devicePixelRatio);

    this.initLights();
    this.initCamera();

    this.figure = new Figure(this.scene, this.world);
    this.wind = new Wind(this.figure.mesh);

    this.update();
  }

  initLights() {
    const ambientlight = new THREE.AmbientLight(0xffffff, 2);
    this.scene.add(ambientlight);
  }

  initCamera() {
    const fov =
      (180 * (2 * Math.atan(window.innerHeight / 2 / perspective))) / Math.PI;

    this.camera = new THREE.PerspectiveCamera(
      fov,
      window.innerWidth / window.innerHeight,
      1,
      5000
    );
    this.camera.position.set(0, 0, perspective);
  }

  update() {
    if (
      this.renderer === undefined ||
      this.scene === undefined ||
      this.camera === undefined
    )
      return;
    requestAnimationFrame(this.update.bind(this));

    this.wind.update();
    this.figure.update();
    this.figure.applyWind(this.wind);
    this.world.step(1 / 60);
    this.renderer.render(this.scene, this.camera);
  }
}

<—— wind.js——>

import SimplexNoise from "simplex-noise";
import { Clock, Vector3 } from "three";
import gsap from "gsap";

const noise = new SimplexNoise();
const baseForce = 2000;
const off = 0.05;

export default class Wind {
  constructor(figure) {
    const { count } = figure.geometry.attributes.position;
    this.figure = figure;

    this.force = baseForce / count;

    this.clock = new Clock();
    this.direction = new Vector3(0.5, 0, -1);
    this.flowfield = new Array(count);

    this.update();

    this.bindEvents();
  }

  bindEvents() {
    window.addEventListener("mousemove", this.onMouseMove.bind(this));
  }

  onMouseMove({ clientX: x, clientY: y }) {
    const { innerWidth: W, innerHeight: H } = window;

    gsap.to(this.direction, {
      duration: 0.8,
      x: x / W - 0.5,
      y: -(y / H) + 0.5
    });
  }

  update() {
    const time = this.clock.getElapsedTime();

    const { position } = this.figure.geometry.attributes;
    const size = this.figure.geometry.parameters.widthSegments;

    for (let i = 0; i < position.count; i++) {
      const col = i % (size + 1);
      const row = Math.floor(i / (size + 1));

      const force =
        (noise.noise3D(row * off, col * off, time) * 0.5 + 0.5) * this.force;

      this.flowfield[i] = this.direction.clone().multiplyScalar(force);
    }
  }
}

<—— index.js——>

import "./styles.css";
import Scene from "./Scene";

const initApp = () => {
  window.scene = new Scene();
};

if (
  document.readyState === "complete" ||
  (document.readyState !== "loading" && !document.documentElement.doScroll)
) {
  initApp();
} else {
  document.addEventListener("DOMContentLoaded", initApp);
}

<—— styles.css ——>

body {
  margin: 0;
  background-color: #e4e0dd;
}

.container {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100vh;
  z-index: 10;
}

.tile {
  width: 50vmin;
  flex: 0 0 auto;
}

.tile__figure {
  margin: 0;
  padding: 0;
}

.tile__image {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}

canvas {
  position: fixed;
  left: 0;
  top: 0;
  width: 100%;
  height: 100vh;
  z-index: 9;
}
1

There are 1 best solutions below

0
On

I think this is more a question about technique than any one error, because there could be a tree of errors that aren't being rendered after your current error crashes the program. I'm not sure what steps you've taken exactly to do get this project running, but what I would do is piece it out step by step. fist, make sure scene.js is running properly on your computer, then build the parts of the project piece by piece. Maybe you could start with piecing it together from this line in the scene.js file and look up every piece from there while using debugging techniques:

 this.renderer = new THREE.WebGLRenderer({
      canvas: this.container,
      alpha: true
    });

I'm guessing that you copy and pasted lot of that code into your project file, and you're usually going to run into big problems by doing that. good luck!