I wanted a box generator that ran entirely in the browser. No slicer plugins, no OpenSCAD compile times, no Python dependencies. Just a URL that gives you a 3D-printable STL. The live demo is here.
BOX3D is a parametric geometry engine built with React, Three.js, and Vite. It generates Gridfinity-compatible storage bins in real time, with spec-accurate foot profiles, magnet pockets, stacking lips, and configurable compartment walls. Everything is procedural, no imported meshes.
Gridfinity is an open-source modular storage system designed by Zack Freedman. The idea is simple: a baseplate with a 42mm grid, and bins with standardized feet that snap into it. The system works because the spec is tight. Feet have a specific stepped profile. Lips have a matching inverse. Bins stack. Everything interlocks.
The problem is that everyone needs slightly different bin dimensions. You want a 2x3 bin with a 15mm-tall compartment for resistors. Or a 1x4 with dividers for drill bits. Parametric generation means you describe what you want and the geometry follows. No manual modeling per variant.
Most parametric Gridfinity tools use OpenSCAD or FreeCAD macros. These work, but the feedback loop is slow. Change a parameter, wait for a CSG recompute, export, slice. I wanted something where you drag a slider and see the bin update instantly.
Every shape in BOX3D is built from one primitive: the rounded rectangle ring. A function generates points around a rectangle's perimeter with radiused corners, parameterized by width, depth, fillet radius, and corner segment count. Stacking multiple rings at different Y-heights and connecting them with triangle strips gives you any revolved-ish profile.
The Gridfinity foot, for example, is four rings:
Connecting adjacent rings produces the stepped profile. Top and bottom caps are triangulated separately. The same approach builds the stacking lip, which is the inverse of this profile: an outer vertical wall with an inner stepped cavity that receives the foot of a stacking bin above.
Box walls use a different strategy: extruded shapes with rectangular holes punched out. The outer rectangle minus the inner rectangle gives the wall cross-section, extruded along Y. This is cheaper than the ring approach for simple prismatic shapes and avoids wasting triangles on flat surfaces.
Early on, I hit a class of bugs that all had the same root cause: floating point accumulation. You set a dimension to 42mm, switch to inches and back, and now it's 41.9999mm. You do arithmetic on grid-snapped values and they drift off-grid. Tolerances that should be 0.5mm come out as 0.4999997mm. None of these are individually catastrophic, but they compound. Geometry that should be watertight develops hairline gaps.
The fix was to store all dimensions in fixed-point internal units (IU). The scale is 100,000 IU per millimeter, giving 10-nanometer precision. One inch is exactly 2,540,000 IU. Unit conversion becomes integer multiplication with a single Math.round() at the boundary. Internally, everything is exact.
The tradeoff is verbosity. Instead of config.wall = 2.0, you write config.wall = initMm(2.0) and convert back with toScene(wall_IU) before handing values to Three.js. Every dimension goes through this pipeline. It's boilerplate, but it eliminated an entire category of bugs. I stopped chasing phantom gaps.
A Gridfinity bin is a vertical stack of features: feet, floor, walls, shoulder, lip. Each feature's vertical position depends on the one below it. The layout engine computes this by maintaining a Y-cursor that starts at zero and advances upward as each layer is placed.
The cursor logic looks like:
gridHeight * 7mm, so wall height = total - feet - floor. In freeform mode, it's directly specified.
Each step records its yMin and yMax in a stack object. The geometry pass reads these bounds and builds meshes to fit. This separation (layout computation vs. geometry generation) means validation can happen before any triangles are created. If the wall height would be negative (floor too thick for the specified total height), the engine reports an error without crashing the renderer.
The cursor approach also makes external vs. internal dimensioning straightforward. In external mode, you work backward: subtract lid, subtract floor, whatever's left is wall. In internal mode, wall height is specified directly and total height is the sum. Same engine, same cursor, just different input ordering.
Gridfinity feet have magnet pockets (6mm diameter, 2.4mm deep) and optional screw holes (2.4mm diameter, through the full foot height). These are subtractive features, material removed from the foot body. Real CSG would be expensive for a real-time preview, so I fake it.
The bottom cap of the foot is generated as a ShapeGeometry with circular holes punched into it. Three.js's shape system supports holes natively. You define a Path for each pocket and add it to shape.holes. The triangulator handles the rest.
For the pocket interiors, I manually construct tube geometry: a ring of vertices at the pocket mouth, another ring at the pocket floor, connected by quads with reversed winding (normals face inward, since you're looking into a hole). An annular floor caps the bottom of the magnet pocket. If there's a screw hole, the annular cap has a smaller hole in it, and a second tube continues through to the top of the foot.
It's not true CSG. There's no BSP tree, no polygon splitting. But the visual result is identical for cylindrical pockets cut into flat faces, which is all we need here. The geometry is watertight and exports cleanly to STL.
The compartment system lets you place internal dividers on a per-segment basis. In a 3x2 Gridfinity bin, each internal grid line has multiple segments you can independently toggle. You can have a wall that spans only one cell of a grid line, creating L-shaped or T-shaped compartments.
The editor is a top-down SVG view of the bin's grid. Mouse proximity detection finds the nearest grid line segment and highlights it. Clicking toggles a wall. The wall state is just an array of {axis, pos, seg} objects: which grid line, which segment.
In the geometry pass, each wall becomes a BoxGeometry positioned at the appropriate grid line, spanning exactly one cell in the perpendicular direction. Wall thickness matches the bin's outer wall parameter. Height spans from floor top to wall top (read from the layout stack).
One subtlety: walls auto-prune on resize. If you have dividers in a 3x3 bin and shrink it to 2x2, walls that reference out-of-bounds grid positions are silently removed. This happens in a useEffect that watches the grid dimensions. Without it, you'd get phantom geometry or crashes from placing walls outside the bin bounds.
The whole thing is a single JSX file. No build-time mesh generation, no server, no external geometry libraries beyond Three.js itself. The STL export traverses the scene graph, collects triangles, and writes ASCII STL with millimeter units. The geometry adheres to the Gridfinity spec (tested numerically), but physical printing hasn't been verified yet. If you have access to a printer, I'd love to hear how the parts fit.