Types - Surface
API reference for ./geometry/surface on @huukhanhnguyen/types.
See the Guide for the package's role.
API reference
Signatures are generated from the live package .d.ts - not hand-written.
NurbsSurface
type
type NurbsSurface
// = {
degreeU: number;
degreeV: number;
knotsU: number[];
knotsV: number[];
controlPoints: Point[][];
weights: number[][];
}PlaneSurface
type
A plane, given as its implicit equation plus the finite window it is used over.
type PlaneSurface
// = {
normal: Vector;
/** The plane's implicit constant: the surface is `normal · p = d`. */
d: number;
/** Lower-left corner of the finite rectangle in surface UV. */
uvMin: Point2d;
/** Upper-right corner of the finite rectangle in surface UV. */
uvMax: Point2d;
}RevolveSurface
type
A profile curve swept about an axis.
u is ALWAYS the ANGLE and v is ALWAYS the profile — there is no transpose flag (Rhino's ON_RevSurface carries m_bTransposed; a swap flag is a second way to say the same surface, so it is not here). The profile owns its own parameter domain, so there is no separate profile-range field either.
This is the OPPOSITE of Rhino's ON_RevSurface, which puts the profile on u. Do not "fix" it back after reading that reference — the order here was verified against this kernel rather than imported: a cylinder(2, 5) reports uMin 0, uMax 2π, vMin 0, vMax 5, and a sphere(2) reports uMin 0, uMax 2π, vMin -π/2, vMax π/2. u sweeps, v runs along the profile. Every analytic carrier agrees, and operations/revolve.rs transposes the general construction to match. A face's uv curves live in that exact uv, so swapping the order would silently invalidate every uv curve on every revolve face.
Revolution earns a kind of its own where extrusion does not, and the reason is the parametrization rather than the shape: a linear extrusion's sweep parameter is a distance, which NURBS preserves exactly, so an extrusion is already exactly a NURBS surface and needs no kind. Revolution's sweep parameter is an ANGLE, and NURBS turns an angle into a Möbius reparametrization — so a NURBS carrier holds the same POINTS but no longer the same meaning, and the angle has to be stated to survive.
An arbitrary-profile revolve is EXPRESSIBLE here but only the four NAMED forms are produced — do not read this type as a general capability. Measured 2026-08-09 after the emission pass: surface_to_json writes a revolve row for any form-tagged cylinder/cone/sphere/torus whose NURBS base is the canonical form layout (the gate is the same agreement check form recovery uses), spelled exactly as the revolveFrom* builders below spell it so the loader's revolve_form folds it back into the same named form — brep_cylinder(2,5) → {"revolve":1,"nurbs":2} (the nurbs rows are the caps' bilinear plane forms), brep_sphere(2) → {"revolve":1}, brep_box(4,4,4) → {"nurbs":6}, box − cylinder → revolve walls plus plane-form nurbs. Two cases keep the NURBS row: a reparametrized base (an extruded-circle wall), because the rebuilt canonical carrier would move its uv curves' uv, and a form whose (xAxis, yAxis) frame is LEFT-handed about the axis (an opposite-wound hole wall), because the sign carries the winding and a revolve row cannot state it — the loader always rebuilds yAxis = axis × xAxis. A GENERAL profile (a non-analytic sweep) has no named form to emit from and also crosses as NURBS.
A general-profile emission would need profile recognition at the writer or a general revolve variant on NurbsSurfaceForm, which has only the five NAMED forms — the 182 match arms this fold deliberately left alone.
What the fold DID buy: vRange and xAxis/yAxis stopped being separately stated fields that can disagree with the parametrization — the profile's own extent is the v range and its position is the seam, so that invalid state is now unrepresentable.
type RevolveSurface
// = {
profile: Curve;
/**
* The axis swept about — the oriented infinite line of {@link Axis}.
* Reversing `direction` gives a different axis and therefore the opposite
* sweep sense, which is exactly what makes an axis able to carry
* orientation.
*/
axis: Axis;
/** Sweep interval in radians. `[0, 2 * Math.PI]` is a full turn. */
angle: [number, number];
}