Skip to content

Repository files navigation

Video.mp4

⚡ zapim

Instant 3D-printable enclosures for your electronics projects — built for the Zoo.dev API Makeathon.

Every IoT project ends the same way: a beautiful circuit… zip-tied to a shelf, or entombed in a gutted Tupperware. Real enclosure design means hours in CAD measuring port positions with calipers. zapim turns "Raspberry Pi 4 + screw-down lid + side vents" into a print-ready case + lid in about a minute — port cutouts, standoffs, screw bosses and all.

An exploded view of a generated enclosure: printed case with port cutouts, vent slots, corner screw bosses and standoffs, its lid floating above on four M3 screws, and the ghosted Raspberry Pi, motor driver and wire harness inside

Actual engine output for a Pi 4B + L298N build — 160.4 × 73.2 × 42 mm, 97.4 cm³, ≈121 g of PLA for both parts. The app's front page walks through the whole workflow with screenshots; npm run dev and open http://localhost:3000.

How it works

board preset ─┐
options ──────┤→ resolver (TS) → KCL source ─→ offline validation ─→ Zoo Design API engine ─→ STL/STEP/GLB/OBJ
              │        (all geometry math)      (kcl-wasm-lib:          (via the zoo CLI)         + 3D preview
custom cuts ──┘                                  parse + mock-exec)                               + volume→grams

The generated KCL is a first-class artifact — commented, parameterized, and openable in Zoo Design Studio to keep designing by hand where zapim leaves off.

Zoo platform usage

Zoo tech Where zapim uses it
KCL every enclosure is emitted as clean, parametric KCL (modern keyword-arg dialect)
Design API engine geometry is built server-side via zoo kcl export (Design API under the hood)
kcl-wasm-lib offline parse + mock-execution validates every model before spending engine time
Text-to-CAD API (/ai/text-to-cad?kcl=true) the /ai lab generates companion parts (knobs, brackets, mounts) with KCL source
Iteration API (/ml/text-to-cad/iteration) the ✨ AI-edit bar prompt-edits the current enclosure's KCL ("honeycomb vents on the lid")
File API (/file/volume) material volume → filament grams per build

Quickstart

npm install
npm run setup:zoo        # downloads the zoo CLI binary for your platform into ./bin
cp .env.example .env.local   # then paste your token from https://zoo.dev/account/api-tokens
npm run dev              # → http://localhost:3000

The designer and live KCL preview work with no setup at all; Generate / downloads / AI modes need the token + CLI. (You can also paste a token in the in-app Setup panel instead of using .env.local.) The env var must be spelled exactly ZOO_API_TOKEN/api/health reports tokenConfigured: false if the app can't find it:

curl -s localhost:3000/api/health
# {"tokenConfigured":true,"cli":{"found":true,"version":"zoo 0.2.170"},"wasmOk":true}

The workflow, in three pictures

The app's front page is a full screenshot-led tour of all six steps — this is the short version.

1 · Lay it out. Pick a board and the box auto-sizes around it; drop in companion modules, drag them around the cavity floor, then click two terminal dots to wire them. A router paths every wire around standoffs and bosses, bundles them into corridors, and reports the jumper lengths to order.

Floor plan with a Raspberry Pi 4B and an L298N motor driver connected by four routed, colour-coded wires, and the Wiring panel listing each net with its pins and jumper length

2 · Build it. ⚡ Generate validates offline in milliseconds, then the Zoo engine builds watertight geometry in 15–60 s. Four view modes; Simulated x-rays the shell so you can inspect the harness inside the case before committing four hours of printer time.

Simulated view: the printed case rendered translucent so the ghosted Raspberry Pi, L298N, standoffs and zip-tie saddle are visible, with the wire harness routed across the cavity floor

3 · Keep the source. Every design is commented, parameterized KCL — hardware shopping list and wiring totals in the header, tunable parameters at the top, every cutout labeled. Download it and keep designing in Zoo Design Studio.

The KCL code tab showing generated, commented KCL: header comments naming the board, hardware and wiring totals, then a parameters block and a rounded-rectangle helper function

Documentation

Doc What's in it
Setup guide detailed install, token & CLI options, health checks, and a troubleshooting decoder ring for every error code
User guide every control explained + seven start-to-finish recipes (Pi case, wired motor driver, custom modules, fit-test-first workflow, AI edits…)
Architecture the config → resolver → KCL → validate → engine pipeline, the wire router's A*, the viewer's plate-split math, and the decisions we'd defend at a whiteboard
Zoo platform field notes 17 actionable bug reports & API suggestions for the Zoo team — engine boolean limits, hung sessions, ML job realities — each with repro shape, shipped workaround, and proposed fix
Roadmap shipped features with scoping notes, and the honest menu of what's next

