Appearance
Layout
The async arrange / pack space-planning jobs — stages two and three of the workflow that starts with program.adjacency. Accessed via snaptrude.program.layout.
Both arrange and pack wrap the product's Arrange / Pack-in-envelope tools (a backend space-solver that can run for up to ~20 minutes). They are fire-and-forget: they resolve inputs, start the job, and return { success: true } immediately. Poll getState for completion — a solver failure surfaces there as inactive, not as a rejected call. Both are Pro-gated, matching the UI. The run state is page-session only (a reload starts fresh).
arrange produces several candidate layouts. By default it auto-commits the first one headless; pass autoCommit: false to hold the candidates for review instead — the run then finishes as pendingReview with totalSolutions in getState, and applySolution(index) commits the one you pick (the headless counterpart of the product's "Solution N of M → Apply" review bar). cancel discards a pending review without applying anything. pack applies its single result directly — it ignores autoCommit.
stack is the cross-storey action — the product's Pack-in-envelope / auto-stack. It splits the building envelope by storey and packs each storey's departments into its slice as one undoable edit. Unlike arrange / pack, it is not the async-job model: await it and it resolves when the whole multi-storey pack is done (no getState polling). It too is Pro-gated, and it is mutually exclusive with an in-flight arrange / pack run.
Types
PluginProgramLayoutRunArgs
Options for arrange / pack. Omit everything to lay out every eligible mass on the active storey into the auto-detected envelope.
| Property | Type | Description |
|---|---|---|
spaceIds | string[]? | Room-level masses to lay out (default: all eligible) |
departmentIds | string[]? | Department-level masses to lay out (default: all eligible) |
envelopeId | string? | Envelope target — a be_… buildable-envelope id or a mass id (default: auto-detect the single envelope on the active storey) |
autoCommit | boolean? | arrange only — true / omitted (default) auto-commits the first candidate solution; false holds the candidates for applySolution. Ignored by pack |
PluginProgramLayoutRunResult
Whether the run was started (not whether it finished).
| Property | Type | Description |
|---|---|---|
success | boolean | Whether the layout run was started |
PluginProgramLayoutStateResult
The current run's state, or null when nothing has run / it was cancelled.
| Property | Type | Description |
|---|---|---|
status | 'running' | 'active' | 'inactive' | 'pendingReview' | running in flight; active once a layout applied; inactive when a run finished without applying one; pendingReview when an arrange({ autoCommit: false }) run finished and its candidates await applySolution / cancel |
totalSolutions | number? | Number of candidate solutions awaiting review — present only while status is pendingReview |
PluginProgramLayoutApplyResult
The outcome of applySolution.
| Property | Type | Description |
|---|---|---|
success | boolean | Whether the chosen solution was applied |
PluginProgramLayoutStackResult
The outcome of a stack run.
| Property | Type | Description |
|---|---|---|
success | boolean | Whether the stack was applied |
skippedStoreys | number[] | Storey values that had departments but no envelope — nothing packed there |
error | string? | Failure reason when success is false |
Functions
arrange(options?)
Start an Arrange run — lay the masses out in the envelope. By default the first candidate solution is auto-committed headless; with autoCommit: false an arrange-with-envelope instead holds its candidates for review (getState → pendingReview + totalSolutions, then applySolution or cancel). An arrange without an envelope applies directly regardless of autoCommit (there is nothing to review). Fire-and-forget; Pro-gated. While solutions are pending review, new arrange / pack / stack runs are refused — apply or cancel first.
- Parameters:
options:PluginProgramLayoutRunArgs(optional)
- Returns:
PluginProgramLayoutRunResult—{ success: true }once started - Throws: when writes are disabled, the workspace is not on a Pro plan, or arrange solutions are pending review
ts
await snaptrude.program.layout.arrange();
// poll until it settles
let state = await snaptrude.program.layout.getState();
while (state?.status === "running") {
await new Promise((r) => setTimeout(r, 5000));
state = await snaptrude.program.layout.getState();
}pack(options?)
Start a Pack-in-envelope run — applies its single result internally. Fire-and-forget; Pro-gated.
- Parameters:
options:PluginProgramLayoutRunArgs(optional)
- Returns:
PluginProgramLayoutRunResult—{ success: true }once started - Throws: when writes are disabled, the workspace is not on a Pro plan, or arrange solutions are pending review
applySolution(index)
Commit one of the pending arrange candidates — the headless counterpart of the product's "Solution N of M → Apply" review bar. After an arrange({ autoCommit: false }) run finishes as pendingReview, this switches the solver to the candidate at index (0-based, 0 ≤ index < totalSolutions) and commits it as one undoable edit, discarding the other candidates. getState then reports active. Write-gated.
If the pending review was resolved natively out from under the plugin (the solver is shared with the product UI), the call fails PRECONDITION_FAILED and the run state resets.
- Parameters:
index:number— 0-based index of the pending solution to apply
- Returns:
PluginProgramLayoutApplyResult—{ success: true }once applied - Throws: when writes are disabled, no solutions are pending review, or
indexis out of range
ts
await snaptrude.program.layout.arrange({ autoCommit: false });
let state = await snaptrude.program.layout.getState();
while (state?.status === "running") {
await new Promise((r) => setTimeout(r, 5000));
state = await snaptrude.program.layout.getState();
}
if (state?.status === "pendingReview") {
console.log(`${state.totalSolutions} candidate layouts`);
await snaptrude.program.layout.applySolution(1); // commit the second one
}stack()
Stack the program across every storey — the product's auto-stack. Splits the building envelope massing into per-storey slices, then packs each storey's departments into its slice, applied as one atomic undo. Takes no arguments: it auto-discovers the departments and envelope on each storey. It does not move departments between floors — each floor's program is laid out into that floor's envelope.
Unlike arrange / pack, this awaits to completion (no polling). Storeys with departments but no envelope come back in skippedStoreys. Operational failures (e.g. the adjacency service is unreachable) return { success: false, error } rather than throwing. Pro-gated; refuses while an arrange / pack run (or another stack) is in flight, or while arrange solutions are pending review.
- Returns:
PluginProgramLayoutStackResult - Throws: when writes are disabled, the workspace is not on a Pro plan, another layout run is in flight, or arrange solutions are pending review
ts
const { success, skippedStoreys, error } = await snaptrude.program.layout.stack();
if (!success) throw new Error(error);
if (skippedStoreys.length) {
console.warn(`No envelope on floors: ${skippedStoreys.join(", ")}`);
}getState()
Read the current run's state. The completion / failure signal for arrange and pack. While an arrange({ autoCommit: false }) run's candidates await review, status is pendingReview and totalSolutions carries the candidate count.
- Returns:
PluginProgramLayoutStateResult—nullwhen nothing has run
cancel()
Cancel the in-flight run (if any) and reset the run state. Also discards a finished run's pending-review candidates without applying one (the review bar's Cancel) — the preview clones are disposed and the scene returns to its pre-review state. Write-gated.
- Returns:
boolean—trueif a run was cancelled or pending solutions were discarded,falsewhen there was nothing to cancel - Throws: when writes are disabled