dankbuild

Measuring a dev board for 3D printing when the size is not published

·Method·Not a build-log

If you just want a holder, do not read this. Search Printables, MakerWorld, Cults3D or Yeggi for your board and you will find a ready-made model, free, from people who have printed theirs. They have more models than this site will ever have and that is the right place to get one.

This page is about the step before a model exists: how you decide a dimension nobody has written down, and how you check a generated solid before you spend filament on it.

Nothing described here has been printed. The two parts this page refers to have not been printed — not by me, not by anyone I know of. Every check below is a check a computer performed on geometry. No printer, no caliper, no fit, no tolerance, no material result, no photograph of a part. Read this as a method, and judge the method; there is no finished object at the end of it.

What I tried, and what actually came back

The part in question parks an ESP32-S3-DevKitC-1. To cut a bay for it you need the board's outline width. The repository's own notes claimed that dimension could not be sourced: that the vendor's board page renders with JavaScript and that the dimensions PDF it links to returns 404. Before repeating a claim like that in public I re-ran it. The claim was stale, and this page is the correction.

What I got, this run. The documentation URL the notes were built on, docs.espressif.com/projects/esp-dev-kits/en/latest/esp32s3/esp32-s3-devkitc-1/user_guide.html, still returns HTTP 404 — so the original negative result reproduces exactly.

But one negative on one URL is not a proof of absence, and walking up the path shows why: the directory index at .../esp32-s3-devkitc-1/index.html returns 200, and every link in it points at user_guide_v1.1.html, which also returns 200.

The guide was renamed to a versioned filename, and the old unversioned path was simply left to 404. Nothing was withdrawn. A link rotted.

That guide's related-documents list includes an item labelled “ESP32-S3-DevKitC-1 Dimensions source file (DXF)”, served from dl.espressif.com/dl/schematics/esp_idf/. It returns 200, as image/vnd.dxf, 743,753 bytes, alongside a PDF rendering of the same drawing at 124,348 bytes. The dimensions source exists and is public. Publishing “you cannot get this” when you can is the same category of error as inventing a number, so the bench parts page now carries the correction.

One place still carries the old wording, and it is worth saying which. The original claim is a header comment inside models.cjs, and that file's body is concatenated verbatim into the geometry module the browser runs — the string “JS-rendered” is present in the committed module today.

The parity check described at the end of this page asserts that module byte for byte, so rewriting one sentence of English in the generator is not a prose edit; it forces a regeneration of the geometry and a re-verification of the plate against the published STL.

That is a different change from writing this page, and doing it as a drive-by is exactly the habit the check exists to prevent. So models.cjs.txt still reads “its linked dimensions PDF 404s”. It is wrong, this page is the current reading, and the correction is owed to the generator the next time its geometry is legitimately rebuilt.

Available is not the same as written down

So I opened the DXF. It is an AutoCAD 2013 file, and it contains zero DIMENSION entities — there is not a single dimension callout in it. Its text entities are silkscreen designators: R9, U4, J2, ESP32-S3-DevKitC-1.

The header's drawing extents cover the whole annotated sheet rather than the board outline, so reading them as a board size would be wrong by a wide margin. The PDF rendering has no extractable text layer at all; it is a picture of a drawing.

This is the useful lesson, and it is more general than one board. The authoritative source is vector geometry, not a table of numbers. To get a width out of it you open it in CAD and measure the outline yourself.

So measuring is not avoidable here — it was never avoidable. The only real choice is where you measure: in CAD, against a file, or in plastic, against the board on your desk. Both are measurements. Neither is a number someone handed you, and that is exactly why this page will not quote one.

Why a printed gauge beats a confident guess

The measurement instrument here is a stepped gauge: six U-channels of increasing width, 24.6, 25.0, 25.4, 25.8, 26.2 and 26.6 mm, defined in models.cjs. You lower the board into each from above; the narrowest channel it settles into without forcing is the board width, to within the 0.4 mm step.

