What it does
Every builder returns a triangle soup: a flat array of vertices, each with a position, a normal and a uv. Curved
surfaces carry smooth normals, so they light as real 3D rather than faceted. You register a soup with
game.world3d.defineMesh(name, verts), or compose the pack and define a builder by name so world3d.mesh(name, opts)
and spawn({ mesh: name }) build it on first use. The 3D world makes its own meshes from these functions, and the
procedural model specs of model-3d build their forms from them.
There are two families. The primitives are unit-sized and scaled at spawn: boxes and rounded boxes, spheres,
cylinders, cones, capsules, tori, torus knots, wedges, planes, panels, discs, rings and the platonic solids, each with
its own segment counts, radii and an arc to cut a wedge out of anything round. The smooth forms are built at a real
size in metres, so a bend or a wall keeps its proportions: a lathe from a profile, a section swept along a path, a
hollow vessel with a fill level, a leaf with fold, curl and twist. Deformers squash, lobe, taper, twist, add noise and
bend; scatter helpers place copies over a surface, along a spiral, round a ring or packed in a volume; and a coat lays
icing, snow or slime over a surface with waves and drips.
For cutting, sliceByPlane cuts a closed mesh exactly and closes the cut face, holes and all, for a sliced fruit or a
cutaway. CSG gives union, subtract and intersect, with normals and uvs interpolated along the cut, so a drilled dimple
lights as a concave bowl. It is bake-time geometry: build the shape at load, register it, and no boolean runs during
play.
Features
- Twenty named primitives —
box,roundedBox,sphere,cylinder,cone,capsule,torus,torusKnot,wedge,plane,quad,panel,disc,ring, four platonic solids and more, each with its own settings. - Outline builders — lathe, tube, shape and extrude, with ear-clipping for flat outlines.
- Smooth forms —
latheForm,sweepForm(round, n-sided, star or custom sections, caps, twist, beads),vesselFormwith contents andleafForm. - Deformers — squash, lobes, taper, twist, noise and bend along a soup's height.
- Scattering — evenly over a surface, in rows by uv, along a spiral or a line, round a ring or packed in a sphere, cone, box, cylinder or bunch, then merged into one soup.
- Coating — a layer of given thickness over a surface, with waves, drips and a skirt where it ends.
- Plane slicing — an exact cut with the section closed from its own loops.
- Polyhedral dice — d4, d6, d8, d10, d12 and d20, chamfered, with each face's number in its uv.
- CSG — union, subtract and intersect, plus a fast
mergefor solids that do not touch.
Good for
- 3D games with no art pipeline, where furniture, props and pickups are built from rounded boxes, discs and lathes.
- Board and dice games, with real numbered dice and pieces turned on a lathe.
- Food and cooking games — sliced fruit, iced cakes with drips, glasses of juice filled to a level.
- Stylised nature — leaves, stems swept along curves and berries scattered in a bunch.
- Architecture and level props — windows cut out of walls, notches and engraving with CSG.
- Packs and tools that generate meshes, which can stand on the same builders.
Make it yours
Every primitive takes its own optional settings, and world3d.mesh caches one mesh per option set, so a 12-sided
cylinder and a 64-sided one are two meshes and the same options are one. Your own builders join the catalogue with
define. Smooth forms come back at a real size, and toUnitBox fits one into a unit box when one mesh should serve
many sizes.
Two quite different uses: a dice game that registers dieSoup(20, { chamfer: 0.04 }) once and textures the faces by
their uv numbers; and a dessert-shop game that lathes a cake, coats it with dripping icing, scatters sprinkles over the
top and slices it open with a plane, the cut face closed.
A quick look
A lathed vase that serves every size, and a chamfered d20:
import { latheForm, toUnitBox, dieSoup } from '@phaser-ae/geometry-3d';
const vase = latheForm([[0, 0], [0.12, 0.02], [0.18, 0.2], [0.08, 0.38], [0.1, 0.42]], { around: 32 });
game.world3d.defineMesh('vase', toUnitBox(vase)); // one mesh for vases of any size
game.world3d.defineMesh('d20', dieSoup(20, { chamfer: 0.04 }));
Works with
world-3d— registers the soups as meshes and builds its own from these functions.model-3d— procedural models (a banana, a glass of juice, a character) as specs built on these forms; usually the easier route for a whole object.core-3d— includes this pack, so most 3D games have it already.procgen— the source of the Perlin noise the deformers andgradientNoiseuse.model-files-3d— for models made in a modelling program rather than in code.
Good to know
- Builders return triangle soups, not indexed geometry: simple and fast to upload, but a sphere has more vertices than an indexed one would.
earCliphandles simple polygons, not holes or self-intersection;sliceByPlanecloses holed sections itself.- CSG is the classic BSP algorithm: right for clean, closed tools against a body, not a CAD kernel for self-intersecting meshes. Merge the tools and subtract once; many separate subtracts are slow.
- It is bake-time work: build at load, never per frame.






