Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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:

Reference — Deep technical documentation:

API Reference — For complete API documentation:

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(())
}

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 scratch
  • advanced_materials.rs — Textures and composite materials
  • geometry_validation.rs — Using paranoid validation to find issues
  • geometry_repair.rs — Programmatic mesh repair
  • secure_content.rs — Digital signatures and encryption
  • beam_lattice_ext.rs — Creating structural lattice designs
  • boolean_operations.rs — Union, difference, intersection operations
  • displacement_mesh.rs — Texture-driven surface modification
  • slice_data.rs — Pre-sliced geometry for resin printers
  • streaming_stats.rs — Processing large files with constant memory

Next Steps

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

CommandPurpose
statsDisplay file statistics (objects, triangles, materials)
listList archive contents
validateRun validation checks
copyCopy/rewrite a 3MF file (roundtrip test)
diffCompare two 3MF files
extractExtract 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 — Success
  • 1 — Validation failed or file error
  • 2 — 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

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:

FeatureWhat It EnablesDependencies AddedWhen to Use
cryptoDigital signatures and encryption (Secure Content Extension)aes-gcm, rsa, sha1, sha2, x509-parser, rand, base64 (~146 crates)Signed/encrypted 3MF files
parallelMulti-threaded mesh processing using Rayonrayon (~6 crates)Large files, multi-core CPUs
png-validationPNG texture validationpng (~15 crates)Texture quality checks
fullAll features enabledAll of the aboveComplete 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
[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:

ConfigurationCompile Time (clean)Binary Size (release)Notes
Minimal~30s~2.5 MBFastest builds
Crypto only~90s~4.2 MBCrypto adds significant compile time
Parallel only~35s~2.8 MBRayon is lightweight
Full~90s~4.5 MBCrypto 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::SecureContent
  • crypto::verify_signature()
  • crypto::decrypt_content()
  • model::KeyStore

Parallel-gated behavior:

  • Model::compute_stats() uses parallel iteration when parallel enabled
  • Mesh::compute_aabb() parallelizes across triangles
  • validation::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

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:

  1. Minimal — Basic structural checks (fastest)
  2. Standard — Reference integrity and common issues (recommended)
  3. Strict — Full specification compliance
  4. 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)?;

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 RangeCategory
1000-1999XML/Structure errors
2000-2999Resource errors
3000-3999Build errors
4000-4999Geometry errors
5000-5999Extension errors

Example error codes:

  • 2001 — Resource ID not found
  • 2042 — Triangle vertex index out of bounds
  • 3010 — Build item references invalid object type
  • 4015 — Non-manifold edge detected
  • 4020 — 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:

  1. Start with Minimal to fail fast
  2. Use Standard for most checks
  3. 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

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

  1. Archive LayerZipArchiver::new() opens the 3MF file (ZIP container)
  2. OPC Layer — Read _rels/.rels to discover main model XML path via find_model_path()
  3. Parser Layerparse_model() converts XML into in-memory Model structure
  4. Model LayerModel contains resources (objects, materials, textures) and build instructions
  5. Validation Layer — Apply checks at chosen level (Minimal/Standard/Strict/Paranoid)

Typical Write Workflow

  1. Model Layer — Create or modify Model structure programmatically
  2. Writer Layerwrite_package() serializes model to XML and ZIP
  3. Archive Layer — Write OPC relationships and package structure
  4. Output — Produces a valid 3MF file

Module Structure in lib3mf-core

archive/ — OPC Container Handling

Key files:

  • zip_archive.rs — ZIP wrapper implementing ArchiveReader trait
  • opc.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> element
  • mesh_parser.rs — Geometry parsing (vertices, triangles)
  • material_parser.rs — Materials (colors, textures, composites)
  • beamlattice_parser.rs — Beam Lattice Extension parser
  • slice_parser.rs — Slice Extension parser
  • secure_content_parser.rs — Secure Content Extension parser
  • streaming.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 — Root Model struct
  • resources.rsResourceCollection (central resource registry)
  • mesh.rs — Geometry types (Mesh, Triangle, Vertex, BeamLattice)
  • materials.rs — Material types (BaseMaterial, ColorGroup, Texture2D, Composite, MultiProperties)
  • build.rsBuild and BuildItem (what to print and where)
  • secure_content.rs — Encryption/signature metadata
  • repair.rsMeshRepair trait 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 orchestration
  • geometry.rs — Geometry checks (manifoldness, self-intersection, orientation)
  • bvh.rs — Bounding Volume Hierarchy for O(n log n) intersection tests
  • report.rs — Structured validation results

