# Make particles follow a path - issues

**URL:** <https://discourse.threejs.org/t/make-particles-follow-a-path-issues/50633>\
**Category:** Questions\
**Tags:** transform, path\
**Created:** [April 20, 2023, 11:29am UTC](https://discourse.threejs.org/t/make-particles-follow-a-path-issues/50633 "2023-04-20T11:29:56Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![UI\_UNICORN](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/ui_unicorn/32/9842_2.png) [@UI\_UNICORN](https://discourse.threejs.org/u/UI_UNICORN)\
**Post date:** [April 20, 2023, 11:29am UTC](https://discourse.threejs.org/t/make-particles-follow-a-path-issues/50633/1 "2023-04-20T11:29:56Z")

</div>

So i am trying to make some particles follow a path I’ve managed to this but the particles seem to be duplicated twice so there are a few particles in the middle of the screen that do not move that should not be there I’ve also noticed the animation rotation of the “particle box” jumps … here is a code pen  
https://codepen.io/uiunicorn/embed/preview/abRBmrm?default-tabs=js%2Cresult&height=300&host=https%3A%2F%2Fcodepen.io&slug-hash=abRBmrm

i am trying to create one of these particle paths from this example but with the above path as you can see It’s not going to well

> **[Volt for Drive — EV Charging stations facility management](https://voltfordrive.com/)**
>
> Facilities for EV drivers, station operators and company's investors and partners

thanks for any help

---

<div class="post-metadata">

**Author:** ![PavelBoytchev](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/pavelboytchev/32/38639_2.png) [@PavelBoytchev](https://discourse.threejs.org/u/PavelBoytchev)\
**Post date:** [April 20, 2023, 12:32pm UTC](https://discourse.threejs.org/t/make-particles-follow-a-path-issues/50633/2 "2023-04-20T12:32:38Z")

</div>

### Issue 1:

Several clouds are created and added to the scene by code like this:

```javascript
for (var i = 0; i < parameterse.length; i++) {
     ...
     particles = new THREE.Points(geometryParticle, materials[i]);
     scene.add(particles);
 }     

```

However, as they all recycle the same variable, at the end, `particles` refers only to the last cloud. So, when you move `particles` only one of the cloud is moved.

### Issue 2:

Try the following idea for turning the cloud. Remove these lines (or just comment them):

```javascript
axis.crossVectors( up, tangent ).normalize();
radians = Math.acos( up.dot( tangent ) );
particles.quaternion.setFromAxisAngle( axis, radians );

if (object instanceof THREE.Points) { 
      object.rotation.y = time * (i < 1 ? i + 2 : -(i + 1));
      object.rotation.x = time2 * (i < 1 ? i + 2 : -(i + 1));
      object.rotation.z = time * (i < 1 ? i + 2 : -(i + 1));
} 

```

add just this line:

```javascript
particles.rotation.y = Math.atan2( tangent.x, tangent.z );

```

---

<div class="post-metadata">

**Author:** ![PavelBoytchev](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/pavelboytchev/32/38639_2.png) [@PavelBoytchev](https://discourse.threejs.org/u/PavelBoytchev)\
**Post date:** [April 20, 2023, 12:43pm UTC](https://discourse.threejs.org/t/make-particles-follow-a-path-issues/50633/3 "2023-04-20T12:43:58Z")

</div>

In case you want to move all clouds, here is the whole `animate` function (not optimal, as I tried to make minimal changes to code).

```javascript
function animate() {
   fraction +=0.0004;
   if (fraction > 1) fraction = 0;

   newPosition = pointsPath.getPoint(fraction);
   tangent = pointsPath.getTangent(fraction);

   for (var i = 0; i < scene.children.length; i++) {
       var object = scene.children[i];
       if (object instanceof THREE.Points) { 
          object.position.copy(newPosition);
          object.rotation.y = Math.atan2( tangent.x, tangent.z );
       } 
   }

   for (var i = 0; i < materials.length; i++) { 
       var color = parameterse[i][0];
       var h = ((360 * (color[0] + time)) % 360) / 360;
       materials[i].color.setHSL(h, color[1], color[2]);  
   }
  
   requestAnimationFrame(animate);
   renderer.render(scene, camera);
};

```

Here is the result:

[https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/1/5/1522007f82ab903af739afdace6379ae85947456.mp4](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/1/5/1522007f82ab903af739afdace6379ae85947456.mp4)

---

<div class="post-metadata">

**Author:** ![UI\_UNICORN](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/ui_unicorn/32/9842_2.png) [@UI\_UNICORN](https://discourse.threejs.org/u/UI_UNICORN)\
**Post date:** [April 20, 2023, 1:08pm UTC](https://discourse.threejs.org/t/make-particles-follow-a-path-issues/50633/4 "2023-04-20T13:08:34Z")

</div>

> [@PavelBoytchev](#):
>
> ```javascript
> fraction +=0.0004;
> if (fraction > 1) fraction = 0;
> 
> newPosition = pointsPath.getPoint(fraction);
> tangent = pointsPath.getTangent(fraction);
> 
> for (var i = 0; i < scene.children.length; i++) {
> var object = scene.children[i];
> if (object instanceof THREE.Points) { 
> object.position.copy(newPosition);
> object.rotation.y = Math.atan2( tangent.x, tangent.z );
> } 
> }
> 
> for (var i = 0; i < materials.length; i++) { 
> var color = parameterse[i][0];
> var h = ((360 * (color[0] + time)) % 360) / 360;
> materials[i].color.setHSL(h, color[1], color[2]);  
> }
>   
> requestAnimationFrame(animate);
> renderer.render(scene, 
> 
> ```

thanks for replying  
Would there be a way to like rotate each particle at different rates ?

---

<div class="post-metadata">

**Author:** ![PavelBoytchev](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/pavelboytchev/32/38639_2.png) [@PavelBoytchev](https://discourse.threejs.org/u/PavelBoytchev)\
**Post date:** [April 20, 2023, 1:26pm UTC](https://discourse.threejs.org/t/make-particles-follow-a-path-issues/50633/5 "2023-04-20T13:26:52Z")

</div>

Currently rotation it taken from the path direction and is set here:

```javascript
object.rotation.y = Math.atan2( tangent.x, tangent.z );

```

If you want every cloud to rotate in its own way, you have to calculate its `rotation` property. Here is an example of crazy clouds:

```javascript
object.rotation.x = 3*Math.cos(i-6*fraction);
object.rotation.y = 7*Math.sin(i+6*fraction);

```

If you want to rotate individual points in the cloud, then you have to calculate their positions in the attribute buffer.

---

<div class="post-metadata">

**Author:** ![prisoner849](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/prisoner849/32/535_2.png) [@prisoner849](https://discourse.threejs.org/u/prisoner849)\
**Post date:** [April 20, 2023, 1:29pm UTC](https://discourse.threejs.org/t/make-particles-follow-a-path-issues/50633/6 "2023-04-20T13:29:59Z")

</div>

> [@UI\_UNICORN](#):
>
> i am trying to create one of these particle paths from this example but with the above path as you can see

@akella has a really good video about it:

[![](https://img.youtube.com/vi/MnKKetZZi8g/maxresdefault.jpg "Travelling particles with Three.js #3") ](https://www.youtube.com/watch?v=MnKKetZZi8g)

---

<div class="post-metadata">

**Author:** ![UI\_UNICORN](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/ui_unicorn/32/9842_2.png) [@UI\_UNICORN](https://discourse.threejs.org/u/UI_UNICORN)\
**Post date:** [April 20, 2023, 3:43pm UTC](https://discourse.threejs.org/t/make-particles-follow-a-path-issues/50633/7 "2023-04-20T15:43:06Z")

</div>

So I ended up with this [https://codepen.io/uiunicorn/full/GRYNWXy](https://codepen.io/uiunicorn/full/GRYNWXy) i know its only one point and ill probably need more but can you suggest a way to make the particles “blend with the curve” kind of like a snake as its kind of ridged looking 🙂

---

<div class="post-metadata">

**Author:** ![PavelBoytchev](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/pavelboytchev/32/38639_2.png) [@PavelBoytchev](https://discourse.threejs.org/u/PavelBoytchev)\
**Post date:** [April 20, 2023, 4:20pm UTC](https://discourse.threejs.org/t/make-particles-follow-a-path-issues/50633/8 "2023-04-20T16:20:19Z")

</div>

You use `getPoint` to get a position along the path, this is completely sufficient. You need to have shorter clouds. Then place every cloud on its own position long the curve, so, `newPosition` and `tangent` must be recalculated for each cloud. All clouds’ positions are based on `t` but with different offset (thus the left cloud is at position `t`, the next cloud is a little bit ahead of time, the next to the next is more ahead of time and so on). This is a simplified illustration of 5 clouds on a path.

 ![image](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/c/3/c3d43862c1dc7a139f6e195a29dd31da64171fb8.png)

And here is what it looks like as animation:

[https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/7/6/764a7c7f54cfd4ba055034884d755b7573ad45f4.mp4](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/7/6/764a7c7f54cfd4ba055034884d755b7573ad45f4.mp4)

Good luck with your project!

---

<div class="post-metadata">

**Author:** ![UI\_UNICORN](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/ui_unicorn/32/9842_2.png) [@UI\_UNICORN](https://discourse.threejs.org/u/UI_UNICORN)\
**Post date:** [April 20, 2023, 4:53pm UTC](https://discourse.threejs.org/t/make-particles-follow-a-path-issues/50633/9 "2023-04-20T16:53:42Z")

</div>

That’s sick, ill give it ago so i need more than one “particles” array? and then set the time to a short time for each ?

---

<div class="post-metadata">

**Author:** ![PavelBoytchev](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/pavelboytchev/32/38639_2.png) [@PavelBoytchev](https://discourse.threejs.org/u/PavelBoytchev)\
**Post date:** [April 20, 2023, 5:09pm UTC](https://discourse.threejs.org/t/make-particles-follow-a-path-issues/50633/10 "2023-04-20T17:09:12Z")

</div>

You already have 5 or 6. For the video I did not create any new “particles” arrays, just reused the ones that already exist.

---

<div class="post-metadata">

**Author:** ![UI\_UNICORN](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/ui_unicorn/32/9842_2.png) [@UI\_UNICORN](https://discourse.threejs.org/u/UI_UNICORN)\
**Post date:** [April 20, 2023, 7:27pm UTC](https://discourse.threejs.org/t/make-particles-follow-a-path-issues/50633/11 "2023-04-20T19:27:04Z")

</div>

so here’s my attempt at it where am i going wrong maybe the size?  
https://codepen.io/uiunicorn/embed/preview/xxyRWga?default-tabs=js%2Cresult&height=300&host=https%3A%2F%2Fcodepen.io&slug-hash=xxyRWga

---

<div class="post-metadata">

**Author:** ![UI\_UNICORN](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/ui_unicorn/32/9842_2.png) [@UI\_UNICORN](https://discourse.threejs.org/u/UI_UNICORN)\
**Post date:** [April 20, 2023, 8:09pm UTC](https://discourse.threejs.org/t/make-particles-follow-a-path-issues/50633/12 "2023-04-20T20:09:43Z")

</div>

another attempt [https://codepen.io/uiunicorn/pen/MWPbVpE](https://codepen.io/uiunicorn/pen/MWPbVpE)

---

<div class="post-metadata">

**Author:** ![UI\_UNICORN](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/ui_unicorn/32/9842_2.png) [@UI\_UNICORN](https://discourse.threejs.org/u/UI_UNICORN)\
**Post date:** [April 20, 2023, 11:30pm UTC](https://discourse.threejs.org/t/make-particles-follow-a-path-issues/50633/13 "2023-04-20T23:30:27Z")

</div>

[https://codepen.io/uiunicorn/full/abRBKxE](https://codepen.io/uiunicorn/full/abRBKxE) this is the best I could do would you mind showing me what values and stuff you had mine are miles off so doesn’t look as smooth, thanks

---

<div class="post-metadata">

**Author:** ![PavelBoytchev](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/pavelboytchev/32/38639_2.png) [@PavelBoytchev](https://discourse.threejs.org/u/PavelBoytchev)\
**Post date:** [April 21, 2023, 7:42am UTC](https://discourse.threejs.org/t/make-particles-follow-a-path-issues/50633/14 "2023-04-21T07:42:02Z")

</div>

The full JS code of the last video, that I posted, is at the bottom. As a general advice, not related to your questions, try to keep the code tidy and well formatted. This is very helpful for debugging and understanding the fabrics of what the code does. There are several code formatting styles, any of them is better than having no style.

As for the code, there is no need to calculate different positions in different variables. This can be done on-the-fly in the cycle where clouds have their rotation set. Like this:

```javascript
for (var i = 0; i < scene.children.length; i++) {
   // get position and tangent of i-th cloud
   newPosition = pointsPath.getPoint((fraction+i/50)%1);
   tangent = pointsPath.getTangent((fraction+i/50)%1);

   var object = scene.children[i];
   if (object instanceof THREE.Points) { 
        var time = Date.now() * 0.0009;

        // set position of i-th cloud
        object.position.copy(newPosition);

        // set rotation of i-th cloud
        object.rotation.y = Math.atan2( tangent.x, tangent.z );
        object.rotation.z = time * (i < 1 ? i + 2 : -(i + 1));
   } // if
} // for

```

> **Show the full source code**
>
> ```javascript
> import * as THREE from "https://jokertattoo.co.uk/game-lesson-1/js/three.module.js";
> import TWEEN from "https://jokertattoo.co.uk/game-lesson-1/js/tween.esm.js";
> import { RGBELoader } from "https://jokertattoo.co.uk/game-lesson-1/js/RGBELoader.js";
> import { OrbitControls } from "https://jokertattoo.co.uk/game-lesson-1/js/OrbitControls.js";
> import { GLTFLoader } from "https://jokertattoo.co.uk/game-lesson-1/js/GLTFLoader.js";
> import { RoughnessMipmapper } from "https://jokertattoo.co.uk/game-lesson-1/js/RoughnessMipmapper.js";
> import { CSS2DRenderer, CSS2DObject } from "https://jokertattoo.co.uk/game-lesson-1/js/CSS2DRenderer.js";
> 
> var container, controls;
> var camera, scene, renderer, loaderGL, time, mixer, mixer2, mixer3, mixer4, mixer6, mixer7, mixer8, mixer9, clock, labelRenderer;
> var raycaster, mouse, tween;
> var model, model2, model3, model4, model5, model6, model7, model8, model9;
> var cubefix, cube, cube2, cube3, cube4, cube5, character, Characterm, Monster0, score, gltfPlayer, gltfMonster, isZoomed, gltfC1, gltfC2, gltfC3, gltfC4, gltfC5;
> var action, action3, action0, action2, action4, action5, action6;
> var nearFog, farFog, densityFog, colorFog, colorFog2;
> var hotspotLabel1, hotspotLabel2, hotspotLabel3, hotspotLabel4;
> var materials = [],
> parameters;
> var mouseX = 0,
> mouseY = 0;
> var timerAnimate;
> var CH0, CH, CH3, CH4;
> var game_loader_count = 0;
> var observer, text, checkText, partcount, StartButton, ButtonStart;
> var fov, aspect, near, far;
> var fraction, pointsPath, char, axis, up, newPosition, tangent, radians, particles, loaderSprite;
> var materials = [];
> var parameterse =[];
> 
> init();
> animate();
> function init() {
> renderer = new THREE.WebGLRenderer({antialias: true});
> renderer.setSize(window.innerWidth, window.innerHeight);
> renderer.setPixelRatio(devicePixelRatio);
> document.body.appendChild(renderer.domElement); 
> var pmremGenerator = new THREE.PMREMGenerator(renderer);
> pmremGenerator.compileEquirectangularShader();
> 
> fov = { value: 45};
> aspect = window.innerWidth / window.innerHeight;
> near = { value: 1};
> far = { value: 10000};
> camera = new THREE.PerspectiveCamera(fov.value, aspect, near.value, far.value);
> camera.position.set(-8, 10, 25.1);
> 
> camera.lookAt(0,0,0);
> 
> scene = new THREE.Scene();
> scene.background = new THREE.Color(0x000000);
> 
>   
>  
> fraction = 0;
> 
>    
> up = new THREE.Vector3( 0,0,1 );
> axis = new THREE.Vector3( );
> 
> pointsPath = new THREE.CurvePath();
> 
> const curve = new THREE.CatmullRomCurve3( [
> new THREE.Vector3( 0, 0, -0 ),
> new THREE.Vector3( -2, 0, 7 ),
> new THREE.Vector3( -8, 0, 12 ),
> new THREE.Vector3( -14, 0, 8 ),
> new THREE.Vector3( 10, 0, 5 ),
> new THREE.Vector3( -5, 0, -14 ),
> new THREE.Vector3( 5, 0, -15 ),
> new THREE.Vector3( 0, 0, -0 ),
> ] );
>               
> const bezierLine = new THREE.CubicBezierCurve3(
>     
> //originals
> new THREE.Vector3( 13, 0, -1 ),
> new THREE.Vector3( 500, 0, 100 ),
> new THREE.Vector3( -14, 0, -73 ),
> new THREE.Vector3( 0, 0, 0 ),
>     	
> );
>    
>   
> const bezierLine2 = new THREE.CubicBezierCurve3(
> new THREE.Vector3( 0, 0, -1 ),
> new THREE.Vector3( -50, 0, 10 ),
> new THREE.Vector3( -14, 0, -73 ),
> new THREE.Vector3( 0, 0, 0 ),
> );
>   
>   
> pointsPath.add(curve);
> // pointsPath.add(bezierLine2);
>  
> const material = new THREE.MeshNormalMaterial();
> const coneGeom = new THREE.ConeGeometry(1, 2, 10);
> coneGeom.translate(0, 24.5, 0);
>   
>   
> const cone = new THREE.Mesh(coneGeom, material);
> const cylinder = new THREE.CylinderGeometry(0.4, 0.6, 3, 10);
>   
> cylinder.merge(cone.geometry, cone.matrix);
> cylinder.scale(0.5, 0.5, 0.5);
>   
> char = new THREE.Mesh(cylinder, material);
>  
> 
>      
> 
> loaderSprite = new THREE.TextureLoader();
> 	  
> 	               
>         
>                          
> //Load En
>                    
>                   
>                   
>                
> var geometryParticle = new THREE.BufferGeometry();
> var vertices = [];
> 
> var sprite1 = loaderSprite.load("https://i.imgur.com/5w23cqM.png"); 
> var partcount = 40;
> 
> const min = 1,
> max = 2,
> high = Math.floor(Math.random() * (max - min) + min);
> for (var i = 0; i < partcount; i++) { var x = (Math.random() * 2 - 1) * 1; var y = (Math.random() * 2 - 1) * 1; var z = (Math.random() * 2 - 1) * 2;
> vertices.push(x, y, z); }
> geometryParticle.setAttribute("position", new THREE.Float32BufferAttribute(vertices, 3));
> parameterse = [[[0.8, 0, 0.5], sprite1, 1], [[0.8, 0, 0.5], sprite1, 2], [[0.8, 0, 0.5], sprite1, 1], [[0.8, 0, 0.5], sprite1, 2], [[0.8, 0, 0.5], sprite1, 3], ];
> for (var i = 0; i < parameterse.length; i++) { var color = parameterse[i][2]; var sprite = parameterse[i][1]; var size = parameterse[i][2];
> materials[i] = new THREE.PointsMaterial({ size: size, map: sprite, blending: THREE.AdditiveBlending,
> depthWrite: false, transparent: true, fog: false, toneMapped: false}); 
>       
>       
> materials[i].toneMapped = false; materials[i].color.setHSL(color[0], color[1], color[2]);
>       
>       
> particles = new THREE.Points(geometryParticle, materials[i]);
> // particles.rotation.x = Math.random() 
>  
> 
> scene.add(particles);
> }     
>              
> 
>    
>    
>    
>   
> 
>   
> const material2 = new THREE.LineBasicMaterial({
> color: 0x9132a8
> });
> const points = pointsPath.curves.reduce((p, d)=> [...p, ...d.getPoints(60)], []);
>   
> const geometry2 = new THREE.BufferGeometry().setFromPoints( points );
>   
> 
> var liner = new THREE.Line( geometry2, material2 );
> scene.add(liner);
>     
> clock = new THREE.Clock();
> 
>    
>  
> 
>  
>         
> const axesHelper = new THREE.AxesHelper( 0.5 );
> axesHelper.translateX(1);
> scene.add( axesHelper );
>   
> 
> controls = new OrbitControls(camera, renderer.domElement);
> 
> controls.enableKeys = false;
> controls.enableZoom = false;
> controls.enableDamping = true;
> controls.maxPolarAngle = 1.4;
> controls.minPolarAngle = 1.2;
> controls.dampingFactor = 0.04;
> controls.autoRotate = false;
> controls.rotateSpeed = 0.015;
> controls.minDistance = 2;
>           
> controls.enabled = false;
> 
> }
> 
> function animate() {
>     
>     
> fraction +=0.0004;
> // if (fraction > 1) fraction = 0;
> 
> for (var i = 0; i < scene.children.length; i++) {
> 
> newPosition = pointsPath.getPoint((fraction+i/50)%1);
> tangent = pointsPath.getTangent((fraction+i/50)%1);
> 
>      
> var object = scene.children[i];
> if (object instanceof THREE.Points) { 
> const pos = object.position.copy(newPosition);
>         
> var time = Date.now() * 0.0009;
> object.rotation.y = Math.atan2( tangent.x, tangent.z );
>            
> object.rotation.z = time * (i < 1 ? i + 2 : -(i + 1));
>      
>          
>          
> } 
> }
> 
> for (var i = 0; i < materials.length; i++) { 
> var color = parameterse[i][0];
> var h = ((360 * (color[0] + time)) % 360) / 360;
> materials[i].color.setHSL(h, color[1], color[2]);  
> }
>      
>      
>      
> 
>  
> 
> requestAnimationFrame(animate);
> renderer.render(scene, camera);
>   
> };
> 
> ```
