Catalog PyPI
PACKAGE EXPLORERView in registry

3d-review

PyPI

Review a 3D design with an assistant: a web bench where a person marks what is wrong on the model, a ledger of which build step moved what, a requirement board whose rows are proven able to fail, and a Penpot bridge

3d3d-printingassistantdesignpenpotreviewtrimesh
Versions collected1
Direct dependencies7From release 0.1.1
Last observed20 Oct, 15:32 UTC

README

Version 0.1.1 documentation

3d-review

3d-review is what I used to review a 3D design together with an AI assistant, while designing a 3D-printed toy. The person shows what is wrong on the model itself, the assistant answers with pictures, and the assistant has to prove that what the person asked for is still true after every rebuild.

The review bench with three parts loaded

It has four parts, and each one can be used alone.

  • The bench is a web page that shows the model's stages. The person picks a part, moves or turns a ghost of it, marks a spot, writes what is wrong and submits. Each submission keeps the before and after pictures, the exact transform and the words, and becomes a thread the assistant answers. Replies are drawn from the person's own camera. "Publish all" notifies the assistant once for everything new.
  • The ledger records which step of a build pipeline moved or rebuilt a part the person cares about, including code that runs between two steps. A placement the person locked stays locked, or the ledger says which line moved it.
  • The board has one row per thing the person asked for, each with a measurement and a bar. A planted fault proves each row can go red, so a green board is not a green check over a hole.
  • The Penpot bridge pushes 2D outlines in millimetres into a self-hosted Penpot file and reads the person's edits back.

Install

pip install 3d-review
pip install "3d-review[penpot]"    # adds shapely, for cutting outlines in the Penpot bridge

In Python it is imported as review3d. It uses 3d-base for pictures.

The bench

3d-review stages body.stl arm.stl wheel.stl -o model     # writes model/stages.json and model/stages/parts.glb
cp "$(python -c 'import review3d,os;print(os.path.dirname(review3d.__file__))')/bench/bench.example.toml" model/bench.toml
3d-review bench --config model/bench.toml --port 8766

Then open http://localhost:8766/twist.html. threads.html lists every thread. From Python, review3d.stages.write_stages writes any number of stages (for example "parts", "assembled" and "printed") from {stage: {part: trimesh.Trimesh}}, and review3d.bench.server.Bench takes your own notifier, rebuild hook and freshness check. The default notifier appends a line to a file, so the assistant can watch that file.

The bench never changes the model. A submission is a request, and applying it is a separate step.

The ledger

from review3d import ledger
import mybuild

ledger.install(mybuild, watch={"arm", "wheel"}, pipeline="build")
mybuild.build()
print(ledger.missing(mybuild, "build"))   # steps the pipeline calls that the ledger does not wrap
ledger.write("ledger.json")

The steps are read from the pipeline's own source, so a step added later is never invisible to it. Moves are measured exactly (the rigid transform between the vertices before and after), and a part whose vertex count changed is reported as rebuilt.

The board

import types
import trimesh
from review3d.board import Board, Row, at_most, mirror_asymmetry

design = types.SimpleNamespace(body=trimesh.load("part.stl"))   # any object your rows can read

board = Board([Row("symmetric", "the two sides match", lambda d: mirror_asymmetry(d.body, normal=(1, 0, 0)), at_most(0.2), "mm")])

@board.fault("symmetric")
def bump(design):
    lump = trimesh.creation.box(extents=(2, 2, 2))
    lump.apply_translation([6, 0, 0])
    design.body = trimesh.util.concatenate([design.body, lump])

board.report(design)
print(board.proof_table(board.prove(design)))

A row whose measurement fails or has no input reads unknown, never green. A row with no fault reads unproven. The measurements include mirror symmetry, sphericity, surface roughness, gap and penetration between parts, tipping, first-layer area, overhang share, length along an axis, axis angle, bow, out of round, tunnels, and the brightness of a rendered view.

The Penpot bridge

from review3d.penpot import PenpotClient, PenpotSettings

client = PenpotClient(PenpotSettings.load("penpot.toml"))   # or PENPOT_* environment variables
result = client.push({"plate": [(0, 0), (60, 0), (60, 20), (0, 20)]})
edited = client.pull(file_id=result.file_id)

One Penpot unit is one millimetre. Keep credentials in the settings file or the environment, never in code.

Claude Code skill

3d-review skill            # copies it to ~/.claude/skills/3d-review

The skill is the review loop as we ran it. It covers writing the person's requirements as rows before building, proving each row, answering threads with pictures, keeping locks through rebuilds, asking questions with pictures on the bench instead of in words, and the failures that taught each rule.

Limits

  • The bench is meant for one person and one assistant on a trusted network. It has no login, so keep it on 127.0.0.1 or behind a private network.
  • The board's measurements are general. The rows that matter for your design are yours to write.
  • The bench includes three.js r169 (MIT, licence in bench/static/vendor).
  • Reading through Penpot's exporter depends on the exporter service working. The default pull reads the stored geometry and does not need it.

Development

python -m venv .venv && .venv/bin/pip install -e '.[test,penpot]'
.venv/bin/pytest

The Penpot tests use a fake server. Set PENPOT_URL and a token to run the live round trip too.

License

MIT

Downloads & popularity

2downloads
1-day window · source-reported counts17 Oct 2026
17587.50
2026-10-02: 175 · observed 2026-10-20T17:46:10.7249702Z · period 2026-10-02–2026-10-022026-10-03: 20 · observed 2026-10-20T17:46:10.7249702Z · period 2026-10-03–2026-10-032026-10-04: 11 · observed 2026-10-20T17:46:10.7249702Z · period 2026-10-04–2026-10-042026-10-05: 6 · observed 2026-10-20T17:46:10.7249702Z · period 2026-10-05–2026-10-052026-10-06: 7 · observed 2026-10-20T17:46:10.7249702Z · period 2026-10-06–2026-10-062026-10-07: 1 · observed 2026-10-20T17:46:10.7249702Z · period 2026-10-07–2026-10-072026-10-08: 7 · observed 2026-10-20T17:46:10.7249702Z · period 2026-10-08–2026-10-082026-10-09: 5 · observed 2026-10-20T17:46:10.7249702Z · period 2026-10-09–2026-10-092026-10-10: 3 · observed 2026-10-20T17:46:10.7249702Z · period 2026-10-10–2026-10-102026-10-11: 3 · observed 2026-10-20T17:46:10.7249702Z · period 2026-10-11–2026-10-112026-10-13: 1 · observed 2026-10-20T17:46:10.7249702Z · period 2026-10-13–2026-10-132026-10-14: 1 · observed 2026-10-20T17:46:10.7249702Z · period 2026-10-14–2026-10-142026-10-16: 2 · observed 2026-10-20T17:46:10.7249702Z · period 2026-10-16–2026-10-162026-10-17: 2 · observed 2026-10-20T17:46:10.7249702Z · period 2026-10-17–2026-10-17
2 Oct17 Oct

pypistats · 14 observations shown. Missing days are unknown. Source category: overall: without mirrors.

View observed values
Date / source periodValueObserved at
2026-10-17 – 2026-10-1722026-10-20T17:46:10.7249702Z
2026-10-16 – 2026-10-1622026-10-20T17:46:10.7249702Z
2026-10-14 – 2026-10-1412026-10-20T17:46:10.7249702Z
2026-10-13 – 2026-10-1312026-10-20T17:46:10.7249702Z
2026-10-11 – 2026-10-1132026-10-20T17:46:10.7249702Z
2026-10-10 – 2026-10-1032026-10-20T17:46:10.7249702Z
2026-10-09 – 2026-10-0952026-10-20T17:46:10.7249702Z
2026-10-08 – 2026-10-0872026-10-20T17:46:10.7249702Z
2026-10-07 – 2026-10-0712026-10-20T17:46:10.7249702Z
2026-10-06 – 2026-10-0672026-10-20T17:46:10.7249702Z
2026-10-05 – 2026-10-0562026-10-20T17:46:10.7249702Z
2026-10-04 – 2026-10-04112026-10-20T17:46:10.7249702Z
2026-10-03 – 2026-10-03202026-10-20T17:46:10.7249702Z
2026-10-02 – 2026-10-021752026-10-20T17:46:10.7249702Z

Versions 1

Collected releases
VersionPublishedDirect dependenciesOpen version
0.1.12 Oct 20267

Package advisories

0
No matching advisories collected

This describes our collected data; it is not a security assessment.

Repository

PENDING
drkostas/3d-review

Shared repository data · GitHub

License detected in repository
Not collected

Metadata history

Meaningful changes
Current collected state Current

Observed since 20 Oct, 15:32 UTC

No superseded metadata states collected. Unchanged observations do not create new revisions.

Record identity

package:1cb943c3b86062de1d68ea8aeccb9fc7414f58d89c394ae7119d147931a2ec28