A Python script that takes an STL part as input and produces two STL files representing the upper (cavity / A-side) and lower (core / B-side) halves of a basic two-plate injection mold. Output is ready to 3D print, or to use as a clean starting point for CNC machining a soft (aluminum) tool.
The mold includes the features you'd want for a first-pass tool: a sprue, a runner along the parting plane, a small gate to minimize the witness mark on the part, vents at the parting line where they'll actually do something useful, and dowel pins for half alignment.
pip install numpy trimesh manifold3d shapely matplotlib
python two_part_mold.py mypart.stl --out-dir ./mold
This drops four files into ./mold/:
mypart_mold_upper.stlandmypart_mold_lower.stl, the two mold halvesmypart_overview.png, isometric views of both halves alongside the original partmypart_parting_section.png, a 2D cross-section through the parting plane showing the cavity, runner, gate, vents, and dowel sockets
Required:
pip install numpy trimesh manifold3d shapely
Optional:
pip install matplotlib # for the preview PNGs
If matplotlib isn't installed, the script still runs and writes the STLs, just without preview images.
No other optional dependencies. In particular, rtree is not used or needed (silhouette analysis runs through mesh.section + shapely.ops.polygonize instead of ray-casting, which sidesteps rtree's install issues on newer Python versions).
python two_part_mold.py INPUT.stl [options]
INPUT.stl. Path to the input part as an STL file. The mesh should be watertight; the script will attempt repair if it isn't, and will warn if repair doesn't fully close the geometry.
| Flag | Default | Purpose |
|---|---|---|
--out-dir DIR |
current dir | Where to write outputs |
--padding MM |
10 | Wall thickness around the part on each side |
--parting-axis {x,y,z} |
z | Axis perpendicular to the parting plane |
--parting-offset MM |
bbox midpoint | Coordinate along the parting axis where the split happens |
--gate-axis {x,y,z} |
x | Axis along which the runner / gate enter the part (must differ from --parting-axis) |
| Flag | Default | Purpose |
|---|---|---|
--sprue-radius MM |
3.0 | Sprue cylinder radius |
--runner-radius MM |
2.5 | Runner cylinder radius |
--gate-radius MM |
0.8 | Gate radius. Keep small to minimize witness mark |
--gate-penetration FRAC |
0.5 | How deep the gate cylinder reaches into the part bbox, as a fraction. Increase for parts with curved silhouettes if the default doesn't reliably overlap |
| Flag | Default | Purpose |
|---|---|---|
--vent-thickness MM |
0.2 | Slot depth. Production steel tools cut by wire EDM use 0.025 to 0.05; 0.2 is realistic for 3D-printed or aluminum CNC tooling |
--vent-width MM |
4.0 | Slot width perpendicular to the gate axis |
--vent-count N |
2 | Number of vent slots. Set to 0 to skip vents |
--vent-side {upper,lower} |
upper | Which mold half holds the slots |
| Flag | Default | Purpose |
|---|---|---|
--pin-radius MM |
3.0 | Pin radius |
--pin-height MM |
8.0 | How far the pin protrudes from the parting plane |
--hole-clearance MM |
0.15 | Diametral clearance between pin and socket |
| Flag | Default | Purpose |
|---|---|---|
--ejector-grid N |
0 | If nonzero, drills an N×N grid of ejector holes through the lower half |
--ejector-radius MM |
1.5 | Hole radius |
| Flag | Purpose |
|---|---|
--no-preview |
Skip writing the PNG previews. STLs are still produced |
A vertical cylinder through the upper plate, opening to the outside on the top face and connecting to the runner at the parting plane. The script uses a straight cylinder for simplicity; production sprues are tapered 1 to 2 degrees per side for clean ejection. If you're machining the mold from steel, add the taper in CAD before manufacturing.
A short cylindrical channel along the parting plane connecting the sprue base to the gate. Single-cavity tools like this don't need a complex runner system; the channel length is the minimum needed to keep the sprue clear of the part bbox.
A small-radius stub from the runner end into the part. The gate is intentionally narrow so the witness mark on the molded part is minimal. Where it meets the part surface is the constriction; where it extends inside the cavity is automatically absorbed by the part geometry during the boolean union.
Thin slots on the parting plane on the side opposite the gate, where flow fronts converge and trapped air gets pushed during a fill. The script slices the part at the parting plane to get the 2D silhouette, sweeps a horizontal line across it to find the deepest valleys (positions where the part retreats furthest from the gate side), and places vents at those Y positions. Each vent's inner edge is anchored 2mm inside the silhouette at its specific Y, guaranteeing connection to the cavity. The slot sits entirely on one mold half so the depth is visible in the STL and the opposite face seals the channel when the mold closes.
Four cylindrical pins at the corners of the mold, placed in the padding region between the part bbox and the mold edge so they don't conflict with vents or other near-silhouette features. The lower half gets the pins as positive geometry; the upper half gets matching slightly-oversized sockets.
A uniform N×N grid through the lower half, only when you ask for it.
- Load the STL, repair if needed
- Build a mold block as a padded box around the part bbox
- Construct the sprue, runner, and gate as a single union mesh
- Slice the part at the parting plane to get the 2D silhouette polygon, sample where the silhouette is deepest along the perpendicular axis, and use those positions for the vents
- Build each vent as a thin box, with its inner edge anchored to its specific silhouette point
- Union the part, feed system, and vents into one cavity-negative volume
- Subtract the cavity-negative from the mold block
- Split the mold block in half along the parting plane via boolean intersection with two large half-space boxes
- Add dowel pins to the lower half (boolean union) and clearance sockets to the upper half (boolean difference)
- Optionally drill ejector pin holes through the lower half
- Export both halves as STL, write preview PNGs
All boolean operations run through trimesh's manifold3d backend.
-
Flat parting plane only. Parts with significant features on both sides of every axis-aligned midplane need a contoured parting surface, which this script does not generate. Inspect your part along all three axes and pick the one with the cleanest split.
-
No undercut detection. If the part has undercuts relative to the parting axis, the halves will not separate. Add draft to the part in CAD, redesign the part, or model side-actions and lifters.
-
No cooling channels. Add those in CAD before manufacturing.
-
No draft on the cavity. The script reproduces the part as-is. If your part doesn't have draft, the molded part will drag and tear on every shot. Add 0.5 to 2 degrees of draft to the part before running this script.
-
Single cavity. No multi-cavity layout, no balanced runner system, no family tooling.
-
Sprue is a straight cylinder. Real sprues are tapered for ejection. Add the taper in CAD.
-
Witness mark sits at the gate location. The default gate enters from the -X side of the part. Choose
--gate-axisso the witness mark falls on a non-functional surface (typically the hub or back face, not a tooth flank, lens surface, or visible feature).
The cleanest results come from a part that's watertight, has draft, and splits cleanly along one of the axis-aligned midplanes. If yours doesn't, fix those in the source CAD before running this script. A bad part in equals a bad mold out.
If the boolean operations fail on a particular part (rare with manifold3d, but it happens on degenerate meshes), the most common fix is to remesh the part in CAD, MeshMixer, or Blender before re-running.
If the silhouette analysis fails for some reason and falls back to evenly-spaced vents, the script prints a clear [warn] message at runtime. Investigate before trusting the output. Evenly-spaced vents will work, but they may land on feature tips (gear teeth, fins) where the visible vent length is short, or worse, where the slot doesn't reliably connect to the cavity.
The cross-section PNG is the most useful preview for verifying geometry. Check that:
- The cavity is cleanly carved out of both halves
- The runner stub appears on the gate side
- Each vent reaches from the cavity edge through to the mold's outer face
- The dowel sockets sit in the padding region, clear of every other feature
For an input named widget.stl with --out-dir ./mold, the script produces:
./mold/widget_mold_upper.stl./mold/widget_mold_lower.stl./mold/widget_overview.png./mold/widget_parting_section.png
python two_part_mold.py gear.stl --out-dir ./mold \
--parting-axis z --gate-axis x \
--padding 12 \
--sprue-radius 3.5 --runner-radius 2.5 --gate-radius 1.0 \
--vent-count 2 --vent-thickness 0.25 \
--pin-radius 3.0 --pin-height 10 \
--ejector-grid 3
GPL-3.0
Written with Love by Green Shoe Garage.