Advanced Automation with MeshInspector and MeshLib

Chain interface commands and MeshLib geometry functions into repeatable pipelines and batch jobs

5 min read

Overview

Once you can open tools, set their parameters and load and save meshes from Python, you can join these steps into automated workflows: one script that repairs and exports a file, a loop that processes a whole folder, or a pipeline that calls MeshLib geometry functions directly.

This article shows:

  • how to combine interface and geometry commands into a reusable function;
  • how to process all files of a folder;
  • how to call MeshLib functions that have no button in the interface;
  • when to run a script inside MeshInspector and when outside it.

Run the scripts in the Python window (Home › Python).

Chaining Commands into Workflows

A typical workflow:

  1. Load the geometry.
  2. Add it to the scene and select it.
  3. Open the tab and the tool.
  4. Adjust the parameters.
  5. Run the operation and wait for it.
  6. Export the result.

The function below does all of it for one file with Mesh Healer. Everything it needs is inside the script, so you can copy it as it is:

import time
from meshlib import mrmeshpy as mm
from meshlib import mrviewerpy as mv

def wait_progress_bar():
    mv.Viewer().skipFrames(2)
    while any(e.name == "ProgressBar" for e in mv.uiListEntries([])):
        time.sleep(0.2)

def automated_repair(input_path, output_path, mesh_name="Mesh"):
    # Load, display and select the mesh
    mesh = mm.loadMesh(input_path)
    mv.addMeshToScene(mesh, mesh_name)
    mv.Viewer().preciseFitDataViewport()
    mv.selectByName(mesh_name)

    # Open Mesh Healer and wait for the inspection
    mv.uiPressButton(['RibbonTabs', 'Mesh Repair'])
    mv.uiPressButton(['Ribbon', 'Mesh Healer'])
    wait_progress_bar()

    # Mesh Healer opens in the mode it was closed in: switch to Local Repair,
    # repair the checked problem types and wait for the repair
    mv.uiPressButton(['Mesh Healer', '##Local Repair'])
    mv.uiWriteValue(['Mesh Healer', 'Holes'], 1)
    mv.uiPressButton(['Mesh Healer', 'Repair Selected'])
    wait_progress_bar()

    # Close the tool and export the repaired mesh
    mv.uiPressButton(['Ribbon', 'Mesh Healer'])
    repaired = mv.getSelectedMeshes()[0]
    mm.saveMesh(repaired, output_path)
    print(f"{mesh_name}: holes {mesh.topology.findNumHoles()} -> {repaired.topology.findNumHoles()}, saved to {output_path}")

# Example usage
automated_repair(
    input_path="C:/Data/part.stl",
    output_path="C:/Data/part_repaired.stl",
    mesh_name="Part"
)

Example output for a test mesh with two small holes:

Part: holes 2 -> 0, saved to C:/Data/part_repaired.stl

Repair Selected is the button of the Local Repair mode of Mesh Healer: it fixes the problem types whose check boxes are checked (the script makes sure Holes is). To rebuild the whole model instead, Mesh Healer has the Auto Repair mode; see Controlling Tools and Parameters in MeshInspector.

Batch Processing Multiple Files

Python's os module lists a folder, so one loop processes every file in it. The script clears the scene before each file, so memory does not grow and names do not repeat. It is complete: the helper functions are defined in it.

import os
import time
from meshlib import mrmeshpy as mm
from meshlib import mrviewerpy as mv

INPUT_FOLDER = "C:/Data/Models/Input"
OUTPUT_FOLDER = "C:/Data/Models/Output"


def wait_progress_bar():
    mv.Viewer().skipFrames(2)
    while any(e.name == "ProgressBar" for e in mv.uiListEntries([])):
        time.sleep(0.2)


def heal_selected():
    mv.uiPressButton(['RibbonTabs', 'Mesh Repair'])
    mv.uiPressButton(['Ribbon', 'Mesh Healer'])            # open the tool
    wait_progress_bar()                                    # wait for the inspection
    mv.uiPressButton(['Mesh Healer', '##Local Repair'])    # the mode with Repair Selected
    mv.uiWriteValue(['Mesh Healer', 'Holes'], 1)           # make sure holes are repaired
    mv.uiPressButton(['Mesh Healer', 'Repair Selected'])
    wait_progress_bar()                                    # wait for the repair
    mv.uiPressButton(['Ribbon', 'Mesh Healer'])            # close the tool


for filename in sorted(os.listdir(INPUT_FOLDER)):
    if not filename.lower().endswith(".stl"):
        continue
    name = os.path.splitext(filename)[0]
    mv.clearScene()
    mesh = mm.loadMesh(os.path.join(INPUT_FOLDER, filename))
    mv.addMeshToScene(mesh, name)
    mv.selectByName(name)
    holes_before = mesh.topology.findNumHoles()
    heal_selected()
    healed = mv.getSelectedMeshes()[0]
    mm.saveMesh(healed, os.path.join(OUTPUT_FOLDER, name + "_healed.stl"))
    print(f"{filename}: holes {holes_before} -> {healed.topology.findNumHoles()}")

Example output for a folder with two test files:

a.stl: holes 2 -> 0
b.stl: holes 2 -> 0

clearScene() removes all objects without asking to save them, so run the batch in a scene you do not need. The output folder must exist. The built-in Python has no glob or pathlib, which is why the script uses os.listdir() and os.path.

Integrating with MeshLib SDK

MeshInspector is built on MeshLib, and mrmeshpy gives your script the MeshLib algorithms directly: repair, remeshing, simplification, Boolean operations, offsets and more, including functions that have no button in the interface.

Example: Simplify a Mesh Using MeshLib

from meshlib import mrmeshpy as mm

# Load the mesh directly through MeshLib
mesh = mm.loadMesh("C:/Data/part.stl")
before = mesh.topology.numValidFaces()

# Simplify: maxError is the largest allowed deviation, in model units
settings = mm.DecimateSettings()
settings.maxError = 0.05
result = mm.decimateMesh(mesh, settings)
print("Triangles:", before, "->", mesh.topology.numValidFaces(), "| deleted:", result.facesDeleted)

# Save the result
mm.saveMesh(mesh, "C:/Data/part_simplified.stl")

Example output for a small test mesh:

Triangles: 1022 -> 482 | deleted: 540

This script does not use the interface at all: it calls the MeshLib functions directly, and the scene does not change.

When to Use the SDK

Use MeshLib functions directly when you need:

  • more precise control over the parameters of an algorithm;
  • functions that have no button in the interface;
  • processing that does not need the scene, for example in a batch job.

Inside MeshInspector or outside it

Inside MeshInspector (the Python window), a script can use both modules: mrmeshpy for geometry and mrviewerpy for the scene and the interface. The built-in Python has a reduced standard library and no NumPy.

Outside MeshInspector, the MeshLib geometry functions are available in any Python 3 environment as the meshlib package. A script outside the app cannot drive the MeshInspector interface: its tools, windows and buttons are available only to scripts that run inside MeshInspector.

pip install meshlib

From the command line, starting MeshInspector with a script as a command-line argument needs a plan above Professional (Developer or a MeshLib plan).

From an AI assistant, connected over MCP, Python runs inside MeshInspector with the python_run tool; see MCP configuration instruction for MeshInspector users.

Documentation and Examples

The full list of functions and many examples are in the official MeshLib documentation:

Best Practices for Automation

  • Use clear names for objects and output files, so results do not overwrite each other.
  • Check paths before loading or saving; a missing file stops the script with RuntimeError.
  • Wait for long operations with a function such as wait_progress_bar() before you read results or press the next button.
  • Set the options you rely on: some tools, such as Mesh Healer, remember their check boxes between runs.
  • Combine interface and MeshLib calls: the interface for tools that already do what you need, MeshLib for direct control.
  • Test interactively on one file in the Python window before you run a large batch.

Customize Consent Preferences

We use cookies and similar technologies, such as local storage. You will find detailed information about all of them under each consent category below.

To learn more about how Google processes personal information, visit: Google privacy policy

Always Active