Aim

This document is just my notes from our meetup discussion/exploration of 3mf files.

Standards

The 3mf core specification is available at https://3mf.io/spec/

Here are some important excerpts.

Package

Section 1.1: 3mf files are zip files. This means that if you change the filename from dot 3mf to dot zip and then you can unzip them using your normal zip tools.

Parts and Relationships

Section 2 of the specification describes the parts inside the package. 3mf files follow Open Packaging Conventions

https://en.wikipedia.org/wiki/Open_Packaging_Conventions

A 3mf file contains a PAYLOAD. A payload is a complete set of interdependent parts in a package. If the root part of the payload is a 3d model then it is a 3d payload. There can be more than one 3d payload in a 3mf file but only one 3d payload can be the primary 3d payload. The primary 3d payload is defined in the 3MF Document StartPart. Here’s a list of 3MF parts. Note that this is not a complete list because the 3MF format is extensible to include custom parts.

Name

Description

Relationship Source

Required/Optional

3D Model

Contains the description of one or more 3D objects for manufacturing.

Package

REQUIRED

Core Properties

The OPC part that contains various document properties.

Package

OPTIONAL

Digital Signature Origin

The OPC part that is the root of digital signatures in the package.

Package

OPTIONAL

Digital Signature

OPC parts that each contains a digital signature.

Digital Signature Origin

OPTIONAL

Digital Signature Certificate

OPC parts that contain a digital signature certificate.

Digital Signature

OPTIONAL

PrintTicket

Provides settings to be used when outputting the 3D object(s) in the 3D Model part.

3D Model

OPTIONAL

Package Thumbnail

Contains a small JPEG or PNG image that represents the 3D objects in the package or the package as a whole.

Package

OPTIONAL

Object Thumbnail

Contains a small JPEG or PNG image that represents a 3D object in a 3D Model.

3D Model

OPTIONAL

3D Texture

Contains a texture used to apply color to a 3D object in the 3D Model part (available for extensions)

3D Model

OPTIONAL

Custom Parts

OPC parts that are associated with metadata

Package

OPTIONAL

Example Simple 3mf Package

Ok enough theory. Suppose I create a cube in freecad with one corner at (0,0,0) and the opposite corner at (10,10,10) and export the cube as a 3mf file. This is what I see when I unzip the file:

├── 3D
│   └── 3dmodel.model
├── [Content_Types].xml
├── Metadata
│   └── thumbnail.png
└── _rels

In the root folder there’s an xml file named [Content_Types].xml and three subfolders: 3D, Metadata and _rels. Here’s the contents of the xml file and the thumbnail.png file

<?xml version='1.0' encoding='UTF-8'?>
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
 <Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
 <Default Extension="model" ContentType="application/vnd.ms-package.3dmanufacturing-3dmodel+xml"/>
 <Default Extension="png" ContentType="image/png"/>
</Types>


And this is the 3dmodel.model file:

<?xml version="1.0" encoding="UTF-8"?>
<model unit="millimeter" xml:lang="en-US" xmlns="http://schemas.microsoft.com/3dmanufacturing/core/2015/02">
 <metadata name="Application">FreeCAD</metadata>
 <resources>
  <object id="1" type="model">
   <mesh>
    <vertices>
     <vertex x="0" y="0" z="0" />
     <vertex x="0" y="0" z="10" />
     <vertex x="0" y="10" z="0" />
     <vertex x="0" y="10" z="10" />
     <vertex x="10" y="0" z="10" />
     <vertex x="10" y="0" z="0" />
     <vertex x="10" y="10" z="0" />
     <vertex x="10" y="10" z="10" />
    </vertices>
    <triangles>
     <triangle v1="0" v2="1" v3="2" />
     <triangle v1="2" v2="1" v3="3" />
     <triangle v1="4" v2="5" v3="6" />
     <triangle v1="4" v2="6" v3="7" />
     <triangle v1="5" v2="4" v3="0" />
     <triangle v1="0" v2="4" v3="1" />
     <triangle v1="7" v2="6" v3="2" />
     <triangle v1="7" v2="2" v3="3" />
     <triangle v1="2" v2="6" v3="0" />
     <triangle v1="0" v2="6" v3="5" />
     <triangle v1="7" v2="3" v3="1" />
     <triangle v1="7" v2="1" v3="4" />
    </triangles>
   </mesh>
  </object>
 </resources>
 <build>
  <item objectid="1" transform="1 0 0 0 1 0 0 0 1 0 0 0" />
 </build>