A rib count beside each channel identifies it, so the reading survives putting the part down and picking it up again. The channels are only 16 mm long and open at both ends, so you engage a short section of the PCB edge instead of fighting the pin headers.

Top-view outline of the fit gauge: six pairs of parallel walls forming channels, arranged two across and three down, each with a group of small ribs beside it.
That ladder seen from above, drawn from esp32-fit-gauge.stl's own bytes by verify-stl.cjs — a render, not a photograph of a part. The step between neighbouring channels is finer than this drawing resolves at page size, so identify a channel by counting the ribs beside it rather than by eye off the picture; the STL itself and an isometric view of the same mesh are on the ESP32-S3 bench parts page.

Those six numbers are the band published as an STL here, chosen to straddle the board this site is measuring — which is no use to you if you are holding something else.

The ladder is not welded to them: fitGauge() takes an optional centre, so re-running the generator with a rough estimate of the width you are after emits the same six channels at the same 0.4 mm step, re-centred to straddle your estimate — three channels below it, three above, and none landing exactly on it, so every channel gives a verdict rather than a shrug.

A ladder of six trial widths is cheap. A guess is not, because a guess is indistinguishable from a fact once it is written into a parameter file — and search will happily hand you a confident width belonging to a different board in the same family. The gauge cannot be wrong in that way. It has no opinion; it only fails to fit.

Make being wrong cheap: leave the uncertain axis open

The second half of the method costs nothing and matters more. In the bench plate, the devkit bay is open at both ends on purpose. Only the width is constrained; the length is not. Get the length wrong and the board simply overhangs the end of the bay. It cannot fail to fit.

That is a design decision made specifically because a dimension was uncertain: you spend a constraint only on the axis you can defend, and you let the axis you cannot defend run off the edge of the part.

test-fit.cjs asserts that openness rather than trusting it, with a check whose name says what it is for: “the devkit bay is OPEN end to end, so an unverified board LENGTH cannot bind”.

Four layers between the geometry and the printer

Generated geometry looks right in a preview long after it has stopped being right. Four independent checks stand between the model and a print, and one of them caught a real defect.

  1. The mesh cannot self-overlap. stl.cjs builds solids as boxes that touch but never interpenetrate, and its check() rejects any pair with positive overlap on all three axes at once — the self-intersecting shells that make slicers produce nonsense.
  2. The dimensions are asserted, not eyeballed. test-fit.cjs takes a scan line through the finished solid at wall height and reports the clear span, the way a caliper would. Running it now returns 26 assertion(s) passed. This is the layer that earned its place: during design it caught a stray term that had inflated the devkit bay by millimetres, which would have left the board rattling in a part that still looked correct on screen.
  3. The bytes on disk are re-read by a stranger. verify-stl.cjs parses the written STL again with an independent reader, because a generator validating its own memory tells you nothing about what landed in the file. The same pass also counts, for every edge it parsed, how many triangles use that same line, and prints the tally: the plate comes back as 140 undirected edges, 0 used once (an open shell), 4 used more than twice. Those four are the vertical corners where two wall boxes stand against each other; the writer has no boolean union, so the plate is several touching skins rather than one closed surface. That is how the part is built, not a defect that crept in, and the tool reports the number for every file it reads without ever asserting it. Nothing is written at all unless the mesh check passes first — see build.cjs, which leaves no file behind when a model is invalid.
  4. The copy in your browser cannot drift from the copy on the command line. This is the strongest layer. The same geometry now runs client-side from geometry.js, and test/web-geometry-parity.test.cjs fails if that served module differs by one byte from the CLI source, or if the solids it builds stop matching the published STLs. Its output, verbatim, from this run — one line, wrapped here to fit:
ok web-geometry-parity — geometry.js is a byte-exact render of stl.cjs + models.cjs;
the plate it builds is byte-identical to models/esp32/esp32-bench-plate.stl
(4884 bytes, 96 triangles, 120.3 x 63.1 x 5.6 mm) and the comb to
models/esp32/jumper-wire-comb.stl (19884 bytes, 396 triangles, 84.01 x 9.08 x 5.6 mm)

