Helix
helix() creates a helical wire — the curve that springs, threads, and coils are built from. On its own it renders as a wire; pair it with sweep() to turn it into a solid.
import { helix } from 'fluidcad/core';
helix("z").radius(15).pitch(10).turns(4);

The argument is the axis to coil around — a named axis like "z", anything axis-like, or an existing scene object (see deriving from geometry below).
Sizing
Three chained methods control the proportions, and any two determine the third:
helix("z").pitch(10).turns(4) // height = 40
helix("z").pitch(10).height(40) // turns = 4
helix("z").turns(4).height(40) // pitch = 10
.pitch(p)— axial rise per full revolution..turns(n)— number of revolutions; fractional values are fine..height(h)— total axial extent.
Unset values fall back to sensible defaults: turns defaults to 1, radius to 20, and height to 50 (or pitch × turns when a pitch is given).
Springs
Sweep a small profile along the helix to get a spring. The profile is positioned at the path start automatically:
import { sketch, circle, hMove, helix, sweep } from 'fluidcad/core';
const path = helix("z").radius(15).pitch(10).turns(5);
const profile = sketch("left", () => {
hMove(15);
circle(2);
});
sweep(path, profile);

Deriving from geometry
Instead of an axis, pass a scene object and the helix takes its frame from the geometry:
- Cylindrical face — axis, radius, and height come from the face.
- Conical face — the helix follows the cone's taper; radii are derived from the face geometry (
.radius()/.endRadius()are ignored). - Line edge — the line becomes the axis, its length the height.
- Circular edge — the circle's normal becomes the axis, its radius the helix radius.
import { cylinder, select, helix } from 'fluidcad/core';
import { face } from 'fluidcad/filters';
cylinder(15, 60);
helix(select(face().cylinder())).turns(6);

Use select(...) to narrow a body down to the single face or edge the helix should read from.
Threads and grooves
A helix at the surface of a cylinder is the spine of a thread. Sweep a profile along it and the result fuses with the cylinder (the default for boolean operations):
import { cylinder, sketch, move, circle, helix, sweep } from 'fluidcad/core';
cylinder(15, 50);
const path = helix("z").height(50).radius(15).pitch(5)
.startOffset(-5).endOffset(5);
const profile = sketch("left", () => {
move([15, 0]);
circle(3);
});
sweep(path, profile);

Chain .remove() on the sweep to carve a groove instead:
import { cylinder, sketch, move, circle, helix, sweep } from 'fluidcad/core';
cylinder(15, 50);
const path = helix("z").height(50).radius(15).pitch(5)
.startOffset(-5).endOffset(5);
const profile = sketch("left", () => {
move([15, 0]);
circle(3);
});
sweep(path, profile).remove();

Running past the ends
Real threads run off the ends of the stock rather than stopping flush. .startOffset() and .endOffset() shift the helix ends along the axis, in axial mm:
helix("z").height(50).startOffset(-5).endOffset(5) // 5mm overshoot each side
A negative start offset extends the start; a positive end offset extends the end (and vice versa to trim). On a conical face the extension follows the cone's natural taper.
Tapered helixes
When .endRadius() differs from .radius(), the radius blends linearly along the height — a conical helix:
import { sketch, circle, hMove, helix, sweep } from 'fluidcad/core';
const path = helix("z").height(60).pitch(10).radius(25).endRadius(10);
const profile = sketch("left", () => {
hMove(25);
circle(2);
});
sweep(path, profile);

The same shape falls out automatically when the source is a conical face. .endRadius() is ignored for face and circular-edge sources, where the radii come from the geometry.
Limitations
- Turns must be positive and the pitch non-zero; a tapered helix must keep its end radius above zero.
- A face source must be cylindrical or conical; an edge source must be a line or a circle. Multi-shape sources need a
select(...)to single out one face or edge.