What it is
A made-to-order shelving configurator for Rackwise Industrial, a fictional maker of steel modular shelving. A buyer sets the run (bays, bay width, height, depth, levels, load per level), the duty class, the finish and add-ons, sees the rack rebuilt in 3D, gets engineering checks with one-click fixes, a bill of materials and an instant quote, then prints the quote, downloads the BOM as CSV, shares a link or sends a demo request. It ends in a quote, not a cart, the way B2B manufacturing sales work. All prices are illustrative.
Engineering decisions
- The rules, BOM and pricing live in a pure TypeScript
core/ folder with no Three.js or React: config.ts (options, catalogue, presets, share code), rules.ts (beam capacity by class and span, frame capacity, level spacing, height-to-depth stability with wall ties or back bracing, castor and drawer limits, auto-fix), bom.ts (part codes, quantities, weights, prices, CSV) and quote.ts (parts, powder coat, volume discount tiers, assembly from fitting minutes, delivery by zone and weight, VAT, lead time). Vitest covers them, including a sweep that proves auto-fix always reaches a valid rack. - The capacity rules are deliberately simple and labelled illustrative: beam ratings fall in proportion to span, the most loaded frame carries one bay, and a run taller than four times its depth needs anchoring (eight times at most).
- There is no model file. The rack is built in code from the same counts as the BOM: C-profile uprights with teardrop slots on the face and bracing holes on the flanges (alpha-tested canvas masks tiled at the real 50 mm pitch), lipped-channel frame bracing with bolt heads, base plates with wedge anchors or braked castors, extruded step beams with connector plates and red lock pins, ribbed deck panels sitting in the beam step, and add-ons (back mesh, wire dividers, drawer units, hazard-striped end guards, wall ties against a wall, X back bracing, location labels and end signs). Stock is seeded per configuration: cartons, coloured bins on light duty, wrapped pallets on tall heavy levels.
- Every part type is one instanced mesh, so a six-bay, eight-level run stays at a few dozen draw calls. Each instance stores an explode offset; the exploded view moves instances without rebuilding geometry.
- Location labels are one merged mesh over a single canvas atlas, so dozens of unique codes cost one texture and one draw call.
- Clicking the model raycasts to the part, skipping see-through texels of the perforated and mesh parts, and opens its BOM line. Clicking a BOM row highlights the parts in the model.
- The whole configuration is in the address hash in readable form, so a link restores it. The quote sheet is a print-only section with a snapshot of the current view; "Quote PDF" uses the browser's print to PDF.
Performance
- Rendering is on demand: frames are drawn only when the camera glides, the explode eases or a part pulses, and the loop stops while the page is hidden or the viewer is off screen.
- The light tier drops antialiasing, shadows and bevels, uses fewer segments and a lower pixel ratio.