Operations

Standalone functions for combining and manipulating meshes.

merge

Combine multiple meshes into one. Automatically normalizes attributes (colors, UVs, normals) and handles mixed indexed/non-indexed geometry.

import { merge, box, sphere } from 'shapecraft'

const combined = merge(
  box().translate(-1, 0, 0),
  sphere().translate(1, 0, 0),
)

center

Recenter a mesh’s bounding box to the origin.

import { center } from 'shapecraft'
const centered = center(mesh)

clone

Deep copy a mesh.

import { clone } from 'shapecraft'
const copy = clone(mesh)

loft, tube & thicken

loft

Sweep a 2D cross-section along a 3D path. The cross-section is oriented using rotation-minimizing frames (or a fixed up vector).

import { loft } from 'shapecraft'

// Fixed cross-section
loft({
  path: [[0,0,0], [0,1,0], [0.5,2,0]],
  shape: [[-0.1,0], [0.1,0], [0,0.1]],
})

// Varying cross-section (tapered leaf shape)
loft({
  path: frondPath,
  shape: (t) => {
    const w = 0.3 * (1 - t)
    return [[-w, 0], [0, w*0.3], [w, 0]]
  },
  closedShape: false,  // open cross-section (no bottom)
  closed: false,       // no end caps
  up: [0, 1, 0],       // keep cross-section aligned to world up
})

Options:

  • shape[x,y][] or (t: number) => [x,y][] for varying along path
  • closed — cap the ends (default true)
  • closedShape — connect last shape point to first (default true)
  • up — reference up vector for consistent orientation (default: auto)

tube

Shorthand for circular loft — sweep a radius along a path. Great for branches, vines, trunks.

import { tube } from 'shapecraft'

// Fixed radius
tube([[0,0,0], [0,1,0], [0.3,2,0]], 0.05, 6)

// Tapered — radius function of t (0-1 along path)
tube(path, (t) => 0.1 * (1 - t), 6)

// Palm trunk with bulge waves
tube(path, (t) => {
  const taper = 0.1 * (1 - t * 0.6)
  const wave = 1 + Math.sin(t * Math.PI * 14) * 0.15
  return taper * wave
}, 5)

thicken

Give a flat mesh depth by duplicating it, offsetting along normals, and stitching boundary edges. Works best with indexed geometry (e.g. from loft).

import { thicken } from 'shapecraft'

const leaf = thicken(flatLeafMesh, 0.02)
shapecraft