Introduction
Welcome to the lib3mf-rs Guide, comprehensive documentation for the pure Rust implementation of the 3D Manufacturing Format (3MF) specification.
What is lib3mf-rs?
lib3mf-rs is a production-ready, memory-safe library for reading, writing, validating, and processing 3MF files used in 3D printing, additive manufacturing, and CAD workflows. It provides complete support for digital signatures, encryption, advanced materials, slicing, boolean operations, and all official 3MF specifications.
What is 3MF?
The 3D Manufacturing Format (3MF) is an open, XML-based file format designed specifically for additive manufacturing and 3D printing. Unlike older formats like STL or OBJ, 3MF can store:
- Complete 3D geometry (meshes, lattices, voxels)
- Full-color textures and advanced materials
- Manufacturing metadata (part numbers, UUIDs, production paths)
- Digital signatures and encrypted content
- Pre-sliced data for resin printers
- Boolean operations on geometry
- Surface displacement via textures
3MF is maintained by the 3MF Consortium and supported by major CAD and slicing software including PrusaSlicer, Bambu Studio, Cura, Fusion 360, and many others.
Why lib3mf-rs?
Pure Rust — No C++ dependencies, guaranteed memory safety, first-class WASM support.
Complete Specification Support — Implements all 9 official 3MF extensions with 100% coverage across 345 features:
- Core Specification v1.4.0
- Materials and Properties Extension v1.2.1
- Production Extension v1.1.2
- Beam Lattice Extension v1.2.0
- Slice Extension v1.0.2
- Volumetric Extension v0.8.0
- Secure Content Extension v1.0.2
- Boolean Operations Extension v1.1.1
- Displacement Extension v1.0.0
Production Ready — Progressive validation system (Minimal/Standard/Strict/Paranoid), geometry repair utilities, mesh topology analysis, digital signature verification.
High Performance — Optional multi-threading for large files, streaming parser for low memory usage, efficient XML processing, BVH-accelerated geometry checks.
Flexible Feature Flags — Minimal build with ~154 dependencies, optional crypto support adds ~146 more. Choose what you need.
Vendor Extensions — Native support for Bambu Studio project files including multi-plate layouts and filament metadata.
What This Book Covers
This guide is organized into two main sections:
User Guide — Practical tutorials for common workflows:
- Getting Started — Installation, quick start, your first 3MF program
- CLI Guide — Command-line tools for inspecting and analyzing files
- Feature Flags — Minimizing dependencies for your use case
- Validation Guide — Using the 4-level validation system
Reference — Deep technical documentation:
- Architecture Overview — Crate structure, parsing pipeline, design patterns
- Extensions — Details on all 9 3MF extensions
- Contributing — Development setup, testing, adding features
API Reference — For complete API documentation:
- Rustdoc API Reference — Module, struct, and function documentation with examples
- docs.rs — Versioned API docs for released crates
Quick Example
use lib3mf_core::Model;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Load and parse a 3MF file
let model = Model::from_file("model.3mf")?;
// Get statistics
let stats = model.compute_stats()?;
println!("Triangles: {}", stats.geometry.triangle_count);
println!("Vertices: {}", stats.geometry.vertex_count);
// Run validation
let report = model.validate(ValidationLevel::Standard)?;
if report.has_errors() {
eprintln!("Validation errors found: {}", report.error_count());
}
Ok(())
}
Project Links
- GitHub Repository: https://github.com/sscargal/lib3mf-rs
- API Documentation: https://docs.rs/lib3mf-core
- Crates.io: https://crates.io/crates/lib3mf-core
- 3MF Consortium: https://3mf.io/
License
lib3mf-rs is distributed under the MIT License. See the LICENSE file for details.
Getting Started
This guide will help you install lib3mf-rs and write your first 3MF program.
Installation
CLI Tool
The fastest way to try lib3mf-rs is to install the command-line tool:
cargo install lib3mf-cli
This installs the lib3mf-cli binary, which you can use to inspect, validate, and analyze 3MF files without writing any code.
Try it on a 3MF file:
lib3mf-cli stats path/to/model.3mf
Library Dependency
To use lib3mf-rs in your Rust project, add it to your Cargo.toml:
[dependencies]
lib3mf-core = "0.1"
By default, this gives you a minimal build with no optional dependencies. If you need cryptographic features (digital signatures and encryption) or parallel processing, see the Feature Flags chapter.
Quick Start with CLI
The CLI tool provides several commands for working with 3MF files:
# Get file statistics (object count, triangle count, materials)
lib3mf-cli stats model.3mf
# Get JSON output for scripting
lib3mf-cli stats model.3mf --format json
# List archive contents
lib3mf-cli list model.3mf --format tree
# Validate a file (Standard level)
lib3mf-cli validate model.3mf
# Run paranoid validation (deep geometry checks)
lib3mf-cli validate model.3mf --level paranoid
# Compare two versions
lib3mf-cli diff v1.3mf v2.3mf
For complete CLI documentation, see the CLI Guide.
Your First Program
Let’s write a simple program that opens a 3MF file, prints statistics, and runs validation.
Create a new Rust project:
cargo new my_3mf_tool
cd my_3mf_tool
Edit Cargo.toml to add lib3mf-core:
[dependencies]
lib3mf-core = "0.1"
Edit src/main.rs:
use lib3mf_core::Model;
use lib3mf_core::validation::ValidationLevel;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Load and parse the 3MF file
let model = Model::from_file("model.3mf")?;
// Compute statistics
let stats = model.compute_stats()?;
println!("File Statistics:");
println!(" Objects: {}", stats.resource_counts.object_count);
println!(" Triangles: {}", stats.geometry.triangle_count);
println!(" Vertices: {}", stats.geometry.vertex_count);
println!(" Build Items: {}", stats.resource_counts.build_count);
// Run validation at Standard level
let report = model.validate(ValidationLevel::Standard)?;
if report.has_errors() {
eprintln!("\nValidation Errors: {}", report.error_count());
for issue in report.errors() {
eprintln!(" - {}", issue.message);
}
std::process::exit(1);
} else {
println!("\nValidation: PASSED");
}
Ok(())
}
Run it:
cargo run model.3mf
Reading a 3MF File (Step by Step)
The Model::from_file() convenience method is great for simple use cases, but sometimes you need more control. Here’s how to read a 3MF file manually:
use lib3mf_core::archive::{ZipArchiver, ArchiveReader, find_model_path};
use lib3mf_core::parser::parse_model;
use std::fs::File;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Step 1: Open the ZIP archive
let file = File::open("model.3mf")?;
let mut archiver = ZipArchiver::new(file)?;
// Step 2: Find the main model XML file using OPC relationships
let model_path = find_model_path(&mut archiver)?;
println!("Model path: {}", model_path);
// Step 3: Read the model XML data
let model_data = archiver.read_entry(&model_path)?;
// Step 4: Parse XML into Model structure
let model = parse_model(std::io::Cursor::new(model_data))?;
// Step 5: Access model data
println!("Unit: {}", model.unit);
println!("Metadata entries: {}", model.metadata.len());
// Iterate over objects
for (id, obj) in model.resources.iter_objects() {
println!("Object {}: {} triangles", id.0, obj.mesh.triangles.len());
}
Ok(())
}
This lower-level approach gives you access to:
- Archive contents (thumbnails, textures, etc.)
- Raw XML data
- Individual resource inspection before full model computation
For detailed API documentation, see the rustdoc reference for Model.
Writing a 3MF File
You can create a 3MF file programmatically. Here’s how to create a simple cube:
use lib3mf_core::model::{Model, Object, Mesh, Vertex, Triangle, BuildItem};
use lib3mf_core::model::ResourceId;
use lib3mf_core::writer::write_package;
use glam::Vec3;
use std::fs::File;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create a new model with millimeter units
let mut model = Model::new("millimeter".to_string());
// Create cube vertices (-10 to +10mm on each axis)
let vertices = vec![
Vertex { position: Vec3::new(-10.0, -10.0, -10.0) },
Vertex { position: Vec3::new( 10.0, -10.0, -10.0) },
Vertex { position: Vec3::new( 10.0, 10.0, -10.0) },
Vertex { position: Vec3::new(-10.0, 10.0, -10.0) },
Vertex { position: Vec3::new(-10.0, -10.0, 10.0) },
Vertex { position: Vec3::new( 10.0, -10.0, 10.0) },
Vertex { position: Vec3::new( 10.0, 10.0, 10.0) },
Vertex { position: Vec3::new(-10.0, 10.0, 10.0) },
];
// Create 12 triangles (2 per face)
let triangles = vec![
// Bottom face (z = -10)
Triangle::new(0, 1, 2),
Triangle::new(0, 2, 3),
// Top face (z = +10)
Triangle::new(4, 6, 5),
Triangle::new(4, 7, 6),
// Front face (y = -10)
Triangle::new(0, 5, 1),
Triangle::new(0, 4, 5),
// Back face (y = +10)
Triangle::new(3, 2, 6),
Triangle::new(3, 6, 7),
// Left face (x = -10)
Triangle::new(0, 3, 7),
Triangle::new(0, 7, 4),
// Right face (x = +10)
Triangle::new(1, 5, 6),
Triangle::new(1, 6, 2),
];
let mesh = Mesh::new(vertices, triangles);
let object = Object::new_model(mesh);
// Add object to model resources
let object_id = ResourceId(1);
model.resources.add_object(object_id, object)?;
// Add object to build (what will be printed)
let build_item = BuildItem {
object_id,
transform: None, // Identity transform (no rotation/translation)
part_number: None,
};
model.build.items.push(build_item);
// Write to file
let output = File::create("cube.3mf")?;
write_package(&model, output)?;
println!("Created cube.3mf");
Ok(())
}
For more examples, check out the examples directory in the repository:
create_cube.rs— Building a 3MF model from scratchadvanced_materials.rs— Textures and composite materialsgeometry_validation.rs— Using paranoid validation to find issuesgeometry_repair.rs— Programmatic mesh repairsecure_content.rs— Digital signatures and encryptionbeam_lattice_ext.rs— Creating structural lattice designsboolean_operations.rs— Union, difference, intersection operationsdisplacement_mesh.rs— Texture-driven surface modificationslice_data.rs— Pre-sliced geometry for resin printersstreaming_stats.rs— Processing large files with constant memory
Next Steps
- CLI Guide — Learn all the command-line tools
- Architecture Overview — Understand how lib3mf-rs is structured
- Validation Guide — Deep dive into the validation system
- Extensions — Working with advanced 3MF features
- API Reference — Complete API documentation
CLI Guide
The lib3mf-cli command-line tool provides comprehensive commands for inspecting, validating, and analyzing 3MF files without writing code.
Installation
cargo install lib3mf-cli
This installs the lib3mf-cli binary. You can verify installation:
lib3mf-cli --version
Quick Reference
| Command | Purpose |
|---|---|
stats | Display file statistics (objects, triangles, materials) |
list | List archive contents |
validate | Run validation checks |
copy | Copy/rewrite a 3MF file (roundtrip test) |
diff | Compare two 3MF files |
extract | Extract files from the archive |
Commands in Detail
stats — File Statistics
Get a summary of the model including geometry counts, materials, and vendor metadata.
Basic usage:
lib3mf-cli stats model.3mf
Example output:
File: model.3mf
Unit: millimeter
Resources:
Objects: 5
- Model: 3
- Support: 1
- SolidSupport: 1
Materials: 2
Textures: 1
Build Items: 3
Geometry:
Triangles: 48,562
Vertices: 24,281
Surface Area: 15,234.5 mm²
Volume: 42,891.2 mm³
Extensions:
- Materials and Properties v1.2.1
- Production Extension v1.1.2
JSON output for scripting:
lib3mf-cli stats model.3mf --format json
{
"file_path": "model.3mf",
"unit": "millimeter",
"resource_counts": {
"object_count": 5,
"material_count": 2,
"texture_count": 1,
"build_count": 3,
"type_counts": {
"Model": 3,
"Support": 1,
"SolidSupport": 1
}
},
"geometry": {
"triangle_count": 48562,
"vertex_count": 24281,
"surface_area": 15234.5,
"volume": 42891.2
},
"extensions": [
"Materials and Properties v1.2.1",
"Production Extension v1.1.2"
]
}
When to use:
- Quick inspection of 3MF files
- Automated testing (check triangle counts)
- CI/CD validation pipelines
- Comparing file complexity
list — Archive Contents
List all files inside the 3MF archive (3MF is a ZIP container).
Basic usage:
lib3mf-cli list model.3mf
Example output:
[Content_Types].xml (358 bytes)
_rels/.rels (237 bytes)
3D/3dmodel.model (125,482 bytes)
3D/_rels/3dmodel.model.rels (412 bytes)
Metadata/thumbnail.png (18,592 bytes)
Metadata/model_thumbnail.png (22,145 bytes)
Tree view:
lib3mf-cli list model.3mf --format tree
Example output:
model.3mf/
├── [Content_Types].xml (358 bytes)
├── _rels/
│ └── .rels (237 bytes)
├── 3D/
│ ├── 3dmodel.model (125,482 bytes)
│ └── _rels/
│ └── 3dmodel.model.rels (412 bytes)
└── Metadata/
├── thumbnail.png (18,592 bytes)
└── model_thumbnail.png (22,145 bytes)
When to use:
- Debugging OPC structure issues
- Finding thumbnails or textures
- Understanding vendor-specific file layouts
- Investigating Bambu Studio project files
validate — Validation Checks
Run validation at different levels to check file integrity and spec compliance.
Basic usage (Standard level):
lib3mf-cli validate model.3mf
Example output (no errors):
Validation Level: Standard
Status: PASSED
Issues: 0 errors, 0 warnings, 1 info
Info:
- Model uses millimeter units
Example output (with errors):
Validation Level: Standard
Status: FAILED
Issues: 2 errors, 1 warning, 0 info
Errors:
- Object 5 referenced in build but not defined in resources
- Triangle 142 in object 3 references vertex index 500 (out of bounds)
Warnings:
- Object 7 defined but never used in build
Validation levels:
# Minimal — Basic structural checks only
lib3mf-cli validate model.3mf --level minimal
# Standard — Reference integrity (default)
lib3mf-cli validate model.3mf --level standard
# Strict — Full spec compliance
lib3mf-cli validate model.3mf --level strict
# Paranoid — Deep geometry analysis (manifoldness, self-intersection)
lib3mf-cli validate model.3mf --level paranoid
JSON output:
lib3mf-cli validate model.3mf --format json
{
"level": "Standard",
"passed": false,
"error_count": 2,
"warning_count": 1,
"info_count": 0,
"issues": [
{
"severity": "Error",
"code": 3001,
"message": "Object 5 referenced in build but not defined in resources"
},
{
"severity": "Error",
"code": 2042,
"message": "Triangle 142 in object 3 references vertex index 500 (out of bounds)"
},
{
"severity": "Warning",
"code": 4010,
"message": "Object 7 defined but never used in build"
}
]
}
When to use:
- Pre-flight checks before printing
- CI/CD quality gates
- Debugging invalid files
- Compliance certification
See the Validation Guide for details on validation levels and error codes.
copy — Roundtrip Test
Read a 3MF file and write it to a new file. This tests the parser → model → writer pipeline.
Usage:
lib3mf-cli copy input.3mf output.3mf
Example output:
Reading: input.3mf
Parsing model...
Writing: output.3mf
Done. Objects: 3, Triangles: 1,542
When to use:
- Testing parser and writer compatibility
- Normalizing 3MF files (remove vendor extensions)
- Verifying roundtrip fidelity
- Converting between 3MF versions
diff — Compare Models
Compare two 3MF files to find structural or metadata differences.
Usage:
lib3mf-cli diff v1.3mf v2.3mf
Example output:
Comparing:
v1.3mf
v2.3mf
Differences found:
Geometry:
✓ Triangle count: 1,542 (same)
✗ Vertex count: 771 → 823 (+52)
Resources:
✗ Objects: 3 → 4 (+1)
✓ Materials: 2 (same)
Build:
✓ Build items: 3 (same)
Metadata:
✗ Title: "Model v1" → "Model v2"
+ Author: "John Doe" (added)
When to use:
- Reviewing CAD export changes
- Debugging slicer modifications
- Version control for 3MF files
- Regression testing
extract — Extract Archive Files
Extract specific files from the 3MF archive (thumbnails, textures, etc.).
Usage:
lib3mf-cli extract model.3mf "Metadata/thumbnail.png" --output thumb.png
Example output:
Extracting: Metadata/thumbnail.png
Written to: thumb.png (18,592 bytes)
Extract multiple files:
# Extract all thumbnails
lib3mf-cli extract model.3mf "Metadata/thumbnail.png"
lib3mf-cli extract model.3mf "Metadata/model_thumbnail.png"
When to use:
- Extracting preview images
- Debugging texture issues
- Analyzing vendor-specific files
- Inspecting encrypted content metadata
Common Workflows
Pre-Print Validation
# Run paranoid validation before printing
lib3mf-cli validate model.3mf --level paranoid
# If validation passes, check geometry stats
lib3mf-cli stats model.3mf
CI/CD Pipeline
#!/bin/bash
# QA script for 3MF exports
# Validate file
lib3mf-cli validate $1 --level strict --format json > validation.json
# Check for errors
if grep -q '"passed": false' validation.json; then
echo "Validation failed"
cat validation.json
exit 1
fi
# Verify expected geometry
lib3mf-cli stats $1 --format json > stats.json
triangle_count=$(grep -o '"triangle_count": [0-9]*' stats.json | grep -o '[0-9]*')
if [ "$triangle_count" -lt 1000 ]; then
echo "Error: Too few triangles ($triangle_count)"
exit 1
fi
echo "QA passed: $triangle_count triangles"
Debugging Invalid Files
# Step 1: Check archive structure
lib3mf-cli list broken.3mf --format tree
# Step 2: Run minimal validation (skip geometry checks)
lib3mf-cli validate broken.3mf --level minimal
# Step 3: If minimal passes, try standard
lib3mf-cli validate broken.3mf --level standard
# Step 4: Get detailed stats
lib3mf-cli stats broken.3mf
Comparing Slicer Exports
# Compare before and after slicer processing
lib3mf-cli diff original.3mf sliced.3mf
# Extract thumbnails to visually compare
lib3mf-cli extract sliced.3mf "Metadata/thumbnail.png" --output sliced_thumb.png
Exit Codes
The CLI uses standard exit codes:
0— Success1— Validation failed or file error2— Invalid arguments or usage
This allows easy integration with shell scripts:
if lib3mf-cli validate model.3mf --level strict; then
echo "File is valid"
else
echo "File has errors"
fi
Next Steps
- Validation Guide — Understanding validation levels and error codes
- Feature Flags — Building custom CLI tools
- API Reference — CLI implementation details
Feature Flags
lib3mf-core uses Cargo feature flags to minimize dependencies, allowing you to choose exactly what functionality you need.
Overview
By default, lib3mf-core has zero optional dependencies. This gives you the smallest possible build with just core 3MF parsing and writing capabilities.
You can selectively enable features based on your requirements:
| Feature | What It Enables | Dependencies Added | When to Use |
|---|---|---|---|
crypto | Digital signatures and encryption (Secure Content Extension) | aes-gcm, rsa, sha1, sha2, x509-parser, rand, base64 (~146 crates) | Signed/encrypted 3MF files |
parallel | Multi-threaded mesh processing using Rayon | rayon (~6 crates) | Large files, multi-core CPUs |
png-validation | PNG texture validation | png (~15 crates) | Texture quality checks |
full | All features enabled | All of the above | Complete functionality |
Dependency Impact
Minimal build (no features):
[dependencies]
lib3mf-core = { version = "0.1", default-features = false }
Result: ~154 crate dependencies
Crypto-enabled build:
[dependencies]
lib3mf-core = { version = "0.1", features = ["crypto"] }
Result: ~300 crate dependencies (+146 from crypto)
Full-featured build:
[dependencies]
lib3mf-core = { version = "0.1", features = ["full"] }
Result: ~300 crate dependencies (crypto dominates)
Users who don’t need cryptographic features save 48% of dependencies.
Feature Combinations
Minimal — Smallest Footprint
[dependencies]
lib3mf-core = { version = "0.1", default-features = false }
Provides:
- Core 3MF parsing and writing
- All geometry types (meshes, lattices, slices, voxels)
- All material types (colors, textures, composites)
- Boolean operations and displacement (parsing only, no evaluation)
- Validation (all 4 levels)
- Single-threaded mesh processing
Missing:
- Digital signature verification
- Content encryption/decryption
- Multi-threaded mesh processing
- PNG texture validation
Best for:
- Embedded systems
- WebAssembly builds
- Size-critical applications
- Applications that don’t need security features
Crypto Only — Secure Files
[dependencies]
lib3mf-core = { version = "0.1", features = ["crypto"] }
Adds:
- XML-DSIG digital signature verification
- AES-GCM content encryption/decryption
- X.509 certificate parsing
- RSA public key operations
Use when:
- Working with signed 3MF files
- Working with encrypted content
- Manufacturing workflows requiring authenticity verification
- Single-threaded processing is acceptable
Parallel Only — Fast Processing
[dependencies]
lib3mf-core = { version = "0.1", features = ["parallel"] }
Adds:
- Rayon-based parallel iteration
- Multi-threaded AABB computation
- Parallel area/volume calculation
- Parallel statistics computation
Use when:
- Processing large meshes (>100K triangles)
- Multi-core CPU available
- Speed is more important than dependency count
- No security features needed
Full-Featured — Everything
[dependencies]
lib3mf-core = { version = "0.1", features = ["full"] }
Enables:
- All crypto features
- All parallel features
- PNG texture validation
Use when:
- Building production tools
- Need all functionality
- Dependency count not a concern
- Desktop or server applications
Checking Dependency Count
You can verify the dependency count for different feature combinations:
# Minimal build
cargo tree -p lib3mf-core --no-default-features | wc -l
# Crypto only
cargo tree -p lib3mf-core --no-default-features --features crypto | wc -l
# Parallel only
cargo tree -p lib3mf-core --no-default-features --features parallel | wc -l
# Full-featured
cargo tree -p lib3mf-core --all-features | wc -l
Build Time and Binary Size Impact
Feature flags affect both compile time and binary size:
| Configuration | Compile Time (clean) | Binary Size (release) | Notes |
|---|---|---|---|
| Minimal | ~30s | ~2.5 MB | Fastest builds |
| Crypto only | ~90s | ~4.2 MB | Crypto adds significant compile time |
| Parallel only | ~35s | ~2.8 MB | Rayon is lightweight |
| Full | ~90s | ~4.5 MB | Crypto dominates |
Measured on Apple M1 Max with 10 cores
Feature-Gated API Items
Some API items are only available when specific features are enabled. The rustdoc documentation marks these with badges:
Crypto-gated items:
model::SecureContentcrypto::verify_signature()crypto::decrypt_content()model::KeyStore
Parallel-gated behavior:
Model::compute_stats()uses parallel iteration whenparallelenabledMesh::compute_aabb()parallelizes across trianglesvalidation::geometry::check_self_intersection()uses parallel BVH construction
PNG-validation-gated:
validation::validate_png_texture()
In your code, you can check for features with:
#[cfg(feature = "crypto")]
use lib3mf_core::crypto::verify_signature;
#[cfg(feature = "crypto")]
fn verify_model(model: &Model) -> Result<bool> {
verify_signature(&model.signature?)
}
#[cfg(not(feature = "crypto"))]
fn verify_model(_model: &Model) -> Result<bool> {
Err("Crypto feature not enabled".into())
}
Recommendations
For applications:
- CLI tools → Use
full(users expect all features) - Web services → Use
crypto+parallel(security + speed) - WASM builds → Use minimal (size matters, crypto doesn’t work in WASM)
- Embedded → Use minimal (constrained resources)
For libraries:
- Re-export lib3mf-core with
default-features = false - Let users choose features via your crate’s feature flags
- Document which lib3mf features you require
Example library pattern:
[dependencies]
lib3mf-core = { version = "0.1", default-features = false }
[features]
default = []
crypto = ["lib3mf-core/crypto"]
parallel = ["lib3mf-core/parallel"]
full = ["crypto", "parallel"]
CI/CD Testing
To ensure your code works with different feature combinations, test them all in CI:
# GitHub Actions example
strategy:
matrix:
features:
- "--no-default-features"
- "--features crypto"
- "--features parallel"
- "--all-features"
steps:
- run: cargo test -p lib3mf-core ${{ matrix.features }}
lib3mf-rs uses this approach to guarantee compatibility across all configurations.
Next Steps
- Getting Started — Choose features for your first program
- Extensions — Learn which extensions require which features
- API Reference — See feature badges on API items
Validation Guide
lib3mf-rs provides a comprehensive 4-level progressive validation system to ensure 3MF file integrity and specification compliance.
Overview
Validation checks 3MF files for errors ranging from basic structure issues to deep geometry problems. The system uses four levels that progressively increase in thoroughness:
- Minimal — Basic structural checks (fastest)
- Standard — Reference integrity and common issues (recommended)
- Strict — Full specification compliance
- Paranoid — Deep geometry analysis (slowest, most thorough)
Quick Start
use lib3mf_core::Model;
use lib3mf_core::validation::ValidationLevel;
let model = Model::from_file("model.3mf")?;
let report = model.validate(ValidationLevel::Standard)?;
if report.has_errors() {
eprintln!("Validation failed: {} errors", report.error_count());
for error in report.errors() {
eprintln!(" - {}", error.message);
}
} else {
println!("Validation passed!");
}
Validation Levels
Minimal — Quick Structural Check
What it checks:
- XML is well-formed
- Required elements present (
<model>,<resources>,<build>) - Resource IDs are valid integers
- ZIP archive is readable
- Basic OPC structure exists
What it skips:
- Reference integrity (broken links)
- Geometry validation
- Spec compliance details
Use when:
- CI/CD pipelines (fast feedback)
- Quick file format detection
- Pre-validation before deeper checks
- Processing untrusted files (fail fast)
Performance: <10ms for most files
Example:
let report = model.validate(ValidationLevel::Minimal)?;
Standard — Reference Integrity (Recommended)
What it checks:
- Everything from Minimal level
- All resource references valid (objects, materials, textures)
- Build items reference existing objects
- Triangle vertex indices within bounds
- Property references valid
- Material/texture paths exist
- Component hierarchies valid
What it skips:
- Geometry quality checks (manifoldness, self-intersection)
- Strict spec compliance (ranges, optional attributes)
- Deep validation of extension data
Use when:
- Production file processing (default level)
- Pre-print validation
- General file integrity checks
- Most applications
Performance: ~100ms for 100K triangles
Example:
let report = model.validate(ValidationLevel::Standard)?;
// Check for specific severity levels
println!("Errors: {}", report.error_count());
println!("Warnings: {}", report.warning_count());
println!("Info: {}", report.info_count());
Strict — Full Specification Compliance
What it checks:
- Everything from Standard level
- All attribute ranges per spec (coordinates, colors, UVs)
- Required vs. optional attribute presence
- Namespace declarations
- Extension version compatibility
- Metadata format compliance
- Unit validation (mm, inch, micron, etc.)
What it skips:
- Deep geometry checks (performance intensive)
Use when:
- Compliance certification
- 3MF Consortium validation
- Exporter testing
- Strict quality requirements
Performance: ~150ms for 100K triangles
Example:
let report = model.validate(ValidationLevel::Strict)?;
for issue in report.all_issues() {
match issue.severity {
Severity::Error => eprintln!("ERROR: {}", issue.message),
Severity::Warning => println!("WARN: {}", issue.message),
Severity::Info => println!("INFO: {}", issue.message),
}
}
Paranoid — Deep Geometry Analysis
What it checks:
- Everything from Strict level
- Manifoldness — Every edge has exactly 2 adjacent triangles
- Vertex manifoldness — No singular vertices or edge singularities
- Self-intersection — BVH-accelerated triangle-triangle intersection tests
- Orientation consistency — All face normals point consistently outward
- Degenerate triangles — Zero-area or duplicate-vertex triangles
- Island detection — Connected component analysis
- Watertightness — No holes or boundary edges
Use when:
- Pre-print validation (avoid print failures)
- Geometry repair workflows
- Quality assurance for manufacturing
- Debugging mesh issues
Performance: ~5 seconds for 100K triangles (depends on geometry complexity)
Example:
let report = model.validate(ValidationLevel::Paranoid)?;
if report.has_errors() {
println!("Geometry issues found:");
for error in report.errors() {
println!(" - {}", error.message);
}
// Consider mesh repair
use lib3mf_core::model::repair::MeshRepair;
for (id, obj) in model.resources.iter_objects() {
let repaired = obj.mesh.stitch_vertices(0.001)?;
println!("Object {}: repaired", id.0);
}
}
Understanding Validation Reports
Severity Levels
Error — File violates specification, may cause failures:
- Missing required resources
- Invalid references
- Out-of-bounds indices
- Geometry defects (at Paranoid level)
Warning — Unusual but technically valid:
- Unused resources (defined but not in build)
- Empty resource groups
- Non-optimal geometry
Info — Informational messages:
- Units used (millimeter, inch, etc.)
- Extensions detected
- Statistics (object count, triangle count)
Error Codes
Validation errors use numeric codes for programmatic handling:
| Code Range | Category |
|---|---|
| 1000-1999 | XML/Structure errors |
| 2000-2999 | Resource errors |
| 3000-3999 | Build errors |
| 4000-4999 | Geometry errors |
| 5000-5999 | Extension errors |
Example error codes:
2001— Resource ID not found2042— Triangle vertex index out of bounds3010— Build item references invalid object type4015— Non-manifold edge detected4020— Self-intersection found
Accessing Report Data
use lib3mf_core::validation::{ValidationReport, Severity};
fn analyze_report(report: &ValidationReport) {
// Check overall status
if report.passed() {
println!("Validation passed");
return;
}
// Count by severity
println!("Errors: {}", report.error_count());
println!("Warnings: {}", report.warning_count());
// Get specific severity issues
for error in report.errors() {
println!("ERROR [{}]: {}", error.code, error.message);
}
for warning in report.warnings() {
println!("WARN: {}", warning.message);
}
// Access all issues
for issue in report.all_issues() {
println!("{:?}: {}", issue.severity, issue.message);
}
}
Geometry Validation Details
At the Paranoid level, lib3mf-rs performs sophisticated geometry analysis:
Manifoldness Check
Every edge should have exactly 2 adjacent triangles (closed surface):
// Non-manifold edges are detected:
// - Boundary edges (only 1 triangle)
// - Over-connected edges (3+ triangles)
Common causes:
- Holes in geometry
- T-junctions
- Duplicate triangles
Vertex Manifoldness
Vertices must have valid topological neighborhoods:
// Detects:
// - Singular vertices (vertex used by non-connected triangles)
// - Edge singularities (fan of triangles meeting at edge)
Self-Intersection Detection
Uses BVH (Bounding Volume Hierarchy) for efficient O(n log n) intersection testing:
// Checks all triangle pairs for intersection
// Reports intersecting triangle IDs
Performance: BVH acceleration makes this practical even for large meshes.
Orientation Consistency
All face normals should point outward consistently:
// Uses directed edge analysis
// Reports reversed triangles
Fix: Mesh repair can harmonize orientation automatically.
Degenerate Triangle Detection
Finds zero-area or invalid triangles:
// Detects:
// - Duplicate vertices in triangle (v1 == v2)
// - Zero-area triangles (collinear vertices)
Mesh Repair
When Paranoid validation finds issues, use the MeshRepair trait:
use lib3mf_core::model::repair::MeshRepair;
let mesh = obj.mesh;
// Stitch nearby vertices (merge within tolerance)
let stitched = mesh.stitch_vertices(0.001)?;
// Remove degenerate triangles
let cleaned = stitched.remove_degenerate_faces()?;
// Harmonize orientation (fix reversed normals)
let fixed = cleaned.harmonize_orientation()?;
println!("Repair stats:");
println!(" Vertices merged: {}", stitched.repair_stats.vertices_merged);
println!(" Triangles removed: {}", cleaned.repair_stats.triangles_removed);
println!(" Triangles flipped: {}", fixed.repair_stats.triangles_flipped);
Repair operations return new Mesh instances (immutable design).
Common Validation Errors and Fixes
Error: Object referenced in build but not defined
Cause: Build item references object ID that doesn’t exist in resources.
Fix:
// Remove invalid build items
model.build.items.retain(|item| {
model.resources.get_object(item.object_id).is_some()
});
Error: Triangle vertex index out of bounds
Cause: Triangle references vertex index >= vertex count.
Fix: Mesh is corrupted, regenerate or repair geometry.
Error: Non-manifold edge detected
Cause: Geometry has holes or inconsistent connectivity.
Fix:
let repaired = mesh.stitch_vertices(0.001)?;
Warning: Object defined but never used
Cause: Resource exists but no build item references it.
Fix: Either add to build or remove resource (cosmetic issue).
CLI Validation
Use the CLI tool for quick validation:
# Standard level (default)
lib3mf-cli validate model.3mf
# Paranoid level (deep checks)
lib3mf-cli validate model.3mf --level paranoid
# JSON output for scripting
lib3mf-cli validate model.3mf --format json > report.json
See the CLI Guide for details.
Performance Tuning
For large files:
- Start with Minimal to fail fast
- Use Standard for most checks
- Reserve Paranoid for final QA
For CI/CD:
- Minimal: <10ms (good for pre-commit hooks)
- Standard: ~100ms (good for PR checks)
- Paranoid: ~5s (good for release validation)
Parallel validation:
When built with the parallel feature, geometry checks use multi-threading automatically:
cargo build --features parallel
This can reduce Paranoid validation time by 2-4x on multi-core systems.
Next Steps
- CLI Guide — Command-line validation tools
- Architecture — How validation system works internally
- API Reference — Detailed validation API docs
Architecture Overview
This chapter explains the internal architecture of lib3mf-rs, including crate structure, data flow pipeline, and key design patterns.
Crate Structure
lib3mf-rs is organized as a Cargo workspace with five crates:
lib3mf-rs/
├── crates/
│ ├── lib3mf-core/ # Main library implementation
│ ├── lib3mf-cli/ # Command-line interface
│ ├── lib3mf-converters/ # STL and OBJ format converters
│ ├── lib3mf-async/ # Async I/O with tokio
│ └── lib3mf-wasm/ # WebAssembly bindings
├── fuzz/ # Fuzzing targets (cargo-fuzz)
├── book/ # This documentation (mdBook)
└── Cargo.toml # Workspace definition
lib3mf-core — The main library containing:
- Archive layer (ZIP/OPC package handling)
- Parser layer (XML to model conversion)
- Model layer (immutable data structures)
- Validation layer (4-level progressive validation)
- Writer layer (model to XML/ZIP serialization)
- Crypto layer (digital signatures and encryption)
lib3mf-cli — Binary crate providing command-line tools for inspecting, validating, and analyzing 3MF files.
lib3mf-converters — Standalone converters between 3MF and other formats (STL, OBJ).
lib3mf-async — Asynchronous I/O support using tokio and async-zip for non-blocking file operations.
lib3mf-wasm — WebAssembly bindings for running lib3mf-rs in browsers and WASM runtimes.
Data Flow Pipeline
The library follows a layered architecture where each layer has a single responsibility:
Archive Layer (ZIP/OPC)
↓
Parser Layer (XML)
↓
Model Layer (Immutable)
↓
Validation/Processing
↓
Writer Layer (XML/ZIP)
Typical Read Workflow
- Archive Layer —
ZipArchiver::new()opens the 3MF file (ZIP container) - OPC Layer — Read
_rels/.relsto discover main model XML path viafind_model_path() - Parser Layer —
parse_model()converts XML into in-memoryModelstructure - Model Layer —
Modelcontains resources (objects, materials, textures) and build instructions - Validation Layer — Apply checks at chosen level (Minimal/Standard/Strict/Paranoid)
Typical Write Workflow
- Model Layer — Create or modify
Modelstructure programmatically - Writer Layer —
write_package()serializes model to XML and ZIP - Archive Layer — Write OPC relationships and package structure
- Output — Produces a valid 3MF file
Module Structure in lib3mf-core
archive/ — OPC Container Handling
Key files:
zip_archive.rs— ZIP wrapper implementingArchiveReadertraitopc.rs— Open Packaging Convention (relationships and content types)
The ArchiveReader trait abstracts over different archive backends, allowing the parser to work with any ZIP implementation or even in-memory archives for testing.
pub trait ArchiveReader {
fn read_entry(&mut self, path: &str) -> Result<Vec<u8>>;
fn entry_names(&mut self) -> Result<Vec<String>>;
}
parser/ — XML to Model Conversion
Key files:
model_parser.rs— Main orchestrator parsing<model>elementmesh_parser.rs— Geometry parsing (vertices, triangles)material_parser.rs— Materials (colors, textures, composites)beamlattice_parser.rs— Beam Lattice Extension parserslice_parser.rs— Slice Extension parsersecure_content_parser.rs— Secure Content Extension parserstreaming.rs— SAX-style event-based parser for large files
Design: Modular parsing where each extension has its own parser. The main parser delegates to extension parsers based on XML namespaces.
model/ — Core Data Structures
Key files:
core.rs— RootModelstructresources.rs—ResourceCollection(central resource registry)mesh.rs— Geometry types (Mesh,Triangle,Vertex,BeamLattice)materials.rs— Material types (BaseMaterial, ColorGroup, Texture2D, Composite, MultiProperties)build.rs—BuildandBuildItem(what to print and where)secure_content.rs— Encryption/signature metadatarepair.rs—MeshRepairtrait for geometry fixing
Design: Immutable-by-default. Structures use Clone semantics. Mutation happens via explicit repair operations.
pub struct Model {
pub unit: String,
pub metadata: Vec<MetadataEntry>,
pub resources: ResourceCollection,
pub build: Build,
pub attachments: Vec<Attachment>,
}
validation/ — Progressive Validation System
Key files:
validator.rs— Main validation orchestrationgeometry.rs— Geometry checks (manifoldness, self-intersection, orientation)bvh.rs— Bounding Volume Hierarchy for O(n log n) intersection testsreport.rs— Structured validation results
Four validation levels:
- Minimal — Basic structural checks (well-formed XML, valid IDs)
- Standard — Reference integrity (all referenced resources exist)
- Strict — Full spec compliance (ranges, formats, constraints)
- Paranoid — Deep geometry analysis (manifoldness, self-intersection, orientation)
writer/ — Model to File Serialization
Key files:
model_writer.rs— Main model serializationmesh_writer.rs— Geometry serializationpackage_writer.rs— Top-level package orchestrationopc_writer.rs— OPC relationships and content types
Design: Mirrors parser structure but in reverse. Each module is responsible for writing its corresponding XML elements.
crypto/ — Secure Content Extension
Key files:
signature.rs— XML-DSIG digital signature verificationencryption.rs— Content encryption/decryption (AES-GCM)cert.rs— X.509 certificate parsing
Feature-gated: Only available when crypto feature is enabled to reduce dependencies.
Key Design Patterns
Immutable Model Design
Model and child structures are immutable by default. This provides:
- Thread safety — Safe to share models across threads
- Predictable behavior — No hidden mutations
- Easier testing — No state changes between operations
Mutation happens explicitly via repair operations:
use lib3mf_core::model::repair::MeshRepair;
let repaired = mesh.stitch_vertices(epsilon)?;
Trait-Based Abstractions
ArchiveReader — Decouples parser from ZIP implementation:
pub trait ArchiveReader {
fn read_entry(&mut self, path: &str) -> Result<Vec<u8>>;
fn entry_names(&mut self) -> Result<Vec<String>>;
}
ModelVisitor — Visitor pattern for streaming parser:
pub trait ModelVisitor {
fn visit_object(&mut self, id: ResourceId, object: &Object);
fn visit_build_item(&mut self, item: &BuildItem);
}
MeshRepair — Trait for mesh repair operations:
pub trait MeshRepair {
fn stitch_vertices(&self, epsilon: f32) -> Result<Self>;
fn remove_degenerate_faces(&self) -> Result<Self>;
fn harmonize_orientation(&self) -> Result<Self>;
}
Error Handling Strategy
Uses thiserror for custom error types:
#[derive(Debug, thiserror::Error)]
pub enum Lib3mfError {
#[error("Parse error: {0}")]
ParseError(String),
#[error("Validation failed: {0}")]
ValidationError(String),
#[error("IO error: {0}")]
IoError(#[from] std::io::Error),
}
pub type Result<T> = std::result::Result<T, Lib3mfError>;
Philosophy: No panics in library code. All errors are expected and recoverable.
Two Parsing Modes
DOM Mode — Loads entire model into memory:
let model = parse_model(reader)?; // Fast, simple, <100MB files
SAX Mode — Event-based streaming:
struct MyVisitor;
impl ModelVisitor for MyVisitor {
fn visit_object(&mut self, id: ResourceId, object: &Object) {
// Process objects as they're parsed
}
}
parse_model_streaming(reader, &mut MyVisitor)?; // Constant memory, GB+ files
Resource Management
Resources use a typed ID system to prevent mixing different resource types:
pub struct ResourceId(pub u32); // Newtype pattern
pub struct ResourceCollection {
objects: HashMap<ResourceId, Object>,
materials: HashMap<ResourceId, BaseMaterialGroup>,
textures: HashMap<ResourceId, Texture2D>,
// ...
}
All resources share a global ID namespace within a model. Duplicate IDs are detected and rejected.
Property System (Materials on Geometry)
Materials can be applied at multiple levels with a clear precedence hierarchy:
- Per-vertex properties —
Trianglewithp1,p2,p3attributes - Per-triangle properties —
Trianglewithpidattribute - Per-object default —
Objectwithpidandpindex
Resolution order: Triangle → Vertex → Object → None
Performance Characteristics
Hotspots
XML Parsing — Uses quick-xml (event-based, fast, zero-copy where possible)
Float Parsing — Uses lexical-core (spec-compliant and 2-5x faster than stdlib)
Self-Intersection Detection — Uses BVH (Bounding Volume Hierarchy) for O(n log n) instead of naive O(n²)
Statistics Computation — Can be parallelized with Rayon when parallel feature enabled
Memory vs Speed Tradeoffs
| Approach | Speed | Memory | Best For |
|---|---|---|---|
DOM mode (parse_model) | Fast | O(n) | Files <100MB |
| SAX mode (streaming) | Slower | O(1) | Files >1GB |
| Parallel (Rayon) | Fastest | O(n) | Large meshes with multi-core CPU |
Feature Flags and Dependencies
| Configuration | Dependency Count | Use Case |
|---|---|---|
Minimal (default = []) | ~154 crates | Embedded systems, WASM, size-critical |
| Crypto only | ~300 crates | Secure files, signature verification |
| Parallel only | ~160 crates | Fast mesh processing, no security |
Full (features = ["full"]) | ~300 crates | Complete functionality |
Users who don’t need crypto save 48% of dependencies.
Extension Architecture
Extensions are first-class citizens integrated directly into core structures:
Parser Integration:
- Each extension has its own parser module
- Main parser delegates based on XML namespace
- Extensions can add new resource types to
ResourceCollection
Model Integration:
- Extension data stored directly in model structures
- No separate “extension bag” — type-safe access
- Geometry enum includes extension types (BeamLattice, SliceStack, etc.)
Validation Integration:
- Extensions contribute their own validation rules
- Integrated into 4-level validation system
- Extension-specific error codes
Example: Boolean Operations Extension adds BooleanShape to Geometry enum and provides its own parser, validator, and writer.
Next Steps
- Extensions — Details on all 9 3MF extensions
- Validation Guide — Deep dive into validation system
- Contributing — Adding new extensions or features
- API Reference — Complete API documentation
Extensions
The 3MF specification is modular, with a core specification and optional extensions that add specialized capabilities. lib3mf-rs implements all 9 official extensions with 100% feature coverage.
What are 3MF Extensions?
Extensions are additions to the core 3MF specification that enable advanced manufacturing scenarios. They use XML namespaces to add new elements and attributes without breaking compatibility.
A 3MF file can use multiple extensions simultaneously. For example, a file might combine Materials (colors/textures), Production (part tracking), and Slice (pre-sliced layers) extensions.
Supported Extensions
| Extension | Version | Feature Coverage | Required lib3mf Feature |
|---|---|---|---|
| Core Specification | v1.4.0 | 98/100 (98%) | None (always available) |
| Materials and Properties | v1.2.1 | 38/38 (100%) | None |
| Production | v1.1.2 | 20/20 (100%) | None |
| Beam Lattice | v1.2.0 | 29/29 (100%) | None |
| Slice | v1.0.2 | 35/35 (100%) | None |
| Volumetric | v0.8.0 | 20/20 (100%) | None |
| Secure Content | v1.0.2 | 49/50 (98%) | crypto |
| Boolean Operations | v1.1.1 | 16/16 (100%) | None |
| Displacement | v1.0.0 | 31/31 (100%) | None |
Total: 336/345 features (97.4%)
Extension Details
Materials and Properties Extension (v1.2.1)
Purpose: Add color, texture, and advanced material properties to geometry.
Features:
- Base Materials — Solid colors (RGB/RGBA) with display names
- Color Groups — Per-vertex color gradients via color property groups
- Texture 2D — UV-mapped images with tile styles and filtering
- Composite Materials — Blend multiple materials with mixing ratios
- Multi-Properties — Combine multiple property types on single geometry
Code example:
use lib3mf_core::Model;
let model = Model::from_file("textured.3mf")?;
// Access textures
for (id, texture) in model.resources.iter_textures() {
println!("Texture {}: {} ({}x{})",
id.0,
texture.path,
texture.width,
texture.height
);
}
// Access base materials
for (id, material_group) in model.resources.iter_base_materials() {
for (idx, material) in material_group.materials.iter().enumerate() {
println!("Material {}/{}: {} - #{:06X}",
id.0,
idx,
material.name,
material.color & 0xFFFFFF // RGB only
);
}
}
Use cases:
- Full-color 3D printing
- Texture mapping from CAD
- Multi-material printing
- Visual fidelity in manufacturing
Specification: Materials Extension v1.2.1
Production Extension (v1.1.2)
Purpose: Track manufacturing metadata like UUIDs, part numbers, and production paths.
Features:
- UUIDs — Unique identifiers for each build item
- Part Numbers — Manufacturing part numbers
- Production Path — Hierarchical organization of parts
Code example:
for item in &model.build.items {
if let Some(uuid) = &item.uuid {
println!("Build item {} has UUID: {}", item.object_id.0, uuid);
}
if let Some(part_number) = &item.part_number {
println!(" Part number: {}", part_number);
}
}
Use cases:
- Manufacturing tracking
- Inventory management
- Production workflow integration
- Quality assurance
Specification: Production Extension v1.1.2
Beam Lattice Extension (v1.2.0)
Purpose: Define structural lattice geometries as cylindrical beams connecting vertices.
Features:
- Beam Sets — Collections of beams with shared radius
- Cap Modes — Sphere, hemisphere, or butt caps at beam endpoints
- Clipping Modes — How beams interact at intersections
- Precision Radii — Specify exact beam thickness
Code example:
use lib3mf_core::model::Geometry;
for (id, obj) in model.resources.iter_objects() {
if let Geometry::BeamLattice(lattice) = &obj.geometry {
println!("Object {} is a beam lattice:", id.0);
println!(" Min length: {}", lattice.min_length);
println!(" Beam sets: {}", lattice.beam_sets.len());
for beam_set in &lattice.beam_sets {
println!(" Beams: {}, Radius: {}",
beam_set.beams.len(),
beam_set.radius
);
}
}
}
Use cases:
- Structural optimization
- Lightweight mechanical parts
- Heat exchangers
- Medical implants (porous structures)
Specification: Beam Lattice Extension v1.2.0
Slice Extension (v1.0.2)
Purpose: Pre-sliced 2D layer data for DLP/SLA resin printers.
Features:
- Slice Stacks — Ordered layers with Z-heights
- 2D Polygons — Per-layer geometry as closed polygons
- Multi-Material Slices — Different materials per layer
- External Slice Refs — Reference external slice files
Code example:
use lib3mf_core::model::Geometry;
for (id, obj) in model.resources.iter_objects() {
if let Some(slice_stack_id) = obj.slice_stack_id {
println!("Object {} references slice stack {}", id.0, slice_stack_id.0);
if let Some(stack) = model.resources.get_slice_stack(slice_stack_id) {
println!(" Layers: {}", stack.slices.len());
}
}
}
Use cases:
- SLA/DLP resin printing
- Pre-processed slicing workflows
- Layer-based manufacturing
- Optimized print files
Specification: Slice Extension v1.0.2
Volumetric Extension (v0.8.0)
Purpose: Voxel-based geometry representation for volume data.
Features:
- Volumetric Stacks — 3D voxel grids
- Field-Based Volumes — Continuous field representations
- Image Stacks — Layer-by-layer image data
Code example:
for (id, stack) in model.resources.iter_volumetric_stacks() {
println!("Volumetric stack {}: {} layers", id.0, stack.layers.len());
}
Use cases:
- Medical imaging (CT/MRI to 3D print)
- Scientific visualization
- Voxel-based manufacturing
- Material density variation
Specification: Volumetric Extension v0.8.0
Secure Content Extension (v1.0.2)
Purpose: Digital signatures and content encryption for secure manufacturing.
Features:
- XML-DSIG — Digital signatures for authenticity verification
- XML-ENC — AES-GCM content encryption
- X.509 Certificates — Certificate chain validation
- RSA Public Key — Asymmetric cryptography
Requires: crypto feature flag
Code example:
#[cfg(feature = "crypto")]
use lib3mf_core::crypto::verify_signature;
#[cfg(feature = "crypto")]
fn check_signature(model: &Model) -> Result<bool> {
if let Some(signature) = &model.signature {
verify_signature(signature)
} else {
Ok(false) // No signature present
}
}
Use cases:
- Intellectual property protection
- Manufacturing authenticity
- Regulatory compliance
- Trusted supply chains
Specification: Secure Content Extension v1.0.2
Boolean Operations Extension (v1.1.1)
Purpose: Constructive solid geometry operations (union, difference, intersection).
Features:
- Union — Combine meshes
- Difference — Subtract mesh from another
- Intersection — Keep only overlapping volume
- Transform Matrices — Position operands
- Nested Operations — Boolean trees
Code example:
use lib3mf_core::model::Geometry;
for (id, obj) in model.resources.iter_objects() {
if let Geometry::BooleanShape(boolean) = &obj.geometry {
println!("Boolean operation: {:?}", boolean.operation);
println!(" Operands: {}", boolean.operands.len());
}
}
Use cases:
- CAD modeling workflows
- Complex geometry construction
- Parametric design
- Procedural generation
Note: lib3mf-rs parses and writes boolean operations but does not evaluate them (geometry processing is left to slicers/CAD software).
Specification: Boolean Operations Extension v1.1.1
Displacement Extension (v1.0.0)
Purpose: Texture-driven surface modification for detailed surface features.
Features:
- Displacement Maps — Grayscale textures define surface offset
- Normal Maps — RGB textures for surface normal perturbation
- Texture Coordinates — UV mapping per vertex
- Scale Factors — Control displacement intensity
Code example:
use lib3mf_core::model::Geometry;
for (id, obj) in model.resources.iter_objects() {
if let Geometry::DisplacementMesh(displacement) = &obj.geometry {
println!("Displacement mesh {}:", id.0);
println!(" Texture: {}", displacement.texture_id.0);
println!(" Scale: {}", displacement.scale);
}
}
Use cases:
- High-detail surface textures
- Realistic skin/terrain
- Efficient detail representation
- Artistic surface effects
Note: lib3mf-rs parses displacement data but does not evaluate/tessellate it (surface subdivision is left to renderers).
Specification: Displacement Extension v1.0.0
Detecting Extensions in Files
You can check which extensions a file uses:
use lib3mf_core::Model;
let model = Model::from_file("model.3mf")?;
let stats = model.compute_stats()?;
println!("Extensions used:");
for extension in &stats.extensions {
println!(" - {}", extension);
}
Extensions are detected automatically during parsing based on XML namespaces.
Vendor Extensions
Beyond official 3MF Consortium extensions, lib3mf-rs supports some vendor-specific extensions:
Bambu Studio Project Files:
- Multi-plate layouts
- Filament metadata
- Print time estimates
- Machine settings
These are parsed but not officially documented by the 3MF Consortium.
Next Steps
- Architecture — How extensions are integrated into lib3mf-rs
- API Reference — Detailed extension data structures
- Examples — Code examples for each extension
Contributing
Thank you for your interest in contributing to lib3mf-rs! This guide covers development setup, testing strategies, code conventions, and how to add new features.
Development Setup
Prerequisites
- Rust toolchain (stable, v1.70 or later)
- Git
Clone and Build
git clone https://github.com/sscargal/lib3mf-rs.git
cd lib3mf-rs
# Debug build (fast compilation)
cargo build
# Run tests
cargo test
# Run linter
cargo clippy -- -D warnings
# Format code
cargo fmt
Project Structure
lib3mf-rs/
├── crates/
│ ├── lib3mf-core/ # Main library
│ ├── lib3mf-cli/ # CLI tool
│ ├── lib3mf-converters/ # Format converters
│ ├── lib3mf-async/ # Async I/O
│ └── lib3mf-wasm/ # WebAssembly bindings
├── fuzz/ # Fuzzing targets
├── book/ # This documentation
├── scripts/ # QA and utility scripts
└── .github/workflows/ # CI/CD pipelines
Build Commands
Standard Builds
# Debug build (fast compilation, slower execution)
cargo build
# Release build (optimized for performance)
cargo build --release
# Build specific crate
cargo build -p lib3mf-core
cargo build -p lib3mf-cli
Feature-Specific Builds
# Minimal build (no optional dependencies)
cargo build -p lib3mf-core --no-default-features
# With crypto support
cargo build -p lib3mf-core --features crypto
# With parallel processing
cargo build -p lib3mf-core --features parallel
# All features
cargo build -p lib3mf-core --all-features
Check Dependency Count
# Verify minimal build dependency count
cargo tree -p lib3mf-core --no-default-features | wc -l
# Expected: ~154 crates
# Full-featured build
cargo tree -p lib3mf-core --all-features | wc -l
# Expected: ~300 crates
Testing
Running Tests
# Run all tests
cargo test
# Run tests for specific crate
cargo test -p lib3mf-core
# Run tests with specific features
cargo test -p lib3mf-core --no-default-features
cargo test -p lib3mf-core --features crypto
cargo test -p lib3mf-core --all-features
# Run property-based tests
cargo test -p lib3mf-core --test proptests
Test Organization
Unit tests — Located in same file as code, in #[cfg(test)] mod tests blocks:
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_vertex() {
// Test implementation
}
}
Integration tests — Located in tests/ directories:
crates/lib3mf-core/tests/
├── parse_tests.rs # Full file parsing
├── roundtrip_tests.rs # Parse → Write → Parse
├── validation_tests.rs # Validation system
└── extension_tests.rs # Extension-specific tests
Property-based tests — Using proptest for robustness:
use proptest::prelude::*;
proptest! {
#[test]
fn test_vertex_roundtrip(x in -1000.0f32..1000.0, y in -1000.0..1000.0, z in -1000.0..1000.0) {
let vertex = Vertex::new(x, y, z);
let xml = write_vertex(&vertex);
let parsed = parse_vertex(&xml)?;
assert_eq!(vertex, parsed);
}
}
Fuzzing
Fuzzing tests for security and robustness using cargo-fuzz:
Setup:
# Install nightly toolchain (required for fuzzing)
rustup toolchain install nightly
# Install cargo-fuzz
cargo +nightly install cargo-fuzz
Running fuzz targets:
# List available targets
cargo +nightly fuzz list
# Run a specific target (indefinitely until Ctrl+C)
cargo +nightly fuzz run parse_model
# Run with time limit (60 second smoke test)
cargo +nightly fuzz run parse_model -- -max_total_time=60
# Run with dictionary for better coverage
cargo +nightly fuzz run parse_xml -- -dict=fuzz/dictionaries/3mf.dict
Available fuzz targets:
parse_model— Full 3MF file parsing (ZIP + XML + invariants)parse_xml— Direct XML model parsing (bypasses ZIP)parse_materials— Material/texture parsing isolationparse_crypto— Signature/encryption parsingparse_extensions— Extension-specific parsersparse_opc— OPC relationship parsingwriter_roundtrip— Fuzz writer by round-tripping models
Crash handling:
If fuzzing finds a crash:
# Minimize crash file (reduce to smallest reproducer)
cargo +nightly fuzz tmin parse_model fuzz/artifacts/parse_model/crash-abc123
# Add to regression tests
cp fuzz/artifacts/parse_model/crash-abc123 crates/lib3mf-core/tests/fuzz_regression/parse_model_001.bin
# Create test case
#[test]
fn test_fuzz_regression_001() {
let data = include_bytes!("fuzz_regression/parse_model_001.bin");
// Verify it doesn't crash or produces expected error
let result = parse_model(Cursor::new(data));
assert!(result.is_err()); // Should error gracefully, not panic
}
QA Test Suite
Run comprehensive validation before submitting PRs:
./scripts/qa_test_suite.sh
This script runs:
- Format check (
cargo fmt --check) - Linter (
cargo clippy) - All tests with all feature combinations
- Benchmarks
- Example runs
- CLI validation
Expected runtime: ~5 minutes
Code Quality Standards
Formatting
Use rustfmt with default settings:
cargo fmt
Before committing:
cargo fmt --check
Linting
Use clippy with warnings as errors:
cargo clippy -- -D warnings
Common clippy warnings to avoid:
- Unnecessary clones
- Inefficient string operations
- Missing error propagation
- Unsafe code without justification
Documentation
Public items must have doc comments:
/// Parses a 3MF model from an XML reader.
///
/// # Arguments
///
/// * `reader` - The XML data source
///
/// # Returns
///
/// A `Model` instance on success, or `Lib3mfError` on parse failure.
///
/// # Examples
///
/// ```
/// use lib3mf_core::parser::parse_model;
/// use std::io::Cursor;
///
/// let xml = r#"<model>...</model>"#;
/// let model = parse_model(Cursor::new(xml))?;
/// # Ok::<(), lib3mf_core::error::Lib3mfError>(())
/// ```
pub fn parse_model<R: Read>(reader: R) -> Result<Model> {
// Implementation
}
Module-level documentation:
//! Mesh repair utilities for fixing geometry issues.
//!
//! This module provides the `MeshRepair` trait and implementations
//! for common repair operations like vertex stitching and orientation
//! harmonization.
Code Conventions
Immutable Design
Prefer immutable data structures:
// Good: Return new instance
pub fn stitch_vertices(&self, epsilon: f32) -> Result<Mesh> {
let mut new_mesh = self.clone();
// Perform stitching on new_mesh
Ok(new_mesh)
}
// Avoid: Mutate in place (unless explicitly required)
pub fn stitch_vertices_mut(&mut self, epsilon: f32) {
// Avoid this pattern
}
Rationale: Thread safety, predictable behavior, easier testing.
Error Handling
Use Result<T> for fallible operations:
use crate::error::{Lib3mfError, Result};
pub fn parse_vertex(xml: &str) -> Result<Vertex> {
let x = xml.parse::<f32>()
.map_err(|e| Lib3mfError::ParseError(format!("Invalid X coordinate: {}", e)))?;
// ...
Ok(Vertex { x, y, z })
}
Never panic in library code:
// Bad
pub fn get_object(&self, id: ResourceId) -> Object {
self.objects.get(&id).unwrap() // DON'T DO THIS
}
// Good
pub fn get_object(&self, id: ResourceId) -> Option<&Object> {
self.objects.get(&id)
}
// Or
pub fn get_object(&self, id: ResourceId) -> Result<&Object> {
self.objects.get(&id)
.ok_or_else(|| Lib3mfError::ResourceNotFound(id))
}
Trait Abstractions
Use traits for extensibility:
pub trait ArchiveReader {
fn read_entry(&mut self, path: &str) -> Result<Vec<u8>>;
fn entry_names(&mut self) -> Result<Vec<String>>;
}
impl ArchiveReader for ZipArchiver {
// Implementation
}
Resource Management
Use newtype pattern for type-safe IDs:
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ResourceId(pub u32);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct TextureId(pub u32);
// Prevents mixing different ID types
Adding New Features
Adding a New Extension
Extensions require integration across multiple layers:
- Define data structures (
model/module):
// In model/geometry.rs or new file
pub struct MyExtensionData {
pub property_a: String,
pub property_b: f32,
}
// Add to Geometry enum if geometry-related
pub enum Geometry {
Mesh(Mesh),
BeamLattice(BeamLattice),
MyExtension(MyExtensionData), // Add here
}
- Create parser (
parser/my_extension_parser.rs):
use quick_xml::Reader;
use crate::model::MyExtensionData;
pub fn parse_my_extension<R: BufRead>(reader: &mut Reader<R>) -> Result<MyExtensionData> {
// XML parsing logic
}
- Integrate into main parser (
parser/model_parser.rs):
match event {
// Existing cases...
Start(ref e) if e.local_name().as_ref() == b"myextension" => {
let ext_data = parse_my_extension(reader)?;
// Add to model
}
}
- Add writer (
writer/my_extension_writer.rs):
pub fn write_my_extension<W: Write>(writer: &mut Writer<W>, data: &MyExtensionData) -> Result<()> {
// XML writing logic
}
- Add validation (
validation/validator.rs):
fn validate_my_extension(&self, data: &MyExtensionData, report: &mut ValidationReport) {
if data.property_b < 0.0 {
report.add_error(5100, "Property B must be non-negative");
}
}
- Write tests (
tests/my_extension_tests.rs):
#[test]
fn test_my_extension_roundtrip() {
let xml = r#"<myextension property_a="test" property_b="1.5" />"#;
let parsed = parse_my_extension(xml)?;
assert_eq!(parsed.property_a, "test");
assert_eq!(parsed.property_b, 1.5);
}
- Add example (
examples/my_extension_demo.rs):
//! Demonstrates using MyExtension feature
use lib3mf_core::Model;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let model = Model::from_file("example.3mf")?;
// Show extension usage
Ok(())
}
- Update documentation:
- Add to
book/src/extensions.md - Update rustdoc comments
- Update README.md feature list
- Add to
Adding a New Resource Type
Similar process but focuses on ResourceCollection:
- Define struct in
model/resources.rs - Add to
ResourceCollectionwithadd_*/get_*methods - Implement parser and writer
- Add validation rules
- Write tests and examples
Feature Flag Testing
Test all feature combinations in CI:
# Test minimal build
cargo test -p lib3mf-core --no-default-features
# Test crypto only
cargo test -p lib3mf-core --no-default-features --features crypto
# Test parallel only
cargo test -p lib3mf-core --no-default-features --features parallel
# Test all features
cargo test -p lib3mf-core --all-features
CI matrix (.github/workflows/ci.yml):
strategy:
matrix:
features:
- "--no-default-features"
- "--features crypto"
- "--features parallel"
- "--all-features"
Pull Request Process
- Fork and clone the repository
- Create a feature branch (
git checkout -b feature/my-feature) - Make changes following code conventions
- Write tests (unit + integration)
- Run QA suite (
./scripts/qa_test_suite.sh) - Commit with clear messages:
feat: add MyExtension support - Parse myextension elements - Add MyExtensionData to Geometry enum - Write tests and example - Update documentation - Push and create PR
- Address review feedback
Finding Work
Check GitHub Issues for:
- Good First Issue — Beginner-friendly tasks
- Help Wanted — Community contributions welcome
- Bug — Reported bugs needing fixes
- Enhancement — Feature requests
Or propose your own improvements!
Questions?
- GitHub Issues — For bugs and feature requests
- GitHub Discussions — For questions and ideas
- Email — steve@scargall.com
License
By contributing, you agree that your contributions will be licensed under the MIT License.
Rust API Documentation
This section provides links to the auto-generated API documentation for all workspace crates. The API docs are generated from inline documentation in the source code using rustdoc and provide detailed information about every public function, struct, enum, and module.
Core Library
lib3mf-core
Core library implementation including parser, model structures, validation, writer, and cryptographic support. This is the main crate that provides all fundamental 3MF functionality.
Key modules:
parser- XML parsing and model constructionmodel- Core data structures (Model, Mesh, Build, etc.)validation- Progressive validation system (Minimal/Standard/Strict/Paranoid)writer- Model serialization back to 3MF formatarchive- ZIP/OPC container handlingcrypto- Secure Content Extension (digital signatures, encryption)
Command-Line Tools
lib3mf-cli
Command-line interface tool providing the 3mf binary for file inspection, validation, conversion, and manipulation from the terminal. Also exposes command functions as a library module for programmatic use.
Commands: stats, list, validate, copy, diff, extract, rels, dump, repair, benchmark, convert, sign, verify, encrypt, decrypt, thumbnails
Key types:
ExecuteStats- Generate statistics reports (mesh counts, triangles, volumes)ExecuteList- List archive contents with tree or flat formatExecuteValidate- Validate files at Minimal/Standard/Strict/Paranoid levelsExecuteCopy- Copy and optionally repair 3MF filesExecuteDiff- Compare two 3MF files for differences
Feature flags:
crypto- Enables sign, verify, encrypt, decrypt commandsparallel- Enables multi-threaded processing in repair and stats
Format Conversion
lib3mf-converters
Format converters for interoperability with other 3D file formats. Supports importing/exporting binary STL and basic OBJ files to/from 3MF.
Key types:
StlImporter- Read binary STL files into 3MF modelsStlExporter- Write 3MF models to binary STL formatObjImporter- Read OBJ files (vertices and faces) into 3MFObjExporter- Write 3MF models to OBJ format
Features:
- Binary STL support (ASCII STL not supported)
- Multi-part STL export with
write_with_resolverfor filename mapping - Basic OBJ import (no materials, textures, or normals)
- Automatic unit conversion and coordinate system handling
Limitations:
- STL: Binary format only, no color/material support
- OBJ: No material (.mtl) files, normals, or texture coordinates
Async I/O
lib3mf-async
Async I/O support using tokio and async-zip for non-blocking file operations. Ideal for web servers, concurrent applications, and scenarios where blocking I/O would be problematic.
Key types:
AsyncArchiveReader- Trait for async archive reading (implemented byAsyncZipArchive)AsyncZipArchive- Async ZIP archive reader usingasync_zipload_model_async- High-level async function to load 3MF files
Architecture:
- Uses
tokioruntime for async I/O operations - ZIP archive reading is fully async (non-blocking)
- XML parsing uses
spawn_blocking(CPU-bound work on thread pool) - All archive readers must be
Send + Syncfor multi-threaded async
When to use:
- Web servers handling concurrent requests
- Applications processing multiple files in parallel
- Scenarios where UI responsiveness matters
- When you already have a tokio runtime
When NOT to use:
- Single-threaded CLI tools (use synchronous
lib3mf-coreinstead) - When simplicity is more important than concurrency
WebAssembly
lib3mf-wasm
WebAssembly bindings enabling lib3mf-rs to run in browsers and JavaScript environments. Provides a JavaScript-friendly API for parsing and analyzing 3MF files in the browser.
Key types:
WasmModel- JavaScript-accessible model representationset_panic_hook- Improved panic messages in browser console
Features:
- Parse 3MF files from
Uint8Arrayin JavaScript - Access basic model information (units, objects, build items)
- Browser-compatible API using
wasm-bindgen
Building:
wasm-pack build crates/lib3mf-wasm --target web
Current status:
- Early-stage bindings with limited API surface
- Basic parsing and model inspection supported
- Advanced features (validation, writing, crypto) not yet exposed
- Future expansion planned based on community needs
Viewing API Docs Locally
If you’re viewing this locally (not on GitHub Pages), you can generate and open the API documentation by running:
cargo doc --workspace --all-features --no-deps --open
This will build the documentation for all crates and open it in your default browser.