Project & File Formats
Surface Labs reads and writes four file formats of its own:
| Extension | What it is |
|---|---|
.surfacelabs | The project archive: all materials, subgraphs, embedded images, fonts, the preview model and export settings in one portable file |
.surfacenode | A single node or subgraph packaged for sharing, with a preview thumbnail |
.surfacetheme | An exported color theme |
.mcpb | A one-click Claude Desktop extension bundle exported by the MCP server settings page |
.surfacelabs, the project
Section titled “.surfacelabs, the project”A project is a single ZIP archive. Its internal structure:
| Entry | Contents |
|---|---|
manifest.xml | Format version (currently 1.0), app version stamp, project name, created and last-modified dates, and the project’s tags written in full (id, label, color) so tags survive moving between users |
graph/material.xml | The active material: every node with parameters, seed, resolution mode and override, bit-depth mode and override, ports and port defaults, plus all connections |
graph/m<n>.xml | One file per inactive material in the project |
materials.xml | The material list: each material’s name, and which index is active |
export_presets.xml | The project’s saved export settings (format, prefix, engine, material type, packed/individual toggles, normal override, disabled channels) |
exposed_params.xml | The project’s exposed-parameter list |
view_state.json | Canvas pan/zoom plus the 3D preview’s camera and render settings |
subgraphs/<id>.xml | One file per subgraph definition |
thumbnails/__project__.png | The rendered material image used as the project’s Hub card, written when the graph has a PBR Output |
media/<name> | Imported bitmaps used by Image nodes, referenced as media:<name>, plus the model imported into the 3D preview |
fonts/<name> | Imported fonts used by Text nodes, referenced as font:<name> |
Per-node preview images are not written. Encoding one PNG per node meant a GPU-to-CPU readback, a resize and an encode for every node in the graph on every save, which stalled large projects; nothing read them back, because canvas previews re-render when a project opens. The only image in the archive is the project’s Hub card.
The graph XML also carries canvas furniture: Jump Nodes, comment boxes (position, size, background color and opacity, text) and freehand annotation strokes.
The archive is zipped and written on a background isolate, so autosaving a project with tens of megabytes of embedded media does not freeze the editor.
Embedded assets
Section titled “Embedded assets”Everything a project depends on travels inside it, so a .surfacelabs you hand
to someone else opens the same way it does for you:
- Imported bitmaps used by Image nodes.
- Fonts used by Text nodes, so a Text node typesets identically on a machine that does not have the font installed.
- The 3D preview model, when you import your own
.objor.glb. - Tags, written into
manifest.xmlin full (id, label, color) rather than as bare ids, so they arrive with the labels their author chose.
Embedded assets are pruned on save: one no longer referenced by any material or
subgraph is dropped rather than carried forever, so deleting or repointing an
Image or Text node stops inflating every later save. The prune reads every
material and subgraph, not just the active one, so a bitmap used only by a
material you have not switched to is never removed, and it only drops an asset
once a saved copy exists to fall back on. The preview model is named by
view_state.json rather than by a node parameter, and is kept on that basis.
Loading
Section titled “Loading”A missing manifest.xml or graph/material.xml is a hard error. Unknown node
types are skipped with a warning rather than aborting the load. Missing optional
entries degrade gracefully: no materials.xml resets to a single material, no
view_state.json clears the pending view state, no export_presets.xml
restores export defaults. A corrupt view_state.json is ignored rather than
failing the load. A project that fails to open is copied into the crash
directory automatically so it can be attached to a bug report.
A project last saved when JPEG was still an export format loads with its format reset to PNG: an unrecognized format name falls back rather than failing, and PNG is the closest lossless equivalent. See Exporting.
Where projects live
Section titled “Where projects live”New projects from the Project Hub go into a
Surface Labs folder inside your Documents folder, created on first use. (On
systems where a Documents folder cannot be resolved, the app falls back to
$HOME/Documents, then the app-support directory, then the home directory.)
Projects can be moved and opened from anywhere afterwards.
Multi-material projects
Section titled “Multi-material projects”A project can hold several materials. The Material Library panel lists them: tap one to switch (the live graph is snapshotted into the outgoing entry first), Add Material creates an empty one, and ✕ deletes an inactive one. The active material and the last remaining material cannot be deleted.
Only the active material is live in the editor, and the in-app export dialog only ever exports a node from the active material. Exporting every material in one pass, with each non-active material’s files suffixed by its name, exists only through the MCP and command-line surface, not in the app UI. See Multi-Material Projects for working with materials in the editor.
.surfacenode, a single node
Section titled “.surfacenode, a single node”A small ZIP holding one node:
| Entry | Contents |
|---|---|
node.xml | The node’s type, label, all parameter values, seed, resolution mode and override, bit-depth mode and override, and its ports including values set directly on unconnected inputs |
thumbnail.png | The node’s last rendered output, written only when the node has already been evaluated |
Connections are not part of the package: it describes one node in isolation. A
missing thumbnail is not an error; previews regenerate. Unlike a
.surfacelabs, a .surfacenode carries no embedded assets and no tags - so a
node that depends on an imported bitmap does not bring the bitmap with it, and
any tags you applied to it stay on your machine. See
Sharing Nodes for how to export and import these
packages.
.surfacetheme, an interface theme
Section titled “.surfacetheme, an interface theme”A plain, indented JSON file (not a ZIP) holding one interface theme: its id, name, light/dark brightness, and one hex color per interface token, covering surfaces, text, borders, accent, status colors, overlay scrim, and the per-type node-connection colors. Exported and imported from Settings → Appearance. Themes exported by older builds are still readable: tokens added later fall back to their defaults instead of failing the import. A file that cannot be read or does not match the expected shape fails the import rather than partially applying.