Tutorial 01
February 26, 2026 · View on GitHub
What you will learn
- The minimal structure of a Meshroom node
- How
desc.Node,inputs,outputs, andprocessChunkwork together - The
__version__string and cache invalidation - Lazy imports for heavy libraries
- The
logManagerpattern (try/finally)
Prerequisites
- Meshroom installed (binary release or built from source)
- mrHelloWorld plugin installed (see Quick Start)
The code
Open meshroom/helloWorld/HelloWorld.py. Here is a walkthrough of every section.
Version string
__version__ = "1.0"
Every node file must declare __version__. Meshroom uses this to determine if cached results are still valid. If you change the version, all previous computations for this node are invalidated and must be recomputed.
Module-level imports
import os
from meshroom.core import desc
from meshroom.core.utils import VERBOSE_LEVEL
These three imports are standard across all Meshroom nodes:
os— lightweight, used for path operations. Not a "heavy" library.desc— the Meshroom descriptor framework. Defines inputs, outputs, and node behavior.VERBOSE_LEVEL— standard verbosity choices for the logging parameter.
Heavy libraries like cv2, numpy, torch are never imported at module level. They go inside processChunk (see below).
Class declaration
class HelloWorld(desc.Node):
The class name must match the filename: HelloWorld.py contains class HelloWorld. Meshroom uses this convention for node discovery.
Class attributes
category = "Hello World"
documentation = """
The simplest Meshroom node. Reads an input image and writes an identical copy.
"""
category— determines where the node appears in the creation menu.documentation— displayed in the Meshroom UI when the user selects the node.
Inputs and outputs
inputs = [
desc.File(name="input", label="Input Image", description="...", value=""),
desc.ChoiceParam(name="verboseLevel", ...),
]
outputs = [
desc.File(name="output", label="Output Image", description="...",
value="{nodeCacheFolder}/output.jpg"),
]
Every parameter needs three attributes:
name— internal identifier, used in code (chunk.node.input.value)label— human-readable name shown in the UIdescription— tooltip text
Output paths use {nodeCacheFolder}, which Meshroom resolves to an isolated cache directory for each computation.
processChunk
def processChunk(self, chunk):
try:
chunk.logManager.start(chunk.node.verboseLevel.value)
import cv2 # Lazy import
image = cv2.imread(chunk.node.input.value)
cv2.imwrite(chunk.node.output.value, image)
finally:
chunk.logManager.end()
The processChunk method is where the actual computation happens. The pattern is always the same:
try/finally— ensures cleanup happens even if an error occurs.chunk.logManager.start(chunk.node.verboseLevel.value)— starts logging. The verboseLevel value is a required argument.- Your computation logic.
chunk.logManager.end()— in thefinallyblock, always.
How to test it
A pre-configured project is available: open meshroom/tuto01-hello-world.mg in Meshroom (make sure you have run scripts/setup_projects.sh first). Or set it up manually:
- Launch Meshroom with
MESHROOM_PLUGINS_PATHset. - Right-click in the graph area and add a HelloWorld node (under "Hello World" category).
- Set the Input Image to any image file on your system. For this tutorial, we use the Meshroom logo:
- Click Compute on the node.
- To view the output in the 2D viewer, double-click on the node or use the dropdown menu at the bottom of the 2D viewer and select Output Image.
- The output will be a copy of the input image in the node's cache folder.

Expected result
The output is a JPEG-encoded copy of the input. If the input is already JPEG, the result is visually identical (minor recompression artifacts are possible). For PNG inputs, the output loses transparency and gains JPEG compression.
