Skip to content

Design Create

Author new scene-committed BIM entities. Every creator takes geometry handles + scalars and returns a ComponentHandle (or ComponentHandle[] for plural creators) — the Component.id of the created entity, resolvable across the rest of the design.* surface. Creation is an undoable host call; it throws on failure (no Result wrapper — consistent with core.geom.create.*). Accessed via snaptrude.design.create.

Footprint objects take a ContourHandle (outer profile + holes); build one with snaptrude.core.geom.create.contourFromProfile(s). Passing an invalid, stale, or foreign handle rejects with HandleInvalidError (code HANDLE_INVALID).

All lengths (heights, thicknesses, positions) are in Snaptrude units — convert with snaptrude.core.units.convert(value, from, to).

Performance

Creating many entities? Use the plural spaces(items) and copy(components, displacement, options) — the whole batch is one host round-trip. Looping a single-item creator (space, mass, slab, …) is one round-trip per item and can trip the rate limit. See Performance.

Types

PluginReferenceLineStyle

Line style of a reference line (mirrors the engine ReferenceLineMode verbatim).

ValueDescription
"SOLID"Solid line (default)
"DASHED"Dashed line
"DOT_DASH"Dot-dash line

PluginSlabType

Slab type (mirrors the engine SLAB_TYPES values verbatim).

ValueDescription
"Intermediate Slab"Intermediate floor slab (default)
"Basement Slab"Basement slab
"Plinth"Plinth slab
"Roof"Roof slab

PluginStaircasePreset

A staircase preset — a base type or a named parametric preset. Mirrors the engine STAIRCASE_PRESETS / StaircaseType. Use the value that matches the shape you want (e.g. "straight", "dogLegged", "lShaped").

Values: "straight", "straightWoLanding", "straightFlightWoMidLanding", "dogLegged", "openWell", "lShaped", "3StepLShaped", "square", "singleStep", "plinthLevel", "amphitheatre", "connectingStepsToAmphitheatre", "mezzanineFloorStraight", "mezzanineFloorDogLegged", "mezzanineFloorLShaped", "custom".

PluginSpaceType

Supported space type values (mirrors the internal SpaceType enum).

ValueDescription
"Room"Standard room
"Program Block"Program/department block
"Balcony"Balcony space
"Road"Road
"Garden"Garden area
"Deck"Deck
"Pool"Pool
"Walkway"Walkway
"Envelope"Envelope
"Parking"Parking area

PluginAreaClass

Area-class classification of a space (mirrors the internal AreaClass enum). Controls which area total a space's footprint contributes to — it does not change the space's own footprint area; it only decides which project-level total that footprint is summed into.

ValueDescription
"NET"Net (usable) area
"GROSS"Gross area
"EXCLUDED"Excluded from area totals

PluginMassType

Supported mass type values (mirrors the internal MASS_TYPES enum).

ValueDescription
"Plinth"Plinth mass
"Void"Void/cut-out
"Pergola"Pergola structure
"Furniture"Furniture element
"Facade element"Facade element
"Generic mass"Generic mass
"Room"Room (default for spaces)
"Department"Department block
"Building"Building envelope
"Revit Import"Imported from Revit
"Mass"Generic mass type
"Site"Site object

PluginDepartmentId

Accepted department ID values — either a well-known built-in ID (PluginWellKnownDepartmentId) or a UUID string for custom (user-created) departments.

ValueDepartment
"DEFAULT"Default department
"SITE"Site department
"ENVELOPE"Envelope department
"CORE"Core department
UUID stringCustom (user-created) department

PluginSmartLayoutArgs

Arguments for smartLayout. Provide a template as EITHER a templateGroup id OR an explicit templateComponents set (not both).

PropertyTypeDescription
templateGroupstring?Id of the group whose supported components form the template — a group id from snaptrude.core.groups.list (groups are string-id entities, NOT component handles)
templateComponentsComponentHandle[]?An explicit template component set
targetsComponentHandle[]The spaces/masses to lay the template into
hideTargetsboolean? (default true)Hide the target masses after placement

PluginSmartLayoutResult

Result of smartLayout — the created entities grouped by kind (flat across all targets; not attributed per target, so the run stays one undo batch).

PropertyTypeDescription
created.wallsComponentHandle[]Created walls
created.furnitureComponentHandle[]Created furniture
created.doorsComponentHandle[]Created doors
created.windowsComponentHandle[]Created windows
created.floorsComponentHandle[]Created floors
skippedWallsnumberWalls the solver could not place

Functions

space(contour, height, label?, position?, spaceType?, massType?, departmentId?, storey?)

Create a space (a room / mass) by extruding a footprint contour upward. The contour is the bottom footprint (outer profile + optional holes); it is extruded by height along +Y. The space is placed on the active story and assigned a default department unless overridden.

  • Parameters:
    • contour: ContourHandle — Bottom footprint (outer + holes)
    • height: number — Extrusion height in Snaptrude units (> 0)
    • label: string (optional) — Room label (maps to the space's room_type)
    • position: Vec3Handle (optional) — Offset from origin (default origin)
    • spaceType: PluginSpaceType (optional) — Space-type classification (default Room)
    • massType: PluginMassType (optional) — Mass-type classification (default Room)
    • departmentId: PluginDepartmentId (optional) — Department assignment (default department)
    • storey: number (optional) — Target storey number — the same integer entity.story uses (1 ground, 2 first floor, -1 basement). Default: the active storey. Folds an entity.story.setActive call into the create, placing the space at that storey's floor elevation; any position offset is applied on top.
  • Returns: ComponentHandle — The created space
  • Throws: If the contour is invalid, the height is not positive, or no storey has the given storey value
ts
const vec3 = snaptrude.core.math.vec3;
const points = [
  await vec3.new(0, 0, 0),
  await vec3.new(10, 0, 0),
  await vec3.new(10, 0, 8),
  await vec3.new(0, 0, 8)
];
const outer = await snaptrude.core.geom.create.profileFromLinePoints(points);
const contour = await snaptrude.core.geom.create.contourFromProfile(outer);
const space = await snaptrude.design.create.space(contour, 3, "Living");

// Place a room directly on the second floor — no entity.story.setActive dance:
const upstairs = await snaptrude.design.create.space(
  contour,
  3,
  "Bedroom",
  undefined,
  undefined,
  undefined,
  undefined,
  2
);

mass(contour, height, label?, position?, massType?)

Create a mass — a generic extruded prism (default massType "Generic mass"). Same footprint-extrude path as space.

  • Parameters:
    • contour: ContourHandle — Footprint (outer + holes)
    • height: number — Extrusion height (> 0)
    • label: string (optional) — Label (maps to room_type)
    • position: Vec3Handle (optional) — Offset from origin
    • massType: PluginMassType (optional) — Mass type (default Generic mass)
  • Returns: ComponentHandle — The created mass
  • Throws: If the contour is invalid or the height is not positive

slab(contour, thickness, direction?, slabType?)

Create a slab by extruding a footprint contour by thickness (default direction: down).

  • Parameters:
    • contour: ContourHandle — Footprint (outer + holes)
    • thickness: number — Slab thickness (> 0)
    • direction: "up" | "down" (optional, default "down") — Extrusion direction
    • slabType: PluginSlabType (optional) — Slab-type classification
  • Returns: ComponentHandle — The created slab
  • Throws: If the contour is invalid or the thickness is not positive

floor(contour, thickness, position?)

Create a floor by extruding a footprint contour by thickness (extruded upward).

  • Parameters:
    • contour: ContourHandle — Footprint (outer + holes)
    • thickness: number — Floor thickness (> 0)
    • position: Vec3Handle (optional) — Offset from origin
  • Returns: ComponentHandle — The created floor
  • Throws: If the contour is invalid or the thickness is not positive

roof(contour, thickness)

Create a roof by extruding a footprint contour by thickness. Created flat (extruded downward); pitch/slope is a separate post-creation edit.

  • Parameters:
    • contour: ContourHandle — Footprint (outer + holes)
    • thickness: number — Roof-slab thickness (> 0)
  • Returns: ComponentHandle — The created roof
  • Throws: If the contour is invalid or the thickness is not positive

ceiling(contour, thickness, heightFromFloor?)

Create a ceiling by extruding a footprint contour by thickness, lifted heightFromFloor above the floor.

  • Parameters:
    • contour: ContourHandle — Footprint (outer + holes)
    • thickness: number — Ceiling thickness (> 0)
    • heightFromFloor: number (optional, default 0) — Lift above the floor
  • Returns: ComponentHandle — The created ceiling
  • Throws: If the contour is invalid or the thickness is not positive

column(position, crossSection, height, directionUp?)

Create a column by extruding a cross-section contour upward by height from a base position. The column is built to exactly height — unlike the interactive draw tool, no slab-thickness deduction is applied.

  • Parameters:
    • position: Vec3Handle — Base point
    • crossSection: ContourHandle — Column cross-section footprint
    • height: number — Column height (> 0), built exactly
    • directionUp: Vec3Handle (optional, default world up) — Up axis; normalized, so magnitude does not scale the height
  • Returns: ComponentHandle — The created column
  • Throws: If the cross-section is invalid, the height is not positive, or the direction is zero / lies in the cross-section plane (degenerate extrusion)

beam(section, length, direction?)

Create a beam running length along direction. Matches the Snaptrude beam tool's semantics: the beam body hangs below the plane the section is authored on.

For a horizontal direction (the common spanning beam), author the section as an axis-aligned plan rectangle: its X extent is the beam's width and its Z extent is its depth (the vertical drop). The beam starts at the section's centre, runs length along direction, and hangs below the authoring plane by its depth — exactly like an interactively drawn beam. Only axis-aligned rectangular sections are supported horizontally.

For a vertical direction (the default), the section itself is extruded by length, again hanging below the authoring plane. Diagonal directions are rejected.

  • Parameters:
    • section: ContourHandle — Cross-section as an axis-aligned plan rectangle (X extent = width, Z extent = depth)
    • length: number — Beam length along direction (> 0)
    • direction: Vec3Handle (optional, default world up) — Beam axis, horizontal or vertical; normalized, so magnitude does not scale the length
  • Returns: ComponentHandle — The created beam
  • Throws: If the section is invalid (horizontal beams: not an axis-aligned plan rectangle), the length is not positive, or the direction is zero or diagonal
ts
// A 300x600 beam spanning 6 units along X (section: X extent = width 0.3, Z extent = depth 0.6):
const rect = await snaptrude.core.geom.create.profileRect(0.3, 0.6);
const section = await snaptrude.core.geom.create.contourFromProfile(rect);
const alongX = await snaptrude.core.math.vec3.new(1, 0, 0);
const beam = await snaptrude.design.create.beam(section, 6, alongX);

walls(profile, height?, thickness?, wallType?)

Create a connected run of walls from a profile — one wall per curve in the profile's chain, with mitred corners at shared endpoints.

wallType builds the run as a specific wall type — the same searchable list the Draw tab's Wall Type dropdown offers. Pass a name from design.types.list("wall") (the summary's label, or its "wall:…" id). The type is stamped on each wall (driving its construction layers, library data and default material) and, when thickness is omitted, its total layer thickness becomes the thickness — mirroring the dropdown's on-select defaults.

  • Parameters:
    • profile: ProfileHandle — Ordered curve chain (wall centerlines)
    • height: number (optional, default engine default) — Wall height
    • thickness: number (optional) — Wall thickness; defaults to the wallType's total layer thickness when wallType is given, else the engine default
    • wallType: string (optional, default the engine's generic wall) — Wall type name (or "wall:…" id) from design.types.list("wall")
  • Returns: ComponentHandle[] — One handle per wall, in profile order
  • Throws: If the profile is empty, wallType names no wall type in the project, or wall creation fails
ts
// …built as a specific wall type (layers/material/thickness from the type):
const [brick] = await snaptrude.design.types.list("wall");
const brickWalls = await snaptrude.design.create.walls(centerlines, 3, undefined, brick.label);

staircase(preset, position, label?, structureId?, level?)

Create a staircase from a parametric preset, placed at a point. Geometry is procedurally generated from the chosen preset; there is no footprint input. Placed on the active structure/story unless overridden.

  • Parameters:
    • preset: PluginStaircasePreset — The parametric preset to generate
    • position: Vec3Handle — Placement point
    • label: string (optional) — Optional label
    • structureId: string (optional, default active) — Target structure
    • level: string (optional, default active/"01") — Target level name
  • Returns: ComponentHandle — The created staircase
  • Throws: If the preset is unknown or placement fails
ts
const stair = await snaptrude.design.create.staircase(
  "dogLegged",
  await snaptrude.core.math.vec3.new(5, 0, 5)
);

referenceLines(profile, color?, thickness?, style?, gridTag?)

Create reference lines from a profile — one reference line per curve in the profile's ordered chain. Returns a handle per created line. Optional style (color, thickness, style, gridTag) applies to every created line.

  • Parameters:
    • profile: ProfileHandle — Ordered curve chain (centerlines)
    • color: string (optional, default white) — Hex color "#RRGGBB"
    • thickness: number (optional, default 1) — Line thickness
    • style: PluginReferenceLineStyle (optional, default "SOLID") — Line style
    • gridTag: string (optional, default "A") — Grid tag label
  • Returns: ComponentHandle[] — One handle per curve, in profile order
  • Throws: If the profile is empty or creation fails
ts
const vec3 = snaptrude.core.math.vec3;
const points = [await vec3.new(0, 0, 0), await vec3.new(10, 0, 0)];
const profile = await snaptrude.core.geom.create.profileFromLinePoints(points);
// skip color and thickness (undefined) to set only the style
const lines = await snaptrude.design.create.referenceLines(profile, undefined, undefined, "DASHED");

furniture(catalogId, position, options?, angleInDegrees?)

Place a furniture item from the project library at a world position. Identified by a catalog (library) id — the team object's stable _id for project uploads, or the item's fullName for the general library. Discover ids with design.furniture.listCatalog. Placement is asynchronous (the source mesh is fetched if not cached) and creates one undo entry.

The item is placed at its default rotation unless angleInDegrees is given, which rotates it about the vertical axis at creation time (baked into the same undo entry). To rotate an existing instance instead, use design.transform.rotate.

  • Parameters:
    • catalogId: string — Library id: team _id or general fullName
    • position: Vec3Handle — Absolute world placement point
    • options: object (optional) — Placement options:
      • options.label: string (optional, default auto ${name}Ins${n}) — Instance name
      • options.createNewSourceMesh: boolean (optional, default true) — Emit a source-mesh creation command
    • angleInDegrees: number (optional) — Signed rotation about the vertical axis, in degrees (same convention as design.transform.rotate). Applied at creation time. Default: the item's own (unrotated) orientation.
  • Returns: ComponentHandle — The placed furniture instance
  • Throws: If the catalog id is unknown, the source mesh fails to load, or placement fails
ts
const chair = await snaptrude.design.create.furniture(
  "6620f1a…", // from design.furniture.listCatalog()
  await snaptrude.core.math.vec3.new(3, 0, 5),
  { label: "Chair-01" }
);

// …placed already turned 90° about the vertical axis:
const turned = await snaptrude.design.create.furniture(
  "6620f1a…",
  await snaptrude.core.math.vec3.new(3, 0, 5),
  undefined,
  90
);

door(catalogId, hostWall, position, options?, facing?)

Place a door from the catalog onto a host wall at a world position. Discover catalog ids with design.doors.listCatalog. The point is projected onto the wall; the wall is re-cut as one undo batch.

facing selects which side of the wall the door faces (the room it opens into) — the same convention as approaching the wall from that side with the cursor in the interactive tool. Any world point clearly on that side works (e.g. the room's center). Without it the engine picks a side nondeterministically (the projected position sits on the wall centreline).

  • Parameters:
    • catalogId: string — Door catalog id
    • hostWall: ComponentHandle — The wall to host the door
    • position: Vec3Handle — World point (projected onto the wall)
    • options: object (optional)label?: string
    • facing: Vec3Handle (optional, default engine-chosen side) — World point on the side of the wall the door faces
  • Returns: ComponentHandle — The placed door
  • Throws: if the host wall has no mesh, the catalog id is unknown, or the hole cut fails
ts
const [wall] = await snaptrude.design.query.listWalls();
const [item] = await snaptrude.design.doors.listCatalog();
const door = await snaptrude.design.create.door(item.id, wall, position);

// …opening into a specific room (pass a point inside that room):
const intoKitchen = await snaptrude.design.create.door(
  item.id,
  wall,
  position,
  undefined,
  await snaptrude.core.math.vec3.new(3, 0, 9)
);

window(catalogId, hostWall, position, options?, facing?)

Place a window from the catalog onto a host wall at a world position. Discover catalog ids with design.windows.listCatalog. Same host-wall + hole-cut behaviour as door, including the optional facing side selector (matters for asymmetric windows, e.g. casement swing).

  • Parameters:
    • catalogId: string — Window catalog id
    • hostWall: ComponentHandle — The wall to host the window
    • position: Vec3Handle — World point (projected onto the wall)
    • options: object (optional)label?: string
    • facing: Vec3Handle (optional, default engine-chosen side) — World point on the side of the wall the window faces
  • Returns: ComponentHandle — The placed window
  • Throws: if the host wall has no mesh, the catalog id is unknown, or the hole cut fails

smartLayout(options)

Run the Smart Layout solver — replicate a template (a furnished room graph) into one or more target spaces. Split-gated behind the place_template treatment; Arrange auto-commits headless (no interactive review over the plugin boundary). Every target merges into one undo batch.

  • Parameters:
    • options: PluginSmartLayoutArgs — Template source (templateGroup XOR templateComponents), targets, and hideTargets?
  • Returns: PluginSmartLayoutResult — The created entities grouped by kind
  • Throws: when the feature is disabled, the template is missing/invalid, or there are no valid targets
ts
const result = await snaptrude.design.create.smartLayout({
  templateComponents: ["furnished-room-mass"],
  targets: ["target-1", "target-2"]
});
console.log(result.created.furniture.length, result.skippedWalls);

copy(components, displacement, options?)

Copy existing entities, offsetting copy i by displacement * i (i = 1…count), source positions preserved. To place N repeats, bulk-create the seed once then call this once with { count: N - 1 } — one host round-trip for every copy; never re-create the same geometry in a loop. Migrated from the removed tools.copy. In "instance" mode copies stay in the source's instance family where possible; "unique" makes independent geometry. The created copies become the active selection. Undoable.

  • Parameters:
    • components: ComponentHandle[] — Entities to copy (≥1)
    • displacement: Vec3Handle — Per-copy offset (copy i at displacement * i)
    • options: object (optional) — Copy options:
      • options.count: number (optional, default 1) — Copies per component (positive integer)
      • options.mode: 'instance' | 'unique' (optional, default 'instance') — Copy mode
  • Returns: ComponentHandle[] — The created copies
  • Throws: for an empty components array, a non-positive count, an unknown/forged handle, or an engine copy failure
ts
const { vec3 } = snaptrude.core.math;
const copies = await snaptrude.design.create.copy(["space-id"], vec3.new(6, 0, 0), {
  count: 3,
  mode: "unique"
});

spaces(items)

Create many spaces in one host round-trip (bulk plural of space) — always prefer this over calling space in a loop; it also commits as a single undoable operation. Migrated from the removed entity.space.bulkCreate. Each item extrudes a contour footprint. For a rectangular (box) space, build the footprint with core.geom.create.profileRectcontourFromProfile. Each item may carry its own storey, so one call can populate several floors at once.

  • Parameters:
    • items: PluginCreateSpaceItem[] — one per space: { contour: ContourHandle; height: number; label?: string; position?: Vec3Handle; spaceType?: PluginSpaceType; massType?: PluginMassType; departmentId?: PluginDepartmentId; storey?: number }. storey is the target storey number (default active storey) — see space.
  • Returns: ComponentHandle[] — the created spaces, in input order
ts
const rect = await snaptrude.core.geom.create.profileRect(4, 3);
const contour = await snaptrude.core.geom.create.contourFromProfile(rect);
// One room on the ground floor, one on the first floor — a single undo step.
const [a, b] = await snaptrude.design.create.spaces([
  { contour, height: 3, label: "R1", storey: 1 },
  { contour, height: 4, label: "R2", storey: 2 }
]);

Errors

Failed calls reject with a typed PluginError — see Error Handling. Conditions specific to this namespace:

CodeThrown byWhendetails
VALIDATIONall creatorsA dimension that must be > 0 (height / thickness / length) is zero or negative; copy count is not a positive integer; spaces/copy given an empty arrayThe offending field and value (e.g. extrudeHeight, count)
HANDLE_INVALIDall creatorsA contour / profile / position / direction / component handle cannot be resolved
PRECONDITION_FAILEDwalls, referenceLinesThe profile has no curves to build fromhandles — the profile id
PRECONDITION_FAILEDstaircaseNo active structure to place intoengineCode: "NO_ACTIVE_STRUCTURE"
PRECONDITION_FAILEDfurnitureThe catalog id matches no library itemengineCode: "FURNITURE_NOT_FOUND", catalogId
PRECONDITION_FAILEDspace, spacesA storey target was given but no storey has that valuestorey — the requested storey number
PRECONDITION_FAILEDcopyA source component was replaced by an earlier "instance" copy and is no longer live — re-query and copy the replacementhandles — the replaced source ids
OPERATION_FAILEDall creatorsThe engine could not build or commit the entity — e.g. the contour is not a valid closed footprint, the created entity got no id, or zero copies were createdFootprint failures carry handles — the contour id; engine Result failures preserve the engine's code in engineCode

spaces validates and resolves every item before touching the scene, so one bad item rejects the whole call without leaving partially-created spaces (all-or-nothing).