3d-card
3d-card turns a set of 3D-printable parts into one printable card, like the sprue of a plastic model kit. The parts sit on a flat frame, each held by small gates at the bottom, and you print the whole card in one go, cut the parts off and put them together. Before it gives you the card, it cuts every gate itself and checks that every part comes back whole and loose (the round trip).
I wrote it for a posable toy figure I designed and printed, and I could not find a public tool that makes this kind of card. It also has the print-in-place joints and the printability checks I needed on the way.
Install
pip install 3d-card
pip install "3d-card[sim]" # adds the MuJoCo stand-up test and convex decomposition
In Python it is imported as card3d. It uses build123d (the CAD kernel), trimesh and manifold3d for the geometry, and 3d-base for mesh loading and pictures.
Make a card
You give it a function that returns your parts, the joints between them and a list of notes.
import trimesh
from card3d import tosprue
def source():
parts = {"body": trimesh.load("body.stl"), "arm": trimesh.load("arm.stl"), "wheel": trimesh.load("wheel.stl")}
joints = [] # optional, see below
return parts, joints, []
got, report = tosprue.best_card(source=source)
print(got["size"], got["fits_bed"], report["ok"])
got["card"].export("card.stl")
best_card tries a few layouts and keeps the smallest one whose round trip passes. build makes one card with the options you pass. export(out="card", name="card.stl", ...) builds and writes it.
What it does, in order.
- Each part is turned so it rests on a face with enough first layer. A part with only a few square millimetres on the plate comes loose in the first layers and the nozzle drags it away.
- The parts are laid out in rows, with a runner bar under each row.
- Gates are placed at the bottom of each part, in the frame's own plane, where the part comes closest to its bar. A gate higher up would print in the air.
- Each part gets a small number stamped on the frame next to it.
- The card is made into one solid, the gates are cut, and every piece is matched back to its part by area and size.
The card is as tall as its tallest part, and it is checked against your printer's bed (bed=(width, depth) in mm, or set card3d.sprue.BED).
A card you can read
By default the parts go into one row after another. To make the card read like the finished model (head at the top, legs lower down, and so on), pass the rows yourself.
tosprue.build(source=source,
rows=[["head"], ["arm_left", "body", "arm_right"], ["leg_left", "leg_right"]],
down=["arm_left", "arm_right", "leg_left", "leg_right"], # long axis down the card
across=["head"]) # long axis across it
Parts you do not name go into a last row. Someone can then put the kit together without instructions.
Joints
card3d.joints makes the two halves of a joint (male is what sticks out, female is what is cut away) for pegs, axles, pivots, ball joints, tabs and cross laps. The clearances were measured on a real printer with the two test prints in card3d.coupons (0.30 mm for push fits, 0.20 mm for a pivot that holds its pose). Print the coupons on your own printer and change joints.CLEAR and joints.PIVOT_CLEAR if yours differ.
If you list your joints in the source as {"type": "peg", "size": 3.0, "axis": (1, 0, 0), "at": (x, y, z), "child": "arm", "parent": "body"}, the card keeps gates away from them and does not cut a part's sole through a peg.
Flat cards and checks
card3d.sprue.make_cardmakes the flat version, a kit card of flat plates of one thickness, andcard3d.roundtrip.checkcuts it and checks every plate comes back.card3d.simulatorreports overhangs and where supports would leave marks, sweeps a peg into its socket to find collisions, finds the best print orientation, and with thesimextra decomposes a part into convex pieces and tests in MuJoCo whether the assembled model stands.card3d.labelsmakes small 3D numbers for parts and cards.
Claude Code skill
3d-card skill # copies it to ~/.claude/skills/3d-card
The skill gives Claude the whole procedure we used, in order. It starts with measuring clearances on your printer and goes through joints, building the card, reading its notes and the round trip, and checking the slice, up to the first physical print. It ends with a table of the failures we met (a card that printed as spaghetti, gates that cut a joint, parts that stayed on the frame) with how to check and fix each one.
Limits
- It was built for one toy with about twenty parts. Cards with many more parts work, but the layout is a row packer, not an optimiser.
- The round trip proves the gates can be cut in the model. Gate size still depends on your material and cutters, so print one card before printing many.
- The clearances are from one printer and PLA.
Development
python -m venv .venv && .venv/bin/pip install -e '.[test,sim]'
.venv/bin/pytest
python examples/make_example.py # rebuilds docs/example.png
License
MIT
Metadata
Release files for 3d-card 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| 3d_card-0.1.0.tar.gz | 67.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| 3d_card-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 138.8 kB
Release files / 3d_card-0.1.0.tar.gz
| Download URL | 3d_card-0.1.0.tar.gz |
|---|---|
| Size | 67.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
81c02c970b83246378070587818258a566e2e433e5de9486b0290d1e891e9578
|
|
BLAKE2b-256 checksum How to use checksums |
9a0413d81f53c2924e2fa8a6376b3f0ba55e908492eac0bb010991927dbd3468
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.
Transparency logRelease files / 3d_card-0.1.0-py3-none-any.whl
| Download URL | 3d_card-0.1.0-py3-none-any.whl |
|---|---|
| Size | 71.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6a7aa738fdb0d1d607ddeda15ae2f8fe8da5e8970070e47b7742f3b1cfedc941
|
|
BLAKE2b-256 checksum How to use checksums |
fcadb47491cb0c138f6b99ef035e3f17e13d022e49fd27f95960b1a9a85f032c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.
Transparency log