Skip to content

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.

PropertyTypeDescription
spaceIdsstring[]?Room-level masses to lay out (default: all eligible)
departmentIdsstring[]?Department-level masses to lay out (default: all eligible)
envelopeIdstring?Envelope target — a be_… buildable-envelope id or a mass id (default: auto-detect the single envelope on the active storey)
autoCommitboolean?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).

PropertyTypeDescription
successbooleanWhether the layout run was started

PluginProgramLayoutStateResult

The current run's state, or null when nothing has run / it was cancelled.

PropertyTypeDescription
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
totalSolutionsnumber?Number of candidate solutions awaiting review — present only while status is pendingReview

PluginProgramLayoutApplyResult

The outcome of applySolution.

PropertyTypeDescription
successbooleanWhether the chosen solution was applied

PluginProgramLayoutStackResult

The outcome of a stack run.

PropertyTypeDescription
successbooleanWhether the stack was applied
skippedStoreysnumber[]Storey values that had departments but no envelope — nothing packed there
errorstring?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 (getStatependingReview + 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.

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.


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 index is 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.


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: booleantrue if a run was cancelled or pending solutions were discarded, false when there was nothing to cancel
  • Throws: when writes are disabled