MaterialX Needs a Single-File Container

Back to Blog Listing

MaterialX Needs a Single-File Container

MaterialX assets are multiple loose files, which breaks down in online, and collaborative contexts. The community has already solved this with zip packaging. We just need to formalize it as .mtlz.

Ben HoustonApril 24, 20268 min read

At Land of Assets, we standardize on MaterialX and OpenPBR for material interchange.

That works well inside our pipeline. In collaborative and online delivery contexts, we ran into a practical gap: how do we exchange MaterialX materials between users and tools?

The Problem#

A typical MaterialX asset is a .mtlx file alongside multiple texture files, all wired together by relative paths that break the moment anything is moved or renamed. That structure is fine in a local DCC project folder. It is painful everywhere else:

  • No single file to upload, version, or share
  • Broken relative paths after moves or renames
  • Multi-file uploads break CDN and API workflows.

For marketplace distribution and API delivery, you need one file per material.

The Community Already Solved This#

Poly Haven and the AMD Material Library (two of the most widely used public MaterialX repositories) both distribute materials as .mtlx.zip archives. This has driven real-world convergence on a consistent internal layout:

MaterialX zip layout from PolyHaven and AMD Material Library

  • One .mtlx file at the root of the archive, named after the material
  • All textures under /textures/
  • Other resources (node definitions, includes) in subdirectories

Keeping the root clear of everything except the primary .mtlx file makes the layout unambiguous. Any tool can identify the entry point without guessing.

Poly Haven and AMD converged on this layout through practice, not a committee decision.

The Missing Piece: A Dedicated Extension#

The one thing .mtlx.zip cannot provide is first-class recognition. Every operating system and browser sees it as a generic zip file, because it is one. There is no way to register a MIME type for it, no way to associate it with a material viewer, and no way for an API or CDN to distinguish a material package from any other archive.

A dedicated extension fixes all of that at no cost to the format itself.

The .mtlz Format#

.mtlz is a name and a spec for the layout Poly Haven and AMD already ship. The format itself is a standard zip archive.

Layout#

marble-cliff.mtlz
├── marble-cliff.mtlx      ← exactly one .mtlx file, at the root
└── textures/
    ├── marble_cliff_diff.jpg
    ├── marble_cliff_nor_gl.exr
    ├── marble_cliff_rough.exr
    └── marble_cliff_disp.png

Normative rules#

  1. The archive is a valid zip file.
  2. Exactly one .mtlx file appears at the root level. Its name can be anything, but this name may be used in UIs for the material's name, so it is best to name it something meaningful, rather than "material.mtlx".
  3. All texture files are stored under subdirectories, such as /textures/.
  4. All other referenced resources (node definitions, includes, etc.) are stored in subdirectories, never at the root.
  5. The file extension is .mtlz.
  6. The MIME type is model/materialx+zip.

The model/materialx+zip MIME type follows the structured syntax convention used across the web (the same +zip suffix pattern seen in model/vnd.usdz+zip) and extends naturally from the existing model/materialx type registered for .mtlx files.

Metadata#

MaterialX has no built-in fields for author, license, or provenance on the root <materialx> element. The format's <attributedef> mechanism, designed for standardized extensions, fills that gap cleanly: declarations are self-describing, and tools that do not understand them will, per the MaterialX spec, preserve and re-emit them unchanged.

We propose the following metadata fields as part of the .mtlz convention, using the materialx_ prefix to avoid collisions with other tools' custom attributes:

<?xml version="1.0"?>
<materialx version="1.39" colorspace="lin_rec709"
  materialx_name="Marble Cliff"
  materialx_authors="Ben Houston ([email protected]), jcaron"
  materialx_license="CC0-1.0"
  materialx_license_url="https://creativecommons.org/publicdomain/zero/1.0/"
  materialx_source_url="https://example.com/materials/marble-cliff"
  materialx_version="1.0.0"
  materialx_description="A weathered marble cliff face with natural veining and displacement."
  materialx_keywords="marble, cliff, rock, natural, displacement, tiled">

  <attributedef name="materialx_name"        attrname="materialx_name"        type="string" value="" elements="materialx"/>
  <attributedef name="materialx_authors"     attrname="materialx_authors"     type="string" value="" elements="materialx"/>
  <attributedef name="materialx_license"     attrname="materialx_license"     type="string" value="" elements="materialx"/>
  <attributedef name="materialx_license_url" attrname="materialx_license_url" type="string" value="" elements="materialx"/>
  <attributedef name="materialx_source_url"  attrname="materialx_source_url"  type="string" value="" elements="materialx"/>
  <attributedef name="materialx_version"     attrname="materialx_version"     type="string" value="" elements="materialx"/>
  <attributedef name="materialx_description" attrname="materialx_description" type="string" value="" elements="materialx"/>
  <attributedef name="materialx_keywords"    attrname="materialx_keywords"    type="string" value="" elements="materialx"/>

  <!-- material graph ... -->
</materialx>
FieldFormatNotes
materialx_namestringHuman-readable material name
materialx_authorsName (email), NameComma-separated; email optional per author
materialx_licenseSPDX identifiere.g. CC0-1.0, CC-BY-4.0, MIT; free string also accepted
materialx_license_urlURLLink to full license text
materialx_source_urlURLCanonical origin of this material
materialx_versionSemVere.g. 1.0.0, 2.1.3
materialx_descriptionstringFree-text description of the material
materialx_keywordscomma-separated stringsSearch and discovery tags

All metadata fields are optional in the draft spec. Some material library systems may require a subset for indexing, moderation, or discovery.

Zip format recommendations#

For streaming renderers, we recommend the following:

  • File ordering: The root .mtlx file should be placed first in the archive, followed by other text files, and lastly the image files. Applications can then start parsing the material definition while textures are still loading.
  • Uncompressed storage: The files within the zip archive should be stored uncompressed. Renderers can memory-map the archive without decompressing it, giving direct access to image data.

What formalizing .mtlz enables#

With loose .mtlx.zip conventionWith formalized .mtlz format
OS treats it as a generic archiveOS can associate it with a material viewer
No MIME type for routingmodel/materialx+zip for APIs and CDNs
Browser offers generic zip handlingBrowser can trigger material-specific handling
Ambiguous in material librariesUnambiguous: this file is a material
Package structure is a loose conventionA formal spec defines valid structure and enables validation
No metadata standard exists for .mtlx.zipMetadata fields are standardized for indexing and provenance
Library and pipeline automation is heuristic-basedAutomation becomes reliable across search, policy, and workflows

FAQ#

Why not just use a degenerate USDZ, glB, or Blend file?#

While USDZ, glTF (GLB), and Blender files can theoretically act as a container for materials, each introduces unnecessary complications:

  • Ambiguous intent: It isn't clear from the file extension alone that it is a material-only file. So it has to be read and inspected to determine this.
  • Validation overhead: These formats support many different variations of materials already. You would need to parse the file, validate that it contains only a material, and then validate that the material is fully compatible with the MaterialX specification.
  • Translation complexities: These formats do not represent MaterialX directly. USDZ expects a USD Shade network, GLB translates materials to a JSON format (which has significant limitations compared to MaterialX), and Blender translates them to a Blender Shader Graph. Relying on these formats means you carry the heavy expectation of translating complex graph-based material definitions back and forth.

MaterialX has already emerged as the standard for graph-based materials with a well-defined file format. Adding a single-file container to that format is much easier than adopting a completely different file format, with all its associated complexities, just to get a zip container.

Path Forward#

At Land of Assets, we are testing the draft .mtlz format alongside our existing .mtlx.zip workflow in a real production scenario. This includes related tools and experiments in the same ecosystem, such as material-viewer.ben3d.ca and material-fidelity.ben3d.ca.

This is experimental. We welcome feedback and discussion from Poly Haven, AMD, and the broader MaterialX community. The format is already close to what everyone ships. The goal is a shared name, layout, and metadata spec.

If you are building material repositories, content pipelines, or DCC integrations, reach out.