Features

  • 21 board presets — Raspberry Pi 5 / 4B / 3B+ / Zero 2 W / Pico, Arduino Uno R3 & R4 / Leonardo / Mega 2560 / Nano / Nano Every / MKR, ESP32 DevKitC & DevKit V1, NodeMCU ESP8266, Seeed XIAO, Teensy 4.0 / 4.1, STM32 Black Pill, Adafruit Feather, Wemos D1 Mini — with real dimensions, mounting holes and port positions (plus a no-board parametric box mode)
  • Custom modules for everything non-standard (motor drivers, buck converters, the whole Elegoo sensor drawer): a sketch-style editor sets the bounding box and mounting holes — click to add, drag to place, snap-to-grid, quick patterns — with per-module mount style (standoffs / tray / none) and standoff height. Modules save to a personal library; presets included (L298N, LM2596, MB102, relay, generic sensor)
  • Floor-plan tab: drag the board and modules around the cavity, rotate in 90° steps, and watch the auto-sized box re-fit live; overlap and out-of-bounds turn red, and the box height follows the tallest item
  • Boards and modules without mounting holes get tray-mount retainer posts automatically
  • Port cutouts auto-placed from board data, each with its own clearance margin; board rotation remaps everything
  • Screw-down lid (corner bosses, pilot holes, lip notches, hardware callouts) or slip-fit lid; vents per wall or lid (auto-dodging ports); custom rect/circle cutouts; wall-mount tabs
  • Cutout part presets — PG7/PG9 cable glands, KCD1 rocker, 16mm pushbutton, MTS-102 toggle, USB-C plug pass-through, SMA bulkhead, 5.5×2.1 barrel jack, 0.96" OLED window — drop in centered with the manufacturer's recommended opening, no datasheet digging
  • Shareable design links — the whole config lives deflate-compressed in a versioned URL hash: refresh restores your work, and 🔗 Share copies a link that reopens the exact design anywhere (npm run test:share proves the codec headlessly)
  • AI quick-edit chips — five curated one-click prompts (honeycomb lid, rounded edges, cable channel, zip-tie slots, foot recesses) through the Zoo iteration API, with the validate-before-render guard still in the loop
  • 🔌 Wiring routing + animation — boards and modules carry real connection terminals (full 40-pin GPIO maps for every 40-pin Pi — 5, 4B, 3B+, Zero 2 W — plus the Pico; module presets named after their silkscreen, plus a terminals tool in the module sketch editor). Click two terminal dots on the floor plan to draw a logical net ("GPIO4 → sensor DATA"); a Manhattan-ish router paths every wire across the cavity floor — dodging standoffs and screw bosses, hopping over crossings, bundling into shared corridors — and the 3D view renders the harness as colored tubes (5V red, GND black) with an animated current pulse. Where routes bundle, zapim prints zip-tie saddles into the case KCL — the wiring designs part of the enclosure — and reports per-wire lengths with standard jumper sizes. Harness height is wired into auto-size: the cavity grows for headroom (or warns in manual mode). npm run test:wiring proves the router invariants headlessly
  • 🎫 Fit-test coupon — one click crops a slice of one wall (real openings, real wall thickness, one real standoff at its true distance, the real lid lip) and builds that instead. Check the USB-C lines up on a short print instead of finding out four hours in. Opening sizes, heights above the floor and along-wall spacing are bit-identical to the full case — npm run test:coupon asserts exactly that, then parses all ten sample coupons
  • Both parts lie flat on one plate — no supports, FDM-friendly
  • Print plate / Simulated / Assembled / Exploded views: the viewer splits the exported plate into case + lid client-side, animates the lid flipping onto the case, shows translucent ghost boards/modules at their real heights, and floats the lid screws in exploded view — and Simulated x-rays the shell and fades the lid away so the pulsing wire harness is the star (npm run test:assembly proves the transform math headlessly)
  • Live, syntax-highlighted KCL with hand-edit mode; downloads: STL · STEP · OBJ · GLB · KCL

Validation without burning credits

npm run test:kcl generates 50 enclosure variants (every board × lid style + kitchen-sink, module and wiring-saddle cases) and runs each through the real KCL interpreter (@kittycad/kcl-wasm-lib in mock-execution mode) — syntax errors, deprecations and semantic errors fail CI without ever touching the network. The same validation guards the /api/generate route, so bad KCL is rejected in milliseconds instead of engine-minutes.

