Skip to main content

My First Assembly

Let's create your first assembly in DynaMaker!

In this tutorial, you will learn how to create an assembly, which is essentially a component with subcomponents, following the configurable size. As a product example, we will use a configurable indoor staircase consisting of steps and glass railings.

For this we will follow 3 steps:

  1. Create new project
  2. Prepare subcomponents
  3. Build assembly

This tutorial takes approximately 30 minutes to complete. Good luck!

1. Create New Project

  • Create a new project and name it for example StaircaseApp.
  • Remove the default component Component1, and create 3 new components:
    • Step
    • Railing
    • Assembly

2. Prepare Subcomponents

Starting from the cube template, we will change the model for the Step and Railing needed for the Assembly.

A. Step

As for the step, we will only change its default properties and its color.

  • Go to the project dashboard and go into the component Step.
  • Go to COMPONENT and update the default property values, e.g. with these values:
constructor() {
super() = {
depth: 500,
height: 20,
width: 200,
  • In generateGeometry(), you can change quickly the color of the material to e.g. light brown as:
geometryGroup.addGeometry(model, {
materials: [new SKYCAD.Material({ color: 0xC4A484 })],
  • Save & Update to apply the changes.
  • Publish to be able to use it later in _Assembly_.

Don't worry about the configurator here, we will use the one of the Assembly instead.

tutorial-my-first-assembly-step Dimensions were added to help you understand the size. They won't be visible later

B. Railing

Here we will add a fourth property railingHeight, remove depth, and change its shape and material.

  • Go back to the project dashboard and go into the component Railing.
  • Go to COMPONENT, create a new property railingHeight and remove depth. Make sure you have:
constructor() {
super() = {
height: 3000,
width: 5000,
railingHeight: 1200,
  • You will see an IntelliSense error in railingHeight (highlighted in red), saying that this property does not exist in properties. Since properties are defined as CONSTANTS.Properties, go to CONSTANTS and make sure you have:
export interface Properties {
height: number
width: number
railingHeight: number
  • Save & Update to apply changes.
  • Refresh (F5) so the IntelliSense loads properly in all tabs.

You will survive if you don't update the IntelliSense, but its purpose is to assist you when coding and make sure you are accessing the right functions. E.g. now you know that, within the class Component (COMPONENT), when you type you only see height, width & railingHeight as available options. This will not only avoid problems within this component but wherever is used throughout the whole project!

  • Let's fix the unexisting properties width and depth, at the same time we change the shape:

    • In COMPONENT, it is up to you to remove or adjust the dimension created in generateLightweightGeometry() since we won't use it (or even removing the whole function as well).

      • In COMPONENT, in generateGeometry(), send height, width & railingHeight as arguments:
        const { height, width, railingHeight } =
        const model = GEOM3D.generateModel(height, width, railingHeight)
    • In GEOM2D, create the sketch (side view) for the railing in a function:

      export function generateRailingSideViewSketch(height: number, width: number, railingHeight: number) {
      const sketch = new SKYCAD.Sketch()
      sketch.moveTo(0, 0)
      sketch.lineTo(0, railingHeight)
      sketch.lineTo(width, height + railingHeight)
      sketch.lineTo(width, height)

      const CORNER_RADIUS = 50
      sketch.getNodes().forEach((node, nodeId) => {
      if (nodeId === 1 || nodeId === 2) {
      sketch.addFillet(CORNER_RADIUS, nodeId)

      return sketch
    • In GEOM3D:

      • update the arguments of generateModel(), so it matches what you wrote in generateGeometry():
      • use the sketch you created in GEOM2D instead, change the plane direction and make the extrusion as thick as the glass (e.g. 15 mm):
      export function generateModel(height: number, width: number, railingHeight: number) {
      const model = new SKYCAD.ParametricModel()

      const GLASS_THICKNESS = 20
      const railingSideViewSketch = GEOM2D.generateRailingSideViewSketch(height, width, railingHeight)
      const refPlane = new SKYCAD.Plane(0, -1, 0, 0)
      model.addExtrude(railingSideViewSketch, refPlane, GLASS_THICKNESS)

      return model
  • In COMPONENT, change the material directly in generateGeometry() to light blue and make it slightly transparent with the material setting opacity (0 = invisible, 1 = opaque):

    geometryGroup.addGeometry(model, {
    materials: [new SKYCAD.Material({ color: 0xadd8e6, opacity: 0.5 })]
  • Save & Update to apply changes
  • Publish to be able to use it later in _Assembly_.

tutorial-my-first-assembly-railing Dimensions were added to help you understand the size. They won't be visible later

Notice that when you Save & Update a component, this will be flagged with a * in the project dashboard, meaning that the component has changed and needs to be published (via Publish) if you want to see the latest version of your component in other components that might use it.

3. Build Assembly

To build the Assembly from other components, it's easier to use what we called the Component Handler.

A. Component Handler Basics

Why using Component Handler? It provides several advantages compared to regular product or component handling from other common CAD software solutions:

  • Use the same component to create multiple copies or instances.
  • Getting or removing all the instances that share the same component.
  • Adding components with their own Component Handler into other components.
  • Using as many components in the app as required.
  • Things to consider:
    • Instances can refer to the same component while having different positions and rotations.
    • A component never has a position. This is handled by the instance instead.
    • What you see in the app is always instances, whose geometries are generated from their component.
    • The Part and Assembly/Product levels, common in other CAD software solutions, do not exist here.
    • You decide how the component level looks like through the Component Handler.

With that said, let's jump into it. We will create an Assembly with multiple Steps and one Railing.

B. Import Components

First off, to be able to use the components Railing & Step in Assembly, you need to import them.

  • Go to the project dashboard and go into the component Assembly.
  • In edit/hide imports... above the code editor, add Step and Railing from the imports dropdown.


Notice that the #region import (on top of the code) has been updated automatically. This region should not be edited manually.

C. Clean Assembly

We will start cleaning the functions in the component Assembly and then we will add the subcomponents.

Let's start cleaning the component and its parameters:

  • give reasonable default values to the properties (COMPONENT). = {
    depth: 800,
    height: 2500,
    width: 3000,
  • empty or remove generateGeometry() and generateLightweightGeometry() for now.

  • set reasonable max/min values of the parameters (PARAMETERS) and making them sliders for simplicity.

    const widthParameter = SKYPARAM.generateSlider('width', 'Width (x)', {
    defaultValue: component.getProperty('width'),
    maxValue: 5000,
    minValue: 2500,
    stepSize: 100,
    unit: 'mm',

    const depthParameter = SKYPARAM.generateSlider('depth', 'Depth (y)', {
    defaultValue: component.getProperty('depth'),
    maxValue: 1000,
    minValue: 300,
    stepSize: 100,
    unit: 'mm',

    const heightParameter = SKYPARAM.generateSlider('height', 'Height (z)', {
    defaultValue: component.getProperty('height'),
    maxValue: 3000,
    minValue: 1000,
    stepSize: 100,
    unit: 'mm',
  • Save & Update and the _Preview_ should be empty.

D. Add subcomponents

To add the subcomponents, we need to make sure to:

  • add them to the componentHandler of the Assembly component (usually done in update())
  • call update() when loading the Assembly component (at the end of its constructor), so the subcomponents are created and added.
  • generate the geometry of the subcomponents in generateGeometry() of the Assembly component.

Let's start with update(). A good pattern to begin with is usually to start by clearing all components, then create them, set the properties and finally add them back. Starting with the railing it would be like:

update() {
const { width, height, depth } =

// Railing
const railingComponent = new RAILING.Component()
railingComponent.setProperties({ width, height })
this.componentHandler.add(railingComponent, {
position: new SKYMATH.Vector3D(0, 0, 0)

// Steps
// here the steps will be added

Great, let's include the steps as well with a small design automation to distribute them evenly along the railing. You can try the following, but feel free to be creative with your own rules.

update() {
const { width, height, depth } =

// Railing

// Steps
const stepComponent = new STEP.Component()
stepComponent.setProperties({ depth })

const stepWidth = stepComponent.getProperty('width')
const MAX_STEP_RISE = 220

const nrSteps = Math.max(Math.floor(height / MAX_STEP_RISE), Math.floor(width / stepWidth))

const stepRise = height / nrSteps // z-space between steps
const stepRun = width / nrSteps // x-space between steps

for (let i = 0; i < nrSteps; i++) {
this.componentHandler.add(stepComponent, {
position: new SKYMATH.Vector3D(i * stepRun, 0, (i + 1) * stepRise)

Notice that what adding a component into the componentHandler really does is creating a copy or instance of the component and then placing it in the world with a position (and rotation if any). Also, it's ok to clear all the instances at the beginning of update(), DynaMaker has already an internal optimization for generating the same geometry over and over that won't affect the app performance.

You won't see the subcomponents if you Save & Update because we have not generated their geometry yet.

D. Subcomponents geometry

  • Generate all subcomponents geometries from the componentHandler in generateGeometry() as:
generateGeometry() {
return this.componentHandler.generateAllGeometry()

You could do the same with the lightweight geometry (if any), intended for sketches and layouts.

generateLightweightGeometry() {
return this.componentHandler.generateAllLightweightGeometry()

But let's say you would want to generate only the lightweight geometry of the railing, then it'd be:

generateLightweightGeometry() {
const geometryGroup = new SKYCAD.GeometryGroup()
// geometryGroup.addGeometry(this.componentHandler.generateLightweightGeometry(STEP.Component))
return geometryGroup
  • Remember to call update() in the constructor so the subcomponents are generated correctly when loading the Assembly component.
constructor() {
super() = {

  • Save & Update to see the fully functional staircase!

Since we have not gone through the configurator (PARAMETERS) in this tutorial, you could try as a challenge to add Railing height as the fourth parameter of the configurator of the Assembly and try to connect it with the property that we created in the component Railing.

Congratulations! You have created your first assembly. Having it in an app would look like this:

Now that you know how to create assemblies, it's time to autogenerate drawings of this staircase at the click of a button in the next tutorial My First Drawing.