Four validation levels:

  1. Minimal — Basic structural checks (well-formed XML, valid IDs)
  2. Standard — Reference integrity (all referenced resources exist)
  3. Strict — Full spec compliance (ranges, formats, constraints)
  4. Paranoid — Deep geometry analysis (manifoldness, self-intersection, orientation)

writer/ — Model to File Serialization

Key files:

  • model_writer.rs — Main model serialization
  • mesh_writer.rs — Geometry serialization
  • package_writer.rs — Top-level package orchestration
  • opc_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 verification
  • encryption.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:

  1. Per-vertex propertiesTriangle with p1, p2, p3 attributes
  2. Per-triangle propertiesTriangle with pid attribute
  3. Per-object defaultObject with pid and pindex

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

ApproachSpeedMemoryBest For
DOM mode (parse_model)FastO(n)Files <100MB
SAX mode (streaming)SlowerO(1)Files >1GB
Parallel (Rayon)FastestO(n)Large meshes with multi-core CPU

Feature Flags and Dependencies

ConfigurationDependency CountUse Case
Minimal (default = [])~154 cratesEmbedded systems, WASM, size-critical
Crypto only~300 cratesSecure files, signature verification
Parallel only~160 cratesFast mesh processing, no security
Full (features = ["full"])~300 cratesComplete 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

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

ExtensionVersionFeature CoverageRequired lib3mf Feature
Core Specificationv1.4.098/100 (98%)None (always available)
Materials and Propertiesv1.2.138/38 (100%)None
Productionv1.1.220/20 (100%)None
Beam Latticev1.2.029/29 (100%)None
Slicev1.0.235/35 (100%)None
Volumetricv0.8.020/20 (100%)None
Secure Contentv1.0.249/50 (98%)crypto
Boolean Operationsv1.1.116/16 (100%)None
Displacementv1.0.031/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

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 isolation
  • parse_crypto — Signature/encryption parsing
  • parse_extensions — Extension-specific parsers
  • parse_opc — OPC relationship parsing
  • writer_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:

  1. Format check (cargo fmt --check)
  2. Linter (cargo clippy)
  3. All tests with all feature combinations
  4. Benchmarks
  5. Example runs
  6. 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:

  1. 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
}
  1. 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
}
  1. 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
    }
}
  1. Add writer (writer/my_extension_writer.rs):
pub fn write_my_extension<W: Write>(writer: &mut Writer<W>, data: &MyExtensionData) -> Result<()> {
    // XML writing logic
}
  1. 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");
    }
}
  1. 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);
}
  1. 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(())
}
  1. Update documentation:
    • Add to book/src/extensions.md
    • Update rustdoc comments
    • Update README.md feature list

Adding a New Resource Type

Similar process but focuses on ResourceCollection:

  1. Define struct in model/resources.rs
  2. Add to ResourceCollection with add_*/get_* methods
  3. Implement parser and writer
  4. Add validation rules
  5. 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

  1. Fork and clone the repository
  2. Create a feature branch (git checkout -b feature/my-feature)
  3. Make changes following code conventions
  4. Write tests (unit + integration)
  5. Run QA suite (./scripts/qa_test_suite.sh)
  6. Commit with clear messages:
    feat: add MyExtension support
    
    - Parse myextension elements
    - Add MyExtensionData to Geometry enum
    - Write tests and example
    - Update documentation
    
  7. Push and create PR
  8. 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 construction
  • model - Core data structures (Model, Mesh, Build, etc.)
  • validation - Progressive validation system (Minimal/Standard/Strict/Paranoid)
  • writer - Model serialization back to 3MF format
  • archive - ZIP/OPC container handling
  • crypto - 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 format
  • ExecuteValidate - Validate files at Minimal/Standard/Strict/Paranoid levels
  • ExecuteCopy - Copy and optionally repair 3MF files
  • ExecuteDiff - Compare two 3MF files for differences

Feature flags:

  • crypto - Enables sign, verify, encrypt, decrypt commands
  • parallel - 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 models
  • StlExporter - Write 3MF models to binary STL format
  • ObjImporter - Read OBJ files (vertices and faces) into 3MF
  • ObjExporter - Write 3MF models to OBJ format

Features:

  • Binary STL support (ASCII STL not supported)
  • Multi-part STL export with write_with_resolver for 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 by AsyncZipArchive)
  • AsyncZipArchive - Async ZIP archive reader using async_zip
  • load_model_async - High-level async function to load 3MF files

Architecture:

  • Uses tokio runtime 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 + Sync for 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-core instead)
  • 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 representation
  • set_panic_hook - Improved panic messages in browser console

Features:

  • Parse 3MF files from Uint8Array in 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.