A Three.js library that bends BufferGeometry along Bezier curves.
npm install flexy-bend
import * as flexy from 'flexy-bend';
import * as THREE from 'three';
const R = 3;
const curve = new THREE.CubicBezierCurve3(
new THREE.Vector3(R, 0, 0),
new THREE.Vector3(R, R * 0.55, 0),
new THREE.Vector3(R * 0.45, R, 0),
new THREE.Vector3(0, R, 0)
);
// A vector perpendicular to the plane the curve lies on.
// For a curve in the XY plane, this is the Z axis.
const orientation = new THREE.Vector3(0, 0, 1);
flexy.bend({
THREE,
curve,
orientation,
bufferGeometry: mesh.geometry,
axis: 'x', // the axis the geometry is elongated along
});Bends a BufferGeometry along a CubicBezierCurve3.
| Option | Type | Required | Description |
|---|---|---|---|
THREE |
Library | ✓ | Your THREE.js instance |
curve |
CubicBezierCurve3 |
✓ | The curve to bend along |
bufferGeometry |
BufferGeometry |
✓ | The geometry to deform |
axis |
'x' | 'y' | 'z' |
✓ | The axis the geometry is elongated along |
orientation |
Vector3 |
A vector perpendicular to the curve's plane | |
quaternion |
Quaternion |
Alternative to orientation |
|
mode |
'fit' | 'preserve' | 'tile' |
Controls how geometry length relates to curve length. Defaults to 'fit'. See below. |
|
orbit |
number |
Fractional shift along the curve. In 'preserve': shifts from center (0.5 toward end, -0.5 toward start). In 'tile': shifts the tiling start position. No effect in 'fit'. Defaults to 0. |
| Value | Behaviour |
|---|---|
'fit' |
The geometry is scaled (stretched or compressed) to exactly fill the full arc length of the curve. |
'preserve' |
The geometry keeps its world-space length. It is centered on the curve and shifted by orbit. t is clamped to [0, 1] — the geometry never bends past the curve endpoints. |
'tile' |
The geometry keeps its world-space length. When the geometry is longer than the curve, t wraps with modulo so the curve pattern repeats across the excess. orbit shifts the tiling start position. |
Raycasts a uniform grid from a rectangular region onto a mesh surface, returning a hashmap from grid points to { normal, point } pairs on the surface. Used as input for wrap().
Conforms a geometry to a curved surface by looking up the face normal at each vertex's projected position and rotating the vertex to align with it.
Applies a Gaussian shear deformation centered at the midpoint of the geometry. Within each cross-section, vertices are displaced along shearAxis in proportion to their distance from the shear-axis center, with a bell-curve falloff from the geometry's center toward its ends.
| Option | Type | Required | Description |
|---|---|---|---|
THREE |
Library | ✓ | Your THREE.js instance |
bufferGeometry |
BufferGeometry |
✓ | The geometry to deform |
amplitude |
number |
✓ | Maximum displacement at the center cross-section |
axis |
'x' | 'y' | 'z' |
The elongation axis. Defaults to 'x' |
|
shearAxis |
'x' | 'y' | 'z' |
The displacement axis (must differ from axis). Defaults to 'z' |
|
sigma |
number |
Gaussian spread in world units. Defaults to geometryLength / 4 |
Applies an arbitrary scalar displacement to a subset of vertices selected by a predicate. The displacement function receives the two coordinates in the plane perpendicular to the displacement axis.
| Option | Type | Required | Description |
|---|---|---|---|
THREE |
Library | ✓ | Your THREE.js instance |
bufferGeometry |
BufferGeometry |
✓ | The geometry to deform |
predicate |
(x, y, z) => boolean |
✓ | Selects which vertices to affect |
fn |
(u, v) => number |
✓ | Returns the displacement amount. For axis='y': fn(x, z); axis='x': fn(y, z); axis='z': fn(x, y) |
axis |
'x' | 'y' | 'z' |
The displacement axis. Defaults to 'y' |
Each coordinate on the bend axis is mapped to a parameter t ∈ [0, 1] on the curve. The leftmost vertices map to t = 0, the rightmost to t = 1.
For each tangent, compute a perpendicular vector (shown in purple) using the cross product with the reference normal.
The orthogonal is rotated around the tangent axis by the angle atan2(z, y) — the angle the original vertex makes in the cross-section plane.
The resulting rotated vectors:
Each rotated vector is scaled to match the original vertex's distance from the bend axis.
The new vertex position is curvePoint(t) + scaledOrthogonal.
The relationship between the curve and the bent geometry:
npm run dev # start dev server at localhost:5151
npm run build # build the library (dist/) and demo site (docs/)