</model>

This looks familiar: it’s a triangular mesh similar to STL but slightly upgraded. That is to say, the vertices are specified first using a list then the triangles references the list of vertices. Which is great because this technique reduces the risk of non-aligned edges due to round off errors. There’s some metadata to tell us what application created the model, the units, and a transformation matrix at the end if we want to scale or rotate the object.

Example Bambu Sliced 3mf

As an example of a more complex object we could look at an export of a Bambu Studio sliced file.

Suppose I open my freecad cube.3mf file in Bambu Studio. Slice it. But instead of printing it, use the drop down, select Export All and export it as cube.gcode.3mf. By default Bambu Studio exports its gcode as 3mf files (you can select bare gcode export in File→Export menu). Here’s what I get when I unzip the cube.gcode.3mf file:

├── 3D
│   └── 3dmodel.model
├── [Content_Types].xml
├── Metadata
│   ├── cut_information.xml
│   ├── model_settings.config
│   ├── pick_1.png
│   ├── plate_1.gcode
│   ├── plate_1.gcode.md5
│   ├── plate_1.json
│   ├── plate_1.png
│   ├── plate_1_small.png
│   ├── plate_no_light_1.png
│   ├── project_settings.config
│   ├── _rels
│   │   └── model_settings.config.rels
│   ├── slice_info.config
│   └── top_1.png
└── _rels

and this is [Content_Types].xml

<?xml version="1.0" encoding="UTF-8"?>
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
 <Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
 <Default Extension="model" ContentType="application/vnd.ms-package.3dmanufacturing-3dmodel+xml"/>
 <Default Extension="png" ContentType="image/png"/>
 <Default Extension="gcode" ContentType="text/x.gcode"/>
</Types>

and here’s the 3dmodel.model file

<?xml version="1.0" encoding="UTF-8"?>
<model unit="millimeter" xml:lang="en-US" xmlns="http://schemas.microsoft.com/3dmanufacturing/core/2015/02" xmlns:BambuStudio="http://schemas.bambulab.com/package/2021" xmlns:p="http://schemas.microsoft.com/3dmanufacturing/production/2015/06" requiredextensions="p">
 <metadata name="Application">BambuStudio-02.00.01.50</metadata>
 <metadata name="BambuStudio:3mfVersion">1</metadata>
 <metadata name="Copyright"></metadata>
 <metadata name="CreationDate">2025-06-12</metadata>
 <metadata name="Description"></metadata>
 <metadata name="Designer"></metadata>
 <metadata name="DesignerCover"></metadata>
 <metadata name="DesignerUserId">2876920761</metadata>
 <metadata name="License"></metadata>
 <metadata name="ModificationDate">2025-06-12</metadata>
 <metadata name="Origin"></metadata>
 <metadata name="Title"></metadata>
 <resources>
 </resources>
 <build/>
</model>

Interestingly, it’s all just metadata. There’s no object. And if we try to open this cube.gcode.3mf file in Bambu Studio it will show a sliced model in the Preview tab but it will complain when we try to switch to the Prepare tab because there is no object. Does it still count as a 3d payload even if there is no 3d object in the model? Maybe Bambu is being sneaky with the standard.

We have lots of files in the Metadata folder, including files describing the model and printer settings (in xml and json respectively). And of course the actual gcode that we are looking for is in the Metadata folder.