Animated Mesh Lines

A set of five demos with animated WebGL lines created with the THREE.MeshLine library. Find out how to animate and build these lines to create your own animations.

Two years ago, I started playing with lines in WebGL using THREE.MeshLine, a library made by Jaume Sanchez Elias for Three.js.

This library tackles the problem that you cannot handle the width of your lines with classic lines in Three.js. A MeshLine builds a strip of triangles billboarded to create a custom geometry instead of using the native WebGL GL_LINE method that does not support the width parameter.

These lines shaped as ribbons have a really interesting graphic style. They also have less vertices than a TubeGeometry usually used to create thick lines.

Animate a MeshLine

The only thing missing is the ability to animate lines without having to rebuild the geometry for each frame.
Based on what had already been started and how SVG Line animation works, I added three new parameters to MeshLineMaterial to visualize animated dashed line directly through the shader.

  • DashRatio: The ratio between what is visible or not (~0: more visible, ~1: less visible)
  • DashArray: The length of a dash and its space (0 == no dash)
  • DashOffset: The location where the first dash begins

Like with an SVG path, these parameters allow you to animate the entire traced line if they are correctly handled.

Here is a complete example of how to create and animate a MeshLine:


  // Build an array of points
  const segmentLength = 1;
  const nbrOfPoints = 10;
  const points = [];
  for (let i = 0; i < nbrOfPoints; i++) {
    points.push(i * segmentLength, 0, 0);
  }

  // Build the geometry
  const line = new MeshLine();
  line.setGeometry(points);
  const geometry = line.geometry;

  // Build the material with good parameters to animate it.
  const material = new MeshLineMaterial({
    transparent: true,
    lineWidth: 0.1,
    color: new Color('#ff0000'),
    dashArray: 2,     // always has to be the double of the line
    dashOffset: 0,    // start the dash at zero
    dashRatio: 0.75,  // visible length range min: 0.99, max: 0.5
  });

  // Build the Mesh
  const lineMesh = new Mesh(geometry, material);
  lineMesh.position.x = -4.5;

  // ! Assuming you have your own webgl engine to add meshes on scene and update them.
  webgl.add(lineMesh);

  // ! Call each frame
  function update() {
    // Check if the dash is out to stop animate it.
    if (lineMesh.material.uniforms.dashOffset.value < -2) return;

    // Decrement the dashOffset value to animate the path with the dash.
    lineMesh.material.uniforms.dashOffset.value -= 0.01;
  }

First animated MeshLine

Create your own line style

Now that you know how to animate lines, I will show you some tips on how to customize the shape of your lines.

Use SplineCurve or CatmullRomCurve3

These classes smooth an array of points that is roughly positioned. They are perfect to build curved and fluid lines and keep control of them (length, orientation, turbulences…).

For instance, let’s add some turbulences to our previous array of points:


  const segmentLength = 1;
  const nbrOfPoints = 10;
  const points = [];
  const turbulence = 0.5;
  for (let i = 0; i < nbrOfPoints; i++) {
    // ! We have to wrapped points into a THREE.Vector3 this time
    points.push(new Vector3(
      i * segmentLength,
      (Math.random() * (turbulence * 2)) - turbulence,
      (Math.random() * (turbulence * 2)) - turbulence,
    ));
  }

Then, use one of these classes to smooth your array of lines before you create the geometry:


  // 2D spline
  // const linePoints = new Geometry().setFromPoints(new SplineCurve(points).getPoints(50));

  // 3D spline
  const linePoints = new Geometry().setFromPoints(new CatmullRomCurve3(points).getPoints(50));

  const line = new MeshLine();
  line.setGeometry(linePoints);
  const geometry = line.geometry;

And like that you create your smooth curved line!

Animated MeshLine Curved

Note that SplineCurve only smoothes in 2D (x and y axis) compared to CatmullRomCurve3 that takes into account three axes.

I recommend to use the SplineCurve, anyway. It is more performant to calculate lines and is often enough to create the desired curved effect.

For instance, my demos Confetti and Energy are only made with the SplineCurve method:

AnimatedMeshLine - Confetti demo

AnimatedMeshLine - Energy demo

Use Raycasting

Another technique taken from a THREE.MeshLine example is using a Raycaster to scan a Mesh already present in the scene.

Thus, you can create your lines that follow the shape of an object:


  const radius = 4;
  const yMax = -4;
  const points = [];
  const origin = new Vector3();
  const direction = new Vector3();
  const raycaster = new Raycaster();

  let y = 0;
  let angle = 0;
  // Start the scan
  while (y < yMax) {
    // Update the orientation and the position of the raycaster
    y -= 0.1;
    angle += 0.2;
    origin.set(radius * Math.cos(angle), y, radius * Math.sin(angle));
    direction.set(-origin.x, 0, -origin.z);
    direction.normalize();
    raycaster.set(origin, direction);

    // Save the coordinates raycsted.
    // !Assuming the raycaster cross the object in the scene each time
    const intersect = raycaster.intersectObject(objectToRaycast, true);
    if (intersect.length) {
      points.push(
        intersect[0].point.x,
        intersect[0].point.y,
        intersect[0].point.z,
      );
    }
  }

This method is employed in the Boreal Sky demo. Here I used a sphere part as geometry to create the mesh objectToRaycast:

Boreal Sky - raycasting example

Now, you have enough tools to play and animate MeshLines. Many of these methods are inspired by the library’s examples. Feel free to explore these and share your own experiments and methods to create your own lines!

References and Credits

Jérémie Boulay

Jérémie is a French Creative Developer based in Toronto, Canada. He enjoys coding and creating interactive things especially with JavaScript and WebGL.

Stay in the loop: Get your dose of frontend twice a week

👾 Hey! Looking for the latest in frontend? Twice a week, we'll deliver the freshest frontend news, website inspo, cool code demos, videos and UI animations right to your inbox.

Zero fluff, all quality, to make your Mondays and Thursdays more creative!

Feedback 7

Comments are closed.
  1. Can anybody help me to find information about hiding canvas with reverse camera motion ( example Shooting Stars). I’ll be very appreciated.

  2. This does not work on Safari iOS. Throws this error in the console.

    SyntaxError: Cannot declare a const variable twice: ‘t’.

    Not sure if anyone knows the fix.

  3. Thank you very much for your great work, I’ve tried but I couldn’t figure out how to stop the animation (after sometime or on a user action). Anyone have guess?