The zoo CLI is pinned to v0.2.170 (scripts/setup-zoo-cli.mjs) so the executor speaks exactly the same KCL as the bundled validator. Override with ZOO_CLI_VERSION=latest npm run setup:zoo at your own risk.

Engine lessons (paid for in credits so you don't have to)

Geometry that mock-executes fine can still be rejected by the real engine. The short version below; the full write-up — 17 structured bug reports and API suggestions with repro shapes and proposed fixes — is in docs/zoo-api-notes.md. zapim's emitter works around rules discovered the hard way:

  • Union two bodies at a time. union([a, b, c, …]) with many solids fails with "Batch edit result is not valid" — so same-height posts are merged into one multi-profile extrude and solids are folded in pairwise.
  • Never leave boolean faces exactly coplanar with body faces. Boss tops flush with the case rim, or subtract tools whose caps sit exactly on a surface, fail with "cannot handle this 3D subtraction yet" — everything is embedded or sunk by 0.15–0.5 mm instead (which is also why mount tabs ship as a separate 1 mm-overlapping body that slicers merge).
  • Chunk big subtracts. Dozens of cutout tools in one subtract call fail the same way — the emitter cuts in batches of 8.
  • Tools must not overlap each other. Vent slots automatically skip any span already claimed by a port or custom cutout.
  • Engine sessions sometimes hang. ~1 in 4 exports during our matrix run simply never returned; the server retries once with a fresh session automatically.

All 20 variants of the 2026-07-24 matrix build successfully on the live engine (the heaviest case — rotated Pi 4B, 30 cutouts, vents, tabs — takes ~55 s). Since then the wired case with a printed zip-tie saddle — the design in the front-page tour — earned its own engine receipt on 2026-08-04. Boards added after the matrix run are offline-validated only: same emitter, same invariants, no engine receipt yet.

Project structure

lib/enclosure/boards.ts         board database (dims, holes, ports)
lib/enclosure/config.ts         config types + resolver — all geometry math, in plain testable TS
lib/enclosure/cutoutPresets.ts  named panel-opening presets for common parts
lib/enclosure/kclgen.ts         KCL emitter (resolved primitives → commented KCL)
lib/enclosure/coupon.ts         fit-test coupon — crops a resolved enclosure to one wall
lib/enclosure/wiring.ts         terminals + nets → floor-routed wires, lengths & zip-tie saddles
lib/enclosure/validate.ts       offline parse + mock-exec via kcl-wasm-lib
lib/client/share.ts             design-link codec (config ⇄ versioned, compressed URL hash)
lib/zoo.ts                      zoo CLI runner + REST (text-to-cad, iteration, volume)
app/api/*                       generate | text-to-cad | iterate | health
app/design                      the designer (config panels, 3D preview, KCL tab, AI edit)
app/ai                          Text-to-CAD lab
scripts/                        setup-zoo-cli.mjs · validate-kcl.ts · test-assembly.ts
                                test-share.ts · test-coupon.ts · test-wiring.ts
docs/                           setup · user guide · architecture · Zoo API field notes

Honest limitations

  • Board port positions come from published mechanical drawings — verify against your actual board before printing (margins default to 1.5 mm to forgive small errors).
  • Filament estimate is solid-volume; real prints use less (infill) plus a bit more (walls/brims).
  • Screw-lid corner bosses need ~6 mm side clearance — auto-size accounts for this.
  • The /ai Text-to-CAD lab currently shows no 3D preview. Since 2026-08-04, POST /ai/text-to-cad/{format}?kcl=true returns completed with good KCL but an empty outputs map — no mesh to render. The KCL is still returned and downloadable; the enclosure pipeline (Design API engine) and the ✨ AI edit bar are unaffected. Repro and suggested fix: ZAP-17.

License

zapim is released under the MIT License — see LICENSE. The enclosures it generates are yours; the emitted KCL carries no strings either, so take it into Zoo Design Studio and keep going.

The zoo CLI that npm run setup:zoo downloads is Zoo's own binary (never vendored into this repo), and npm dependencies keep their respective licenses.


zapim — Zoo.dev API Makeathon 2026. Case closed. 📦

About

Microcontroller and electronics enclosure generator, 2nd place winner of zoo.dev API makeathon

Topics

Resources

Stars

4 stars

Watchers

1 watching

Forks

Contributors

Languages