Every number this page states, in one place. The table collects them and adds nothing: each value is repeated from the prose above in the unit the prose uses, and the last column says what, if anything, re-measures it.

Two rows have no value, and those two are the most useful rows in the table — a missing number is the thing this page is about, so they are marked and explained rather than filled in with something plausible.

The measurements this page states, and what each one is checked against — nothing here is derived, rounded, averaged or converted
Dimension Value Unit Where the number came from, and what it is asserted against
ESP32-S3-DevKitC-1 outline width no value mm Left empty on purpose. Nothing on this page states it. The DXF carries zero DIMENSION entities and the PDF rendering has no text layer, so there is no number to copy across; writing a plausible one here would be the exact failure the page argues against. This is the cell the gauge exists to fill, on your desk, for your board.
Devkit bay length, bench plate no value none Left empty on purpose. There is no length to state: the bay is open at both ends, so a board longer than the bay overhangs instead of binding. test-fit.cjs asserts that openness directly.
Fit-gauge channel widths, six channels 24.6, 25.0, 25.4, 25.8, 26.2, 26.6 mm Literals in models.cjs, published as esp32-fit-gauge.stl. Chosen to straddle the board this site is measuring; fitGauge() re-centres the same ladder on an estimate you supply.
Step between neighbouring channels 0.4 mm The spacing designed into that ladder. It is the resolution of a reading, not an accuracy claim: the gauge tells you which channel the board settles into, no finer.
Fit-gauge channel length 16 mm models.cjs. Short, and open at both ends, so the board engages a section of PCB edge rather than the pin headers.
esp32-bench-plate.stl, bounding box 120.3 x 63.1 x 5.6 mm Quoted from the parity line above, which measures the written file's own bytes with an independent reader instead of trusting the generator's memory.
jumper-wire-comb.stl, bounding box 84.01 x 9.08 x 5.6 mm Same line, same run, same independent reader.
esp32-bench-plate.stl, mesh size 96 triangles Counted out of the file by the same pass. Reported, not asserted against a hand-written figure.
jumper-wire-comb.stl, mesh size 396 triangles Same pass, same run.
Bench-plate edges used by more than two triangles 4 edges Out of 140 undirected edges, 0 used once, as verify-stl.cjs prints it. Reported and never asserted: those are the vertical corners where two wall boxes stand against each other, because the writer has no boolean union.
Dimensional assertions run against the finished solids 26 assertions test-fit.cjs on this run: 26 assertion(s) passed. It scans the solid at wall height and reports the clear span, the way a caliper would.

What you may do with the code this page hands you. Separately from whether the method is any good, you are free to use it. The generator and checking code linked throughout this page — build.cjs, models.cjs, stl.cjs, test-fit.cjs, verify-stl.cjs and the geometry.js the browser runs — is MIT.

So: paste any of it into your own repository, swap the numbers for the board you measured, keep it private or sell what you build on it, without asking. What MIT asks in return is only that the copyright line and the permission notice travel with the copy you pass on; LICENSE-MIT.txt is plain text, opens in the tab, and is short enough to paste whole.

The geometry those scripts emit is a separate question with a separate answer: the STL and SVG files on the parts page are CC BY 4.0, and LICENSE-CC-BY-4.0.txt carries an attribution line you can paste as it stands. Permission is not a promise the code is right, and it is not a promise anything here fits: the notice at the top of this page still stands.

What this does not tell you

It does not tell you the board's width — the whole point is that you measure it. It does not tell you that any of this fits, because nothing has been printed. It reports no tolerance, no print time observed on a printer, no material result, and no experience from anyone who has used any of it.

What it offers is a way to proceed honestly when a number you need is missing: check whether it is really missing or just moved, measure rather than assert, leave the uncertain axis unconstrained, and make the machine re-check the file it just wrote.

The parts and downloads this method produced are on the ESP32-S3 bench parts page, along with every source file quoted above.


← All electronics build-logs

Back to the top