Skip to content

Operations and undo

Every change to the model happens inside an operation. An operation groups edits into one named step in Edit → Undo:

const { mm } = modlumi;
const model = modlumi.activeModel;
const edges = model.operation("Draw line", () =>
model.activeEntities.addEdges([[0, 0, 0], [mm(500), 0, 0]]),
);
console.log(`Drew ${edges.length} edge`);

model.operation(name, body) runs body and returns what it returns. Edits outside an operation throw ModelError. Reading the model doesn’t need an operation, and neither does changing the selection.

  • An operation whose body returns normally commits one undo step. An operation with no edits adds nothing to the history.
  • An error thrown out of the body rolls back every edit made in it, and model.operation throws it on.
  • A failed edit aborts the whole operation straight away, even if you catch the error inside the body. Any further edits in that operation fail.
  • Operations that already committed stay committed when a later one fails.

So if you want to try something that might fail without losing earlier work, give it its own operation:

const model = modlumi.activeModel;
model.operation("Base", () => {
model.entities.addEdges([[0, 0, 0], [2, 0, 0], [2, 2, 0], [0, 2, 0], [0, 0, 0]]);
});
const [face] = model.entities.ofType("Face");
try {
model.operation("Raise", () => face.extrude(1));
} catch (error) {
if (!(error instanceof modlumi.ModelError)) {
throw error;
}
console.log("Extrusion failed, the base is kept:", error.message);
}

Operations can’t be nested, and the body must be synchronous: returning a promise rolls the operation back and throws ModelError. Do any awaiting before or after the operation.

model.undo() and model.redo() step through the history, just like the Edit menu. They can’t be called inside an operation.

const model = modlumi.activeModel;
const edges = model.operation("Draw line", () => model.activeEntities.addEdges([[0, 0, 0], [1, 0, 0]]));
model.undo();
console.log("Deleted after undo:", edges[0].isDeleted);
model.redo();
console.log("Restored after redo:", edges[0].isValid);

Undo and redo keep entity identities, so objects you hold stay usable after a redo.

Error Thrown when
TypeError, RangeError An argument has the wrong type or value
modlumi.ModelError The model rejects an edit or a query
ReferenceError An entity was deleted, or belongs to a model that’s no longer open

The window’s scene updates after the script finishes, including when it ended with an error. Committed edits are kept either way.