ObjectHealer
ObjectHealer repairs meshes for 3D printing. Give it an OBJ, STL, PLY, GLB or glTF file and it writes a copy with duplicate vertices merged, normals pointing outward and holes filled, so the slicer gets a closed solid. The repair runs in Blender with no window open, from a drag-and-drop window or from the command line.
It started as the repair step of Splinter, a mesh segmentation tool, and became its own tool because most scanned or generated meshes need repair whether or not they get segmented.
Requirements
- Blender 4.0 or later. Verified with Blender 5.1.0 on macOS 27 (Apple silicon). Older
versions lack the import and export operators it uses. ObjectHealer looks for Blender in this
order:
- the
BLENDERenvironment variable; /Applications/Blender.app, then~/Applications/Blender.app;blenderon your PATH.
- the
- Python 3.10 or later. Tested on 3.10, 3.12 and 3.14.
Install
uv tool install object-healer
# or
pipx install object-healer
Raw scans usually need floater removal as well. It comes with the scan extra, which adds
PyMeshLab:
uv tool install 'object-healer[scan]'
# or
pipx install 'object-healer[scan]'
Use
Window
object-healer
Drop files on the window, or use Browse files..., then click Heal All. Each healed copy
is written next to its original as <name>_healed.<ext>. Hover over a finished row for the
output path or the full error. Tick Strip floating pieces first for raw scans; the option
is greyed out until the scan extra is installed.
Command line
object-healer heal part.stl scan.ply model.glb # each to <name>_healed.<ext>
object-healer heal model.obj -o model.stl # name the output; its extension picks the format
object-healer heal --strip-floaters raw_scan.ply # remove scan debris first
Other options: --blender PATH picks a specific Blender, and --timeout SECONDS sets the limit
for each file (default 300). An existing output is overwritten; the input never is. The exit
status is 0 when every file healed, 1 when any file failed, and 2 for a usage or setup error,
such as no Blender or a missing extra.
What the repair does
Each file gets its own Blender process, started with factory settings so your add-ons and preferences don't change the result. The file is imported, every mesh in it is joined into one object, and one Edit-mode pass runs:
| Step | Blender operator | Fixes |
|---|---|---|
| Merge by distance | mesh.remove_doubles(threshold=0.0001) |
duplicate vertices, such as an STL's separate corners for every triangle |
| Recalculate normals | mesh.normals_make_consistent(inside=False) |
flipped and inside-out faces |
| Fill holes | mesh.fill_holes(sides=0) |
open boundaries of any size, closed so the mesh is watertight |
Floater removal (--strip-floaters) runs before Blender. Blender's hole filling closes the
object but keeps every disconnected piece, and a raw scan often carries specks of turntable and
background. PyMeshLab removes each piece whose bounding-box diagonal is under 5% of the biggest
piece's diagonal. The threshold is taken from the biggest piece rather than the whole file on
purpose: MeshLab's own percentage is of the whole file's bounding box, so a single speck far
from the object raises the threshold until it deletes the object too.
Limits
- It closes holes and fixes normals. It does not repair self-intersections, edges shared by three or more faces, or walls too thin to print.
- Hole filling closes every open boundary, including openings you meant to keep, so an open shell such as a single-surface cup comes back closed.
- Each filled hole becomes one polygon. STL and GLB output is triangulated, but OBJ and PLY output keeps that polygon for the next tool to triangulate.
- Duplicate vertices within 0.0001 units are merged. For a model in millimetres that is 0.1 µm; for a model in metres it is 0.1 mm.
- Materials from an OBJ's
.mtlare dropped on import. An.mtlcan name any image on disk, and GLB output would embed it. OBJ output never carries materials. - With
--strip-floaters, the mesh passes through PLY on its way to Blender, so UVs and materials from the input are lost. Scans rarely carry either. --strip-floatersneeds faces, so it refuses a point cloud.- Blender files (
.blend) are refused, because they can carry embedded Python. Blender runs with factory settings and with auto-run of embedded scripts off. - A glTF or GLB may refer to other files only through base64
data:URIs or relative paths that stay inside its own folder, with symlinks followed. Absolute paths,..escapes andfile:or web URLs are refused. Blender then gets a private copy of the model and of those files only, so a crafted model can't pull anything else into the output.
License
GPL-3.0-or-later. Copyright 2026 Aaron Montgomery. The repair script runs inside Blender through Blender's Python API, and Blender's license asks that such scripts be shared under the GPL. The window uses PyQt6, which is GPL as well. See LICENSE.
Provided as-is; bug reports are welcome, fixes are not guaranteed.
Metadata
Release files for object-healer 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 | Provenance | |
|---|---|---|---|---|
| object_healer-0.1.0.tar.gz | 104.1 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| object_healer-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 162.6 kB
Release files / object_healer-0.1.0.tar.gz
| Download URL | object_healer-0.1.0.tar.gz |
|---|---|
| Size | 104.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
35bfb12bf7fe20efa36c886382a528bba962e44f4fea491762ac7278c6dd31f9
|
|
BLAKE2b-256 checksum How to use checksums |
32380641c9ca3e19d67c1f922599145e654ff1c2c6514f8bbb1a9c3d5da0e988
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.10.11 {"installer":{"name":"uv","version":"0.10.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / object_healer-0.1.0-py3-none-any.whl
| Download URL | object_healer-0.1.0-py3-none-any.whl |
|---|---|
| Size | 58.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5d96b0a36003f5e7cda57c70e4be3e097af613b095fc326c9d9448ee57a7ba50
|
|
BLAKE2b-256 checksum How to use checksums |
5e22f056d7d7a653d1178be08b42b40d8e271aaa06c3b15be42a482622907688
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.10.11 {"installer":{"name":"uv","version":"0.10.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Security for object-healer 0.1.0
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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.