From CAD to the Browser: Designing a Modular Wireless Node

How I designed the Vigil Node's enclosure as code: parametric FreeCAD driven by scripts, interference and motion checks written as assertions, honest labels, and a mesh pipeline from STEP files to three.js.

Tom Wade

9/24/20266 min read

Software engineers get tests almost for free: change a function, run the suite, and you know whether you broke something. Mechanical design has no such habit by default. You change a dimension, look at the model and decide it looks right. For the Vigil Node's enclosure I wanted the software habit, so every revision ends in a file of checks the geometry has to pass, and the checks are part of the design.

This post covers the problem the node solves, how the enclosure was designed as code, what the checks caught, and how the same CAD ends up as an interactive 3D model on continuislabs.com. Everything here is CAD and rendering. No enclosure has been through physical testing yet, and I'll say so wherever it matters.

The problem

On most infrastructure the sensor is the cheap part. Getting it onto a girder, a dam face, a pipe rack or a stay cable is what costs money: scaffolding, rope access, lane closures, an electrician's day. And servicing it means doing all of that again.

So the node is designed around installation. A mount is fitted once and stays on the structure. The node lowers into the mount's dock and turns 24°, three ball detents click home, and a cam draws it down tight. To service it, you twist it off and twist a spare on. There are five mounts:

  • Steel: a plate bonded to the steel with structural tape, with four flush bolts holding the dock. No drilling, no welding.

  • Concrete: a flange with two wedge anchors 120 mm apart, placed so the installer's tools clear the twist.

  • Timber: the same flange with two lag screws.

  • Pipes and cables: a lined saddle and two metal bands, for pipes up to 12 inches across and for stay cables and hangers.

The node itself is a sealed 60 mm housing with an interchangeable probe on top. Its design targets are IP67 and a 20 lb load. They're targets, and they won't be called ratings until they've been tested.

Designing the enclosure as code

The CAD is FreeCAD, an open-source parametric modeller with a full Python API over the OpenCASCADE geometry kernel. I chose it for exactly that API. The model is built and changed by 27 Python scripts, each one a design step: the keyed lock, the ball detent, service access, the modular split, the mounts, the printable roof. An AI agent ran them through an MCP server connected to FreeCAD, and I reviewed each step on screen before the next one.

Revision 5 has 111 sketches, every one fully constrained, so no dimension is left to chance when a parameter changes, and its STEP export contains 87 solids. Each revision ends by writing a checks file. The checks that matter most:

  • Every body is one valid solid. A single bad boolean operation can quietly produce geometry that a printer or a machinist can't use.

  • Nothing overlaps. The intersection volume of every pair of parts must be zero: the housing and the connector carrier, every O-ring in its groove, every mount, every bolt, and each mount against its substrate (the pipe, the cable).

  • The motion works. The node is posed along its path, lowered in steps and then twisted through the 24° in 4° steps, and at every pose its intersection with the dock must be zero. Then the opposite assertion: at the two wrong orientations, 120° and 240° round, the interference must be non-zero (11.3 mm³), so the node can only go on one way. Turning past the end is blocked too.

  • The seal is right. The O-rings have a 2 mm cross-section at a nominal 25% squeeze and 78% gland fill, and the groove is probed every 15° around its circumference to prove it's continuous and empty.

  • It can be printed. Minimum wall thicknesses (3.2 mm on the side panels), 45° roofs over openings for FDM printing in PETG or ASA, and 48 probes showing the dock never breaks through the 3.2 mm floor under the electronics.

  • The steel mount holds, on paper. Its bonded area (about 57,300 mm²) is checked against the area the 20 lb target calls for (about 51,600 mm²).

The checks file is also where the design is honest about itself. It records what wasn't checked: "Bottom motion sampled geometrically; not a spring force, torque, fatigue or print tolerance simulation." "No tested IP67 or load rating." "Pipe/cable bands are routing envelopes; buckle and tensioner are unspecified." Those lines travel with the model, so nobody later mistakes a geometric check for a qualification test.

The drawings follow the same rule. They're generated from the model and labelled on their face: provisional, IP67 test target only, not rated, contact geometry illustrative.

What the checks caught

The useful part of a test suite is what fails, and three things here are worth passing on.

Interference that's supposed to be there. A ball detent must press into its mating part a little, or it wouldn't click, so a blanket "nothing may overlap" check fails by design. The detent is now checked on its own terms: the rigid parts must never touch at any pose, and the ball's required retraction (up to about 0.19 mm in revision 5) has to stay within the 0.3 mm travel of the spring-loaded ball it's sized for.

Geometry in the wrong frame. A Part Design feature stores the shape it adds in its own coordinate frame. To check one feature on its own (a detent, say), its shape has to be moved by the feature's placement first, or the check tests empty space and passes. The same family of problem showed up in the hardware: screws, balls and inserts are linked copies of one part, and their orientations needed correcting. The STEP export now builds each one from the link's actual placed shape, so the file matches what's on screen, and confirms the count: 87 solids of 87 expected.

A step that didn't finish. Rescaling the whole model from 60 to 66 mm and back worked in an early revision. In a later one the rescale stalled, so the checks file says plainly that the final rescale is unverified. Writing "unverified" or "no success claimed" is less satisfying than a green tick, and much more useful to whoever picks the model up next.

From CAD to a web page

The website shows the node and its mounts in 3D. As you scroll, the node lowers into a dock, twists and locks, and then the mounts come in one by one. That's the same CAD, not a separate model.

A script runs inside FreeCAD's command-line build and turns the STEP files into a compact binary format:

  • It meshes each face separately, using FreeCAD's mesher, because the per-face tessellation call ignores the tolerance you give it.

  • STEP files keep no part names, so parts are classified by their bounding boxes, and hidden hardware is dropped.

  • Positions are quantised to 16-bit integers relative to each part's centre, normals to 8-bit integers, and triangle indices to 16 bits (32 past 65,535 vertices), with every block 4-byte aligned.

  • three.js reads the buffers directly as interleaved attributes, with no parsing step.

The full node comes to 837 KB. A lighter version, at 372 KB, is drawn as an instanced mesh when a scene shows dozens of nodes at once, and all five mounts together are 254 KB.

The circuit board

The node's electronics are on an eight-layer board designed in KiCad, and the first electronics are in bring-up on the bench. The website shows one layer, the top copper. Net names say more about a circuit than I wanted to publish, so before the image went online a short OpenCV script removed the labels. A morphological top-hat filter on lightness picks out thin text (a small kernel for net names, a larger one for pad numbers), and those pixels are inpainted from their surroundings. Pads, traces and vias are wider than the kernels and come through untouched.

Where it's going

The current concept, Revision D, splits the node into modules that twist together: a radio module, a probe and a battery pack, behind one common exterior. Its pictures are deterministic renders of the CAD geometry, labelled as a concept with physical tests not yet run.

What comes next is the part CAD can't do: printing the parts, load-testing the mounts, leak-testing the seals, and publishing ratings once they're qualified, and not before.

---

How this was built. I'm the founder of Continuis Labs. I set the requirements and the design direction, made the engineering calls, and reviewed every revision; an AI agent operated FreeCAD through MCP and wrote the scripts under my direction, and the checks are how I held the geometry to the design. Every picture here is the CAD model, its drawings, or the board's copper as published.

Next in the series: teaching a drone to perch, in simulation first.

Connecting the digital to the physical.

Contact

Links

wadesthomas1@gmail.com

+12155019211

© 2026. All rights reserved.