- OpenSCAD 100%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
114 sizes, M2 to M6, from the measurement tables in six AliExpress listings by HotXYZ Official Store (the listings themselves stay out of the repo). inserts.scad draws an insert and the cutter for its hole, preview.scad shows them, inserts.csv has the table. Taken from the ball-valve actuator's lib/inserts, with the helpers renamed to ins_*. |
||
| docs | ||
| .gitignore | ||
| CLAUDE.md | ||
| inserts.csv | ||
| inserts.scad | ||
| preview.scad | ||
| README.md | ||
heat-set-inserts: SL-type heat-set inserts for OpenSCAD
Models of brass SL-type heat-set inserts (double twill knurl), M2 to M6, and cutters for the holes they go in. 114 sizes, as sold on AliExpress by the HotXYZ Official Store, with their dimensions from the seller's measurement tables. Made for checking fits and collisions in 3D-printed parts, and for drawing assemblies.
inserts.scad the library: the size table, the insert, its hole; draws nothing by itself
preview.scad the viewer: open it to see the inserts, their hole cutters, or the two together
inserts.csv the same size table, with the listings each size comes from
docs/ the pictures in this README
Use
Add it to your project as a git submodule, or copy inserts.scad:
git submodule add https://git.octr.is/rbanic/heat-set-inserts.git heat-set-inserts
include <heat-set-inserts/inserts.scad> // use <...> works too
$fa = 1; $fs = 0.05; // the library follows your $fa / $fs (or $fn)
// a block with a blind hole for an M3 x D4.6 x L5.0 insert, and the insert set in it
difference() {
translate([-5, -5, -10]) cube([10, 10, 10]);
insert_hole("M3xD4.6xL5.0");
}
installed_insert("M3xD4.6xL5.0");
include also gives you the table (INSERTS) and lets you change the
defaults (INSERT_HOLE_ALLOWANCE, INSERT_HOLE_CHAMFER); use keeps the
library's names out of your file. The library sets no $fa, $fs or $fn
of its own.
An insert is named thread x outside diameter x length, in mm:
"M3xD4.6xL5.0". Every size is in the table under Sizes.
Frame
heat_insert()stands on z = 0, the end that goes into the hole first down, its top face at z = L.installed_insert()andinsert_hole()share one frame: the origin on the part's surface, the hole going down -Z. The insert's top face is flush with the surface. The cutter pokes 1 mm out of the surface so it cuts cleanly.
Modules
| Module | Draws |
|---|---|
heat_insert(size) |
the insert, standing on z = 0 |
installed_insert(size) |
the insert as installed: top face on z = 0, going down |
insert_hole(size, depth, allowance = 0.1, screw = 0, chamfer = 0.5) |
the cutter for its hole (see Holes). depth defaults to a blind hole; give more than the wall for a through hole. screw adds that much clearance hole below the bottom, for a screw longer than the hole |
Functions
| Function | Returns |
|---|---|
insert_row(size) |
the size's row of INSERTS, or undef |
ins_size(r), ins_m(r), ins_d(r), ins_phi2(r), ins_phi3(r), ins_l(r) |
name, thread, outside diameter D, Φ2, Φ3, length L |
ins_segs(r) |
[L2, L3, L4, L5, L6] |
ins_pitch(r), ins_bore(r) |
the thread's coarse pitch; its internal minor diameter (ISO 965), drawn as the bore |
ins_hole_d(r, allowance), ins_hole_depth(r) |
the hole's diameter and blind depth |
ins_min_wall(r) |
the least wall to leave round the hole |
ins_clearance(r) |
the ISO 273 medium clearance hole for the thread |
A size that isn't in the table stops with a message naming it.
What is drawn
Going from the end that goes into the hole first to the top face:
| Section | Diameter | |
|---|---|---|
| L2 | smooth lead-in | not dimensioned; drawn at Φ2 |
| L3 | neck | Φ3, the smallest outside diameter |
| L4 | lower knurled band | D |
| L5 | groove between the bands | Φ2 |
| L6 | upper knurled band, to the top face | D |
L2 + L3 + L4 + L5 + L6 = L on every size. Only what the seller dimensions is modelled: the knurls are plain cylinders at D (the two bands are diagonal knurls of opposite hand; their teeth aren't dimensioned), the bore is the thread's minor diameter without a thread, and there are no chamfers.
Holes
- Straight, not tapered: these are straight inserts (Spirol allows at most 1 degree included taper for them). The top sits flush.
- Diameter: Φ2 +
allowance(0.1 mm). CNC Kitchen's holes are their inserts' pilot diameter + 0.1 (+0.15 for the Voron M3), and Φ2 of the SL inserts with the same outside diameter equals their pilot (3.1 at D3.6, 4.25 at D5.0). The knurls (D) melt into the wall. - Blind depth: L + max(1 mm, 2 thread pitches): room for the plastic the insert pushes ahead of it (CNC Kitchen: about 1 mm), and so the screw can't bottom out (Spirol: 2 pitches). A through hole needs no more than L.
- Chamfer: 45 degrees at the mouth,
chamfer(0.5 mm) deep, so the plastic the knurls push up has somewhere to go instead of standing proud round the insert and needing to be cut off. It also centres the insert. - Wall:
ins_min_wall()is CNC Kitchen's least wall round the hole, by outside diameter. - Printed holes come out small, and horizontal ones sag at the top: print a test piece and adjust the allowance.
Sources: CNC Kitchen's design rules and insert table; Spirol, "How to design the proper hole for heat/ultrasonic inserts".
The viewer
Open preview.scad. By default it shows every size, one row per thread x
outside diameter, shortest first.
| Setting | Does |
|---|---|
INSERT |
all, or one size: its dimensions and hole go to the console |
SHOW |
insert, cutter (the hole), or fit (a block with the hole and the insert set in it) |
CUTAWAY |
cut the front half away to show the profile |
ALLOWANCE, CHAMFER |
the hole's diameter allowance and mouth chamfer |
Sizes
| Thread | D | Lengths L |
|---|---|---|
| M2 | 3.0 | 2.0, 2.5, 3.0, 3.6, 4.0, 4.5 |
| M2 | 3.2 | 2.0, 2.5, 3.0, 3.6, 4.0, 4.5 |
| M2 | 3.5 | 2.5, 3.0, 3.6, 4.0, 4.5, 5.0 |
| M2 | 3.6 | 3.0, 3.6, 4.0, 4.5 |
| M2 | 3.8 | 3.0, 3.6, 3.8, 4.0, 4.5, 5.0 |
| M2 | 4.0 | 3.0, 4.0, 4.5 |
| M2.5 | 3.5 | 2.5, 3.0, 3.6, 4.0, 4.5 |
| M2.5 | 3.8 | 2.5, 3.0, 3.6, 4.0, 4.5 |
| M2.5 | 4.0 | 2.5, 3.0, 3.6, 4.0, 4.5, 5.0 |
| M2.5 | 4.2 | 2.5, 3.0, 3.6, 4.0, 4.5, 5.0 |
| M3 | 4.6 | 3.0, 3.6, 3.8, 4.0, 4.5, 5.0, 5.5, 5.7, 6.0, 6.5, 7.0 |
| M3 | 5.0 | 3.0, 3.6, 3.8, 4.0, 4.5, 5.5, 6.0, 6.5, 7.0 |
| M4 | 6.0 | 5.0, 5.5, 5.7, 6.0, 6.5, 7.0, 7.5, 8.0 |
| M4 | 6.5 | 5.0, 5.5, 5.7, 6.0, 6.5, 7.0, 7.5, 8.0 |
| M4 | 7.0 | 5.0, 5.5, 6.0, 7.0, 8.0 |
| M5 | 7.5 | 5.0, 6.0, 7.0, 8.0, 9.0 |
| M5 | 8.0 | 5.0, 6.0, 7.0, 8.0, 9.0 |
| M6 | 9.0 | 6.0, 7.0, 8.0, 9.0, 9.5 |
| M6 | 9.5 | 6.0, 7.0, 8.0, 9.0, 9.5 |
inserts.csv has every dimension of every size, and the listings whose
tables have it.
Sources
The dimensions are from AliExpress: the measurement tables in the descriptions of six listings by the HotXYZ Official Store, transcribed on 2026-10-16. The seller says each table is one batch measured by hand, and "there is a certain error". The listing pages and photos are the seller's and aren't in this repository.
| Listing | Threads | Outside diameters | Sizes in its table |
|---|---|---|---|
| 4000232526110 | M2 | D3.0, D3.2, D3.5, D3.6, D3.8, D4.0 | 31 |
| 4000378858302 | M2.5 | D3.5, D3.8, D4.0, D4.2 | 22 |
| 4000232858343 | M2, M3 | D4.0, D4.6, D5.0 | 23 |
| 4000761483243 | M2, M3 | D4.0, D4.6, D5.0 | 23 |
| 4000232925592 | M4 | D6.0, D6.5, D7.0 | 21 |
| 4000232990523 | M5, M6 | D7.5, D8.0, D9.0, D9.5 | 20 |
The listings sell some sizes their tables don't have, and those aren't modelled: M2xD4.0xL5.0, M3xD4.2 (every length), M3xD5.0 in L4.8, L5.0, L5.7 and L8.0, M4xD6.0xL4.0, M5xD7.0 (every length) and M5xD7.5xL4.5. The M2.5 listing sells D3.55 and D4.05, which its table calls D3.5 and D4.0; they're here under the table's names.
Checked
inserts.csvmatches the table ininserts.scad, and L2 to L6 add up to L on every size.- Every size set in its own hole (
installed_insert()against a block minusinsert_hole()): nothing inside Φ2 touches the hole wall, and the knurls do.
License
Not chosen yet.

