The .mmgraph document
A graph is saved as a .mmgraph file (file-dialog filter: Mesh Morpher Graph (*.mmgraph)). The current format is version 6; the loader also reads version 5 and upgrades it in memory, but always writes version 6 back out, and files older than version 5 will not load at all.
What is stored in it:
- the graph's stable internal ID
- the graph's display name - the same name set by Edit > Rename Graph... (see The Window), which is why the tab label and the Save dialog's suggested filename both survive a reopen
- graph variables
- comment boxes: id, text, position, size and colour
- every node: its class, its id, its canvas position, and its full property data (compressed since format version 6)
- every connection
- every pin's byte payload - meshes, textures and other bulk data live inside the document itself, addressed by a table of contents at the end of the file so large pins can be loaded lazily rather than all at once
What is deliberately not stored:
- the file's own path on disk, and whether the document has unsaved changes - both are decided fresh each time the file is opened
- a node's message, its severity, and its out-of-date badge - these describe your current editing session, not the saved document (see Nodes and Wires)
- undo history
- selection, pan, zoom, and which subgraph card you were inside
- runtime objects a node builds for itself, such as a decoded texture or a dynamic material - these are rebuilt when the file is opened
- app-level settings such as panel layout, window geometry, recent files, theme and minimap visibility - see the table at the end of this page
Opening a document never runs a node, reads an external file, or writes a pin. Loading a graph is contractually a restore, never a recompute. It must never write a pin's payload, mark the graph dirty, or trigger a render; and it must never read an external source file such as your FBX or PNG - re-reading the source is your job, via an explicit action button on the node. The app holds a flag for the whole duration of a load, so that an accidental violation trips a loud internal error rather than silently changing a saved result. There is one narrow exception: a Load Texture From File node caches its own source bytes, so the rule still holds for it, and only a graph saved before that cache existed falls back to reading the file from disk.
A node whose class this build cannot resolve is not dropped when the file loads - it is preserved as the placeholder described in Nodes and Wires, holding its original class and property bytes exactly, and writes them back unchanged the next time you save.
Save behaviour
Save always asks for a destination. There is no quick-save that writes silently over the current file.
Saving to a different file from the one the document came from gives the graph a new internal ID, so the old file and the new one never fight over the same autosave slot. The Save dialog's suggested filename follows the graph's display name, not its on-disk filename - so renaming a graph and then saving suggests the new name - but saving into a path with a different base name does not rename the graph back. On success you see the toast Saved {filename}; on failure, Save failed: {error}.
Unsaved-changes prompts
Closing a document tab, or the app, with unsaved changes:
"{name}" has unsaved changes.
Yes - save before closing.
No - close and discard the changes.
Cancel - keep it open.
Closing the app while a tool has unbaked edits:
You have unsaved tool edits on the current node.
Yes - accept and bake the changes before closing.
No - discard the changes.
Cancel - keep the app open.
Switching document tabs with unbaked tool edits shows a similarly shaped prompt with different wording - see The Window.
If the document already has a file on disk, Yes writes straight to it with no further dialog; a document that has never been saved goes through the normal Save dialog instead, and the window only actually closes once the graph is clean. A save that fails never lets the close proceed. Once every open tab has been resolved this way, any leftover autosave sidecars and scratch files for those documents are swept up, so nothing can resurrect itself on the next launch.
Autosave
Mesh Morpher autosaves every 300 seconds (5 minutes) by default, checked every 30 seconds; the interval is controlled by the console variable mm.AutosaveIntervalSeconds ("Seconds between autosave passes over dirty graphs. 0 disables autosave."). Every document with unsaved changes is snapshotted on each pass; a clean document has its snapshot deleted instead. A document whose mesh is mid brush-stroke is skipped for that one pass only - other open documents are still protected.
Where snapshots go:
- a document that has been saved at least once:
<its path>.autosave, next to the real file (for exampleMyGraph.mmgraph.autosave) - a document that has never been saved:
%LOCALAPPDATA%/MeshMorpher/Autosave/<GraphId>.mmgraph.autosave
Every autosave write is atomic - written to a temp file, then swapped in - so an interrupted write can never corrupt the last good snapshot.
If autosave fails, you are told, not just logged. The message appears once per destination: Autosave failed for "{file}" ({reason}). This graph is NOT protected against a crash - save it somewhere writable.
Nothing is written from inside a crash handler by design - what survives a crash is only the last periodic snapshot that made it to disk.
The restore prompt on open
If a file's autosave sidecar is newer than the file itself, opening it asks first, in a dialog titled "Restore Autosave":
An autosave of "{filename}" is newer than the file itself (likely from an interrupted session).
Yes - open the autosave (Save afterwards to keep it).
No - open the file as last saved.
Yes opens the autosave content but keeps the real file as the document's home, and leaves the document dirty so you have to consciously Save to keep the recovered work. No back-dates the sidecar rather than deleting it - your autosaved bytes are kept on disk, but the prompt will not reappear on every future open. If the autosave cannot be staged for opening at all, the last saved version opens instead, with the toast "The autosave could not be prepared for opening, so the last saved version was opened instead. The autosave file has been left untouched."
Separately, unsaved pin edits are recovered from a per-graph scratch file: if any are found for a graph you are opening, a dialog titled "Recover Unsaved Edits" asks: {N} unsaved pin edit(s) from a previous session were found for this graph. Recover them?
At launch, after a crash
Documents that had never been saved when a previous session crashed are restored automatically into new tabs, with the toast Restored {N} unsaved graph(s) from autosave. A snapshot that cannot be read is not deleted - it is renamed with an .unreadable suffix and reported: {N} autosave snapshot(s) could not be read and were set aside as '.unreadable' in the Autosave folder. They are kept in case they can be salvaged, and will not be retried.
Node presets (.mmnode)
A .mmnode file is one or more nodes exported out of a graph, with a title, author, category, tags and description you fill in - file-dialog filter Mesh Morpher Node (*.mmnode). It uses its own file signature, deliberately distinct from a graph's, so opening the wrong file type gives a clear error rather than a confusing one.
Exporting
From a node's right-click menu (see Nodes and Wires): Export Node Preset... writes a file, Save to My Presets... installs straight into your local library. Both open the same dialog, with fields for Title (pre-filled with the node's title, or {N} Nodes for a multi-selection), Author (pre-filled with your OS user name), Category / Tags, and a multi-line Description. A live summary line reads {N} node(s), {bytes} bytes, or Cannot export: {reason} if the selection cannot be exported at all.
Exporting to a file opens an OS save dialog titled "Export Node Preset", defaulting to {Title}.mmnode; on success it toasts Exported / {Title} -> {path}. Installing to your library checks for an existing preset with the same identity first, and if one exists, offers Replace, Keep Both or Cancel, noting: "Either choice only affects My Presets. Any node you already placed from the current install is an independent copy in its own graph and is not touched."
Importing
Four routes, all ending at the same Import Node Preset dialog:
- File > Import Node...
- Drag a single
.mmnodefile onto the app window or onto the graph canvas - Paste a shared text envelope with
Ctrl+V - Settings > Nodes > Import...
The dialog shows the preset's title, author, description, category and tags, what it contains (Contains: {N} node(s) - {friendly class names}), and a short file fingerprint. If the preset carries a Python script, it shows this warning:
"This preset contains a Python script. Nothing runs when you install or place it - scripts only ever run when you press Run. Read the script before you run it, the same way you would a downloaded file. Settings > Scripting can disable scripting entirely on this machine."
And this note always appears at the bottom of the dialog:
"Placing a node embeds a complete copy in your graph. Uninstalling later never changes graphs you have already saved, and a .mmgraph you share opens correctly for people who do not have this preset installed."
Two buttons decide what happens: Install ("Add this preset to My Presets, so it shows up in the Add Node menu on this machine.") and Add to This Graph Only ("Place this preset's node(s) here without installing anything." - disabled when there is no graph open to place it into).
Managing installed presets
Settings > Nodes lists everything installed, with Import... and Refresh buttons, and a per-preset Uninstall. Uninstall is disabled for presets that shipped with the app, with the tooltip "This preset shipped with the app and cannot be uninstalled."; for anything you installed yourself, its tooltip reads "Remove this preset from My Presets. Graphs you already placed it into are not affected." Confirming shows:
Uninstall "{Title}"?
This removes it from My Presets and the Add Node menu. Any graph you already placed it into keeps its own independent copy and is not affected.
Uninstalling a preset never changes a graph you already used it in. Placing a node from a preset always embeds a full, independent copy in that graph - the graph does not keep referring back to the installed preset afterwards.
The shipped presets live inside the app's own install; your own live at %LOCALAPPDATA%/MeshMorpher/NodePresets/ - you can drop a downloaded .mmnode there by hand, and subfolders are scanned recursively.
Where settings and user files live
| Location | Holds |
|---|---|
%LOCALAPPDATA%/MeshMorpher/MMAppLayout.json |
Window position, size and maximised state; UI scale; the serialised dock layout; undo limits; the theme palette; and Recent Files (max 5). A pre-July-2026 copy under <exe>/Config/MMAppLayout.json is still read as a fallback, but all writes go to the path above. |
%LOCALAPPDATA%/MeshMorpher/MMWelcome.json |
Whether the Welcome screen shows at startup, plus a content-revision stamp |
%LOCALAPPDATA%/MeshMorpher/MMSimulationSettings.json |
Whether simulation nodes are shown |
GameUserSettings.ini, section [MeshMorpher.GraphEditor] |
Minimap visibility (bShowMinimap) |
%LOCALAPPDATA%/MeshMorpher/Starters/ |
Your editable copies of the shipped examples |
%LOCALAPPDATA%/MeshMorpher/Autosave/ |
Crash snapshots of documents that had never been saved |
%LOCALAPPDATA%/MeshMorpher/NodePresets/ |
Your installed .mmnode presets |