Introduction
StlTo3mf Technical Overview
StlTo3mf is a high-performance, 100% memory-safe STL-to-3MF conversion and mesh healing pipeline written in pure Rust (enforcing #![forbid(unsafe_code)]).
Powered by the Omni3MF geometry engine, it bridges legacy CAD mesh output with modern additive manufacturing slicers.
π‘οΈ
100% Safe Rust
Zero unsafe blocks across the entire workspace. Guaranteed spatial memory safety, thread safety, and crash-free execution.
β‘
Deterministic & Fast
Rayon multi-threaded CLI processing thousands of triangles per millisecond, alongside an in-browser WebAssembly and pure client-side engine.
π§©
Multi-Shell Separation
Disjoint Set Union (DSU) topological clustering splits compound STLs into discrete, colorable 3MF <object> nodes.
π§Ή
Profile Sanitization
Purges unverified vendor printer profiles, temperature overrides, and hidden G-code scripts while preserving filament colors.
π‘
Zero Server Dependencies: StlTo3mf runs both as an ultra-fast compiled native CLI and as a zero-backend client-side web application. All geometric repair, shell separation, and 3MF packaging happen directly on your machine or inside your browser tab without any telemetry or file uploads.
30-Second Quickstart
Option A: Instant Browser Studio (Zero Install)
No build tools or installation needed. Simply open the Web Studio directly in your web browser:
- Click Launch Web Studio or navigate to the converter root.
- Drag & drop any ASCII or binary
.stl model into the drop zone.
- Inspect the interactive 3D WebGL preview and click β‘ Convert & Download 3MF.
Option B: High-Throughput Native CLI
Compile the optimized native Rust binary using Cargo:
# Clone repository and build optimized release binary
git clone https://github.com/madireis/stl-to-3mf.git
cd stl-to-3mf
cargo build --release --bin stl-to-3mf
# Convert single STL with auto-repair, shell splitting, and profile sanitization
./target/release/stl-to-3mf convert model.stl -o model.3mf --strip-slicer-config
# Batch convert an entire directory in parallel using Rayon
./target/release/stl-to-3mf convert ./models/ -o ./output_3mf/ --threads 0
Format Comparison
Why Migrate from STL to 3MF?
Created in 1987, the STL (Standard Triangle Language) format was designed for rudimentary stereolithography.
Modern 3D printing requires multi-material identification, unit scaling, watertight validation, and thumbnail metadata.
Here is how StlTo3mf elevates your files:
| Feature / Characteristic |
Legacy STL Format |
Modern 3MF (StlTo3mf Engineered) |
| Data Container |
Raw uncompressed float list (binary or ASCII) |
OPC ZIP container with XML schemas & Deflate compression |
| Multi-Body / Multi-Shell |
β Impossible; all bodies fused into single triangle cloud |
β
Discrete <object> nodes with independent IDs and colors |
| Dimensional Units |
β Undefined; slicer guesses millimeters or inches |
β
Explicit unit="millimeter" declared in root XML schema |
| Color & Filament Materials |
β None in standard specification |
β
Native <m:colorgroup> palette with hex RGBA mapping |
| Topology & Watertightness |
β οΈ Frequently riddled with duplicate vertices and open holes |
β
Automated 11-stage spatial welding and boundary loop patching |
| File Size & Bandwidth |
β Heavy; 50 bytes per triangle, zero compression |
β
Lightweight; 60%β80% smaller thanks to vertex indexing and ZIP |
| Slicer & Printer Previews |
β Requires slow offline parsing of millions of vertices |
β
Embedded 256Γ256 PNG thumbnail at /Metadata/thumbnail.png |
| Slicer Security |
N/A |
β
Sanitizer scrubs third-party printer overrides & custom G-code |
CLI Reference
CLI Commands & Parameter Reference
The StlTo3mf command-line tool provides three subcommands: convert, inspect, and sanitize.
The binary can be invoked using any of its compiled aliases: stl-to-3mf, stls-to-3mf, or omni3mf.
Subcommand: convert
Converts single STL files or entire directories into compliant 3MF packages with full mesh repair and shell splitting.
stl-to-3mf convert <INPUT> [OPTIONS]
| Flag / Option |
Type |
Default |
Description |
<INPUT> |
Path |
(Required) |
Path to single .stl file or directory of STLs. |
-o, --output <PATH> |
Path |
<input>.3mf |
Target output file path or target directory for batch jobs. |
--merge-tolerance <f64> |
Float |
1e-6 |
Spatial welding radius in millimeters for coincident vertices. |
--no-repair |
Flag |
false |
Disables boundary hole loop extraction and ear-clipping hole patching. |
--hole-max-edges <usize> |
Integer |
64 |
Maximum perimeter edges in a single boundary loop permitted for auto-patching. |
--no-split |
Flag |
false |
Preserves all faces as one object; bypasses DSU shell separation. |
--strip-slicer-config |
Flag |
false |
Purges embedded slicer presets, acceleration profiles, and custom G-code. |
--preserve-supports |
Bool |
true |
Retains slicer-generated support structure meshes if present. |
--scale <f64> |
Float |
1.0 |
Uniform scale multiplier (e.g. 25.4 converts inches to mm). |
--threads <usize> |
Integer |
0 |
Rayon worker thread count. 0 uses all logical CPU cores. |
-q, --quiet |
Flag |
false |
Mutes terminal progress bars, spinners, and informative output. |
-v, --verbose |
Flag |
false |
Enables diagnostic debug logging of vertices, loops, and packaging. |
Subcommand: inspect
Analyzes an STL or 3MF model's topology, dimensions, watertightness, and scale sanity without modifying the file.
# Human-readable diagnostic output
stl-to-3mf inspect complex_bracket.stl
# Structured JSON output for CI/CD and pre-flight pipelines
stl-to-3mf inspect complex_bracket.stl --json
Example JSON diagnostics schema returned by --json:
{
"format": "binary",
"raw_triangles": 48200,
"deduplicated_vertices": 24102,
"degenerate_facets_pruned": 14,
"boundary_holes_detected": 2,
"shells_count": 3,
"is_watertight": true,
"bounding_box": {
"min": [-45.0, -22.5, 0.0],
"max": [45.0, 22.5, 35.8],
"dimensions": [90.0, 45.0, 35.8]
},
"scale_sanity": {
"status": "normal",
"suggested_multiplier": 1.0
}
}
Subcommand: sanitize
Cleans an existing .3mf package downloaded from the web, stripping unsafe printer configuration overrides while maintaining geometry, colors, and components.
stl-to-3mf sanitize untrusted_download.3mf -o safe_clean.3mf
Automation
Real-World Recipes & Batch Scripts
Common production command patterns for print farm automation, 3D scan healing, and CI/CD validation.
Recipe 1: Multi-Color Shell Separation for Bambu Studio & OrcaSlicer
Ensure disconnected pieces (e.g. eyes, buttons, body parts) become independent objects ready for filament assignment:
stl-to-3mf convert character_multicolor.stl -o character.3mf \
--merge-tolerance 1e-6 \
--strip-slicer-config
Recipe 2: Aggressive Hole Healing for Defective 3D Scans
Increase boundary perimeter tolerance to patch larger scanning holes and force normal alignment:
stl-to-3mf convert raw_scan.stl -o healed_scan.3mf \
--hole-max-edges 256 \
--merge-tolerance 1e-5 \
--verbose
Recipe 3: Parallel Batch Directory Processing (PowerShell)
Convert all STL files in a folder into individual 3MF packages in Windows PowerShell:
Get-ChildItem -Path .\stls\ -Filter *.stl | ForEach-Object {
$outPath = Join-Path .\3mf_output\ ($_.BaseName + ".3mf")
stl-to-3mf convert $_.FullName -o $outPath --strip-slicer-config
}
Recipe 4: CI/CD Mesh Validation Gate (Bash + jq)
Verify that all generated mechanical parts in your repository are strictly watertight before merging pull requests:
for f in cad_exports/*.stl; do
IS_WATERTIGHT=$(stl-to-3mf inspect "$f" --json | jq -r '.is_watertight')
if [ "$IS_WATERTIGHT" != "true" ]; then
echo "β Validation Failure: $f is NOT watertight!"
exit 1
fi
done
echo "β
All CAD meshes verified 100% watertight."
Web Integration
Web Studio & REST API Guide
StlTo3mf includes a sleek web application running either 100% client-side in static hosting environments or via an isolated Node.js HTTP server.
Starting the Local Server
The local HTTP service in web/server.js requires zero external npm dependenciesβit relies purely on standard Node.js modules (http, fs, path, child_process):
# Run with default port 3000
node web/server.js
# Run with custom port
PORT=8080 node web/server.js
REST API Reference
| Endpoint |
Method |
Content-Type |
Description |
/ |
GET |
text/html |
Serves the Web Studio 3D conversion frontend. |
/docs/ |
GET |
text/html |
Serves this documentation portal. |
/api/convert |
POST |
multipart/form-data |
Uploads an STL and streams back the generated .3mf binary package. |
/api/inspect |
POST |
multipart/form-data |
Returns diagnostic JSON (watertightness, volume, shell count, bounds). |
POST /api/convert
Accepts a multipart form with an STL file and parameters, returning a freshly packaged .3mf binary archive.
Example curl API Request:
curl -X POST http://localhost:3000/api/convert \
-F "file=@sample_gear.stl" \
-F "split_shells=true" \
-F "repair=true" \
-F "strip_slicer_config=true" \
-o sample_gear.3mf
Zero-Backend
Client-Side Geometry Engine (Browser Runtime)
When hosted statically on GitHub Pages or Cloudflare Pages, StlTo3mf converts and heals models directly in JavaScript without sending a single byte to an external server.
The client-side engine consists of five coordinated ES6 modules located in web/public/assets/js/:
stl-parser.js: Ingests binary STL buffers via DataView and ASCII STLs using regex tokenizers directly into continuous Float32Array position buffers.
mesh-repair.js: Implements spatial hash grid vertex welding ($10^{-6}\text{ mm}$ cell size), degenerate facet elimination, boundary loop edge extraction, and Gauss Divergence signed volume checks.
shell-separator.js: Implements Disjoint Set Union (DSU) to group triangles sharing undirected edges into distinct shells with compact 0-based vertex re-indexing.
viewer3d.js: Three.js WebGL viewport featuring OrbitControls, independent multi-color shell rendering, glowing red boundary hole wireframe highlights, and offscreen 256Γ256 thumbnail capture.
threemf-packager.js: Builds compliant OPC ZIP packages entirely in memory using fflate, generating [Content_Types].xml, _rels/.rels, and 3D/3dmodel.model.
Architecture
The 11-Stage Geometry Repair Pipeline
Every mesh processed by StlTo3mf passes through an 11-stage pipeline designed to eliminate non-manifold geometry, ensure positive signed volume, and package compliant 3MF archives.
1
Format Detection & Ingestion
Determines binary vs ASCII STL. Valid binary files follow $L = 84 + 50 \times N$ bytes. ASCII files are parsed via streaming tokenizers supporting scientific float notations.
2
Numeric Sanitization & Guarding
Tests all $(x, y, z)$ coordinates against f64::NAN and $\pm\infty$. Flushes subnormal floats to prevent CPU denormal execution penalties.
3
Spatial Hash Grid Vertex Welding
Raw STLs store 3 independent vertices per triangle. StlTo3mf hashes coordinates into cubic cells of width $\delta = 10^{-6}\text{ mm}$. A 27-neighborhood stencil query collapses coincident points into an indexed representation in $O(N)$ expected time.
4
Degenerate Triangle Pruning
Removes collapsed triangles (duplicate vertex indices) and collinear slivers where cross-product area $\|(\mathbf{v}_1 - \mathbf{v}_0) \times (\mathbf{v}_2 - \mathbf{v}_0)\|^2 < 10^{-24}\text{ mm}^4$.
5
Directed Edge Adjacency & Boundary Loop Detection
Indexes directed edges $u \to v$. Edges lacking an opposite twin $v \to u$ are marked as boundary edges and assembled into closed topological cycles.
6
Topological BFS Winding Propagation
Starting from an arbitrary seed facet, walks adjacent shared edges via BFS. If an adjacent facet shares an edge with identical orientation rather than reversed, its vertex indices are swapped ($v_1 \leftrightarrow v_2$).
7
Outward Normal Rectification via Divergence Theorem
Evaluates polyhedral signed volume $V(\Omega) = \frac{1}{6} \sum \mathbf{p}_0 \cdot (\mathbf{p}_1 \times \mathbf{p}_2)$. If $V < 0$, the shell is wound inside out and all facets are inverted to point outward.
8
Newell Projection & Ear-Clipping Hole Healing
Calculates the best-fit 3D plane normal for each boundary loop using Newell's method, projects onto the dominant 2D axis plane, and clips convex ears to patch holes with valid planar triangles.
9
Dual Face Graph & DSU Shell Splitting
Constructs a dual graph of faces connected by shared undirected edges. Uses Disjoint Set Union with path compression to partition disconnected shells with 0-based re-indexing.
10
Dynamic Scale Sanity Evaluation
Analyzes bounding box dimensions against physical 3D print volumes. Flags anomalies under $2\text{ mm}$ (likely inches or meters) or over $5000\text{ mm}$ (microns or centimeters).
11
Thumbnail Rasterization & OPC ZIP Packaging
Renders an orthographic $256 \times 256$ RGBA thumbnail with Lambertian diffuse shading, builds 3MF XML documents, and writes a Deflate-compressed PKZIP archive.
Mathematics
Mathematical Proofs & Derivations
Rigorous mathematical foundations underpinning StlTo3mf's geometry engine.
1. Gauss-Ostrogradsky Divergence Theorem for Signed Volume
Theorem: Let $\Omega \subset \mathbb{R}^3$ be a compact, orientable 3-manifold with piecewise smooth boundary $\partial \Omega$.
For any continuously differentiable vector field $\mathbf{F}: \Omega \to \mathbb{R}^3$:
Divergence Theorem
β_Ξ© (β Β· F) dV = β¬_βΞ© (F Β· n) dS
Choose the linear position vector field $\mathbf{F}(\mathbf{x}) = \frac{1}{3}\mathbf{x} = \frac{1}{3}(x\hat{\mathbf{i}} + y\hat{\mathbf{j}} + z\hat{\mathbf{k}})$.
The divergence is constantly 1:
β Β· F = 1/3 ( βx/βx + βy/βy + βz/βz ) = 1/3 (1 + 1 + 1) = 1
Substituting into the volume integral:
V(Ξ©) = β_Ξ© 1 dV = 1/3 β¬_βΞ© (x Β· n) dS
For a closed surface discretized into planar triangular facets $f_i = (\mathbf{p}_0, \mathbf{p}_1, \mathbf{p}_2)$, evaluating the surface integral yields the exact summation:
Exact Polyhedral Signed Volume
V(Ξ©) = 1/6 β_{i=1}^{F} p_{0, i} Β· (p_{1, i} Γ p_{2, i})
Decision Criterion: If $V(\Omega) > 0$, the surface facets are consistently wound counter-clockwise when viewed from the outside (normals point outward). If $V(\Omega) < 0$, the shell is inverted; StlTo3mf swaps vertices $\mathbf{p}_1 \leftrightarrow \mathbf{p}_2$ on all faces.
2. Newell's Method for 3D Polygon Normal Estimation
Boundary loops $[v_0, v_1, \dots, v_{k-1}]$ extracted from 3D meshes are often non-planar. Simple cross products of two edges fail when edges are collinear or noisy.
Newell's algorithm calculates the exact projected area integrals along all three cardinal planes:
Newell Normal Components
N_x = β_{i=0}^{k-1} (y_i - y_{i+1})(z_i + z_{i+1})
N_y = β_{i=0}^{k-1} (z_i - z_{i+1})(x_i + x_{i+1})
N_z = β_{i=0}^{k-1} (x_i - x_{i+1})(y_i + y_{i+1})
where index $k \equiv 0$ (cyclic loop). The unit normal is obtained by $\hat{\mathbf{n}} = \mathbf{N} / \|\mathbf{N}\|$.
StlTo3mf projects the loop into 2D by dropping the axis with $\max(|n_x|, |n_y|, |n_z|)$, preventing coordinate distortion before ear-clipping.
3. Ear-Clipping Triangulation with Barycentric Containment
A vertex $w_i$ in a projected 2D polygon $P$ forms a clippable "ear" if it is strictly convex ($\det > 0$) and no other polygon vertex $w_j$ lies within the triangle $\Delta(w_{i-1}, w_i, w_{i+1})$.
Point containment is verified using barycentric coordinates $(\lambda_1, \lambda_2, \lambda_3)$:
Barycentric Coordinates
Ξ»_1 β₯ 0, Ξ»_2 β₯ 0, Ξ»_3 β₯ 0, Ξ»_1 + Ξ»_2 + Ξ»_3 = 1
Packaging
3MF Open Packaging Conventions (OPC) Specification
A valid 3MF file is an Open Packaging Conventions (OPC) PKZIP archive conforming to the 3MF Core Specification v1.x.
model.3mf (Deflate ZIP Archive)
βββ [Content_Types].xml # Declares MIME content types
βββ _rels/
β βββ .rels # Root relationships linking model & thumbnail
βββ 3D/
β βββ 3dmodel.model # 3MF geometric model XML ( & )
β βββ _rels/
β βββ 3dmodel.model.rels # Thumbnail metadata relationship
βββ Metadata/
βββ thumbnail.png # 256x256 RGBA preview thumbnail
Multi-Shell 3D/3dmodel.model Architecture
When multi-shell separation is enabled, each disjoint component is serialized as an independent <object> element with its own unique ID and coordinate buffer:
<?xml version="1.0" encoding="UTF-8"?>
<model unit="millimeter" xml:lang="en-US"
xmlns="http://schemas.microsoft.com/3dmanufacturing/core/2015/02"
xmlns:m="http://schemas.microsoft.com/3dmanufacturing/material/2015/02">
<metadata name="Title">StlTo3mf Multi-Shell Export</metadata>
<metadata name="Application">StlTo3mf (Omni3MF Engine)</metadata>
<resources>
<!-- Color Palette Definition -->
<m:colorgroup id="1">
<m:color color="#38BDF8FF" />
<m:color color="#F97316FF" />
</m:colorgroup>
<!-- Object 1: Body Shell -->
<object id="2" name="Shell_1" type="model" pid="1" pindex="0">
<mesh>
<vertices> ... </vertices>
<triangles> ... </triangles>
</mesh>
</object>
<!-- Object 2: Detail Shell -->
<object id="3" name="Shell_2" type="model" pid="1" pindex="1">
<mesh>
<vertices> ... </vertices>
<triangles> ... </triangles>
</mesh>
</object>
</resources>
<build>
<item objectid="2" />
<item objectid="3" />
</build>
</model>
Compatibility
Slicer Compatibility Matrix
StlTo3mf packages are tested and verified across all major commercial and open-source slicers used in consumer and industrial additive manufacturing.
| Slicer Software |
Verified Versions |
Multi-Shell Splitting |
Sanitizer Protection |
Thumbnail Display |
Overall Status |
| Bambu Studio |
v1.8, v1.9, v2.0+ |
β
Native Multi-Part Dialog |
β
Strips dangerous configs |
β
Renders on LCD & GUI |
β 100% Verified |
| OrcaSlicer |
v1.9, v2.0, v2.1+ |
β
Discrete Per-Object Control |
β
Preserves custom filaments |
β
Full 256x256 display |
β 100% Verified |
| PrusaSlicer |
v2.6, v2.7, v2.8+ |
β
Multi-Object Hierarchy |
β
Drops vendor presets |
β
Plate preview thumbnail |
β 100% Verified |
| UltiMaker Cura |
v5.2, v5.6+ |
β
Multi-Component Grouping |
β
Neutral parameters |
β
Cura project preview |
β 100% Verified |
| SuperSlicer |
v2.4, v2.5+ |
β
Independent Parts List |
β
Clean baseline config |
β
Viewport preview |
β 100% Verified |
Bambu Studio & OrcaSlicer Workflow
- Open Bambu Studio or OrcaSlicer.
- Drag your converted
.3mf file directly onto the build plate.
- When prompted: "Load these objects as a single multi-part object?", select Yes.
- Each separated shell appears in the left object list, allowing 1-click filament / AMS color assignment.
Quality Assurance
Contributing & Synthetic Test Suite
StlTo3mf maintains rigorous quality assurance through a programmatic 85-test synthetic verification suite, guaranteeing stability against pathological geometry.
β οΈ
The Zero-Unsafe Invariant: Every Rust crate in this workspace strictly forbids unsafe code via #![forbid(unsafe_code)]. PRs containing unsafe blocks or disabling this flag will fail automated review gates.
Why Programmatic Synthetic Testing?
To maintain a lightweight git history without checking multi-megabyte binary STL files into the repository, all test meshes are mathematically generated in Rust:
- Canonical Cubes: 12 triangles forming watertight 2-manifold closed boundaries.
- Deliberate Holes: Cubes with dropped faces verifying boundary edge cycle extraction and ear-clipping hole patches.
- Degenerate Facets: Collinear zero-area triangles and duplicate vertices verifying sub-micron spatial hash welding.
- Compound Shells: Multiple separated shapes testing DSU graph clustering and 0-based re-indexing.
Running Verification Gates
Before submitting any pull request, ensure all test gates pass cleanly:
# 1. Check code formatting
cargo fmt --all -- --check
# 2. Enforce zero compiler & clippy warnings
cargo clippy --workspace --all-targets -- -D warnings
# 3. Execute all 85 workspace synthetic and invariant tests
cargo test --workspace
# 4. Execute client-side web engine verification suite
node test/client_engine_test.js