I myself do not deal with modeling software, but I know from the posts here in the forum that such figures are better modeled and animated with such software.

Check out the text and video on the UPDATE Feb 19 of the post Skinned mesh with dynamic knees. The problem is the torsion not only to one axis.

The mathematics of

https://hofk.de/main/discourse.threejs/2022/DynamicTubeGeometry/DynamicTubeGeometryCaps.html

regarding the space curve is already integrated in three.js : three.js/CatmullRomCurve3.js at f021ec0c9051eb11d110b0c2b93305bffd0942e0 · mrdoob/three.js · GitHub

Around this curve I form orthogonal circles in space. Of course you can experiment and use different radii over the curve.

```
g.pts = new THREE.CatmullRomCurve3( points , false ).getSpacedPoints( g.heightSegments ); // new center points
// tangent( direction), normal, binormal, shape in space
let v3a = new THREE.Vector3( );
let v3b = new THREE.Vector3( );
let tangent = new THREE.Vector3( );
let normal = new THREE.Vector3( 0, 0, -1 ); // first normal to after ...
let binormal = new THREE.Vector3( );
let idx = 0;
for( let i = 0; i <= g.heightSegments; i ++ ) {
if ( i === 0 ) tangent.subVectors( g.pts[ 1 ], g.pts[ 0 ] );
if ( i > 0 && i < g.heightSegments ) tangent.subVectors( g.pts[ i + 1 ], g.pts[ i - 1 ] );
if ( i === g.heightSegments ) tangent.subVectors( g.pts[ i ], g.pts[ i - 1 ] );
binormal.crossVectors( normal, tangent );
normal.crossVectors( tangent, binormal );
binormal.normalize( );
normal.normalize( );
for( let j = 0; j <= g.radialSegments; j ++ ) {
// circle in space
v3a.addVectors( binormal.clone( ).multiplyScalar( Math.sin( Math.PI * 2 * j / g.radialSegments ) ), normal.clone( ).multiplyScalar( Math.cos( Math.PI * 2 * j / g.radialSegments ) ) );
v3a.multiplyScalar( g.radius );
v3b.addVectors( g.pts[ i ], v3a );
g.attributes.position.setXYZ( idx ++, v3b.x, v3b.y, v3b.z );
}
}
```

*The idea is quite simple. From the tangent you calculate the normal and binormal. With this you have a system for the plane in space on which the circle lies.*

*Now you add to the vector of the center of the circle simply the radius vector for all angles of the circle according to the number of segments.*

*You get the radius vector by sin and cos in connection with normal and binormal.*

*In the formula above, this is nested and therefore difficult to see.*

```
// vector equation of circle in 3D space (component notation)
// c center, b binormal, n normal
x = cX + r * ( Math.cos( angle ) * bX + Math.sin( angle ) * nX );
y = cY + r * ( Math.cos( angle ) * bY + Math.sin( angle ) * nY );
z = cZ + r * ( Math.cos( angle ) * bZ + Math.sin( angle ) * nZ );
```

This is how I used it in my THREEf.js addon. THREEf.js/THREEf.js at 434de5be15e741b0dc3db29cb3fcd63f00d22809 · hofk/THREEf.js · GitHub line 1828 See Addon. Produces almost infinite many time-varying geometries with functions

You can find another variant there in the source code: https://hofk.de/main/discourse.threejs/2021/CirclesOnCurve/CirclesOnCurve.html

Sources

15-462 Graphics Project 2: Simulating a Roller Coaster via Splines - Camera Control Method

http://lolengine.net/blog/2013/09/21/picking-orthogonal-vector-combing-coconuts