Skip to main content

Troubleshooting

Are you stuck with some bug in your app and have no clue where to start? Don't panic, here we show some of the basic concepts that will help you find those bugs:

Here is a guide that you can use when having problems with your app:


Code Completion

Code completion, or IntelliSense, is a coding aid that helps you learn more about the code that you're using. Use the ctrl + space keys in the editor to bring up a small popup with function references. It will also show when you type on objects. So whenever you write a dot after an object, for example layout. (when having const layout = new SKYCAD.Layout()), you should see a list that helps you find relevant functions or properties regarding layouts. See video for reference:

Debugging

When something is failing after you Save & Update your component, you might get errors in the preview like:

Don't panic! Take the following steps when you get one of those bugs:

  1. Try to understand the error: height is not defined.
  2. No clue what that means? See at least if you identify where the problem comes from by opening the Console (F12), and click on the error (first link of the red message) to take you to the exact line the error comes from:
  3. Once you see the exact line of code where the bug is, you might realize that actually height is not defined anywhere in the function.
  4. Problem not solved? Then it looks like height might have a strange value that you are assigning previously. Use the debugger to go step by step in your code and see exactly what's happening.

These are the 4 steps you should keep in mind for debugging:

  • Press F12 while on the page to open the browser console.
  • Type debugger in the DynaMaker editor in the line you want to stop at.
  • Update (or refresh F5). When it stops at that line, you can hover over all the elements to get values.
  • If you want to go on with debugging:
    • F10 allows you to go to the next line.
    • F11 allows you to go into the function.
    • F8 allows you to go until the next debugger (if any) or finishing the debugging mode.
    • Esc opens the Console (if closed) which allows you to check the values of any variable you typed.

Also, you can check the Callstack on the right side (if the browser console is wide enough), which allows you to check which function is calling the function where you typed debugger, and all its previous functions as well.

Remember that you can only read the values of all the variables that are above the line you are stopped at. You can learn more about debugging with Chrome DevTools or jump into the tutorials (more specifically the 2nd one My First Component) to learn from an example in DynaMaker.

Common Mistakes

Although we cover the basics of DynaMaker in the tutorials, sometimes we could stuck because of some small mistakes made when programming. Don't worry! These are common to get specially if you are new into programming or TypeScript. Here we cover the golden rules and some beginner mistakes.

Golden rules

There are some rules that are good to follow when you get stuck in your app:

  1. Search your problem in the docs. Try to find your problem or more info about something specific with the right key words. The search function will try to come with the best-matching recommendations.

  2. If you are new into TypeScript or completely forgot your programming lectures, ask Google. We cover the very basics in here, but there's a lot of information on the Internet. Since TypeScript (2012) is based on JavaScript (1995), you can find your question by simply adding JavaScript at the end. You will be surprised how many people asked How can I remove a specific item from an array? Get inspiration from the community!

  3. Debug. When you have no clue what's happening in your code, take a look at the values of your variables step by step with the debugging tool. Check our guide on how to tackle DynaMaker errors.

  4. When the debugger can't help you any more (e.g. faces of my model disappear, strange errors in DynaMaker functions, etc), then ask us at support@dynamaker.com. If you can't find your problem in a FAQ from the developers, contact us for any type of question. If we see that many developers have the same question, we will eventually post it as a new FAQ to help other people like you. So don't be shy, we are here to help!

Beginner mistakes

For those that you have trouble understanding how TypeScript works, here we cover some of the most common mistakes that beginners usually encounter in DynaMaker regarding:

Naming Variables

Naming variables is not an easy task. However it is one of the most important things to account for when writing good and understandable code. If there's a parameter called width you might mix it with the property width, but if its name is widthParameter then it's much clearer what it is. It might seem a silly example, but it happens more often than you think, not only in beginners.

Names are case-sensitive in TypeScript, so make sure to be consistent with the naming. Some examples for:

  • functions:
    • getMaterial() meant to return a material (e.g. string)
    • generateProfileSketch() meant to create a sketch from scratch and return it.
    • hasColor() meant to return a boolean (true or false).
    • getColor() meant to return a color (e.g. as hexadecimal).
    • getDoorData() meant to return an object with different values.
    • updateDoor() meant to update all the subcomponents of a door
  • constants:
    • baseSketch in lower case (e.g. used in a model for extrusion) meant to assign a sketch that is retrieved from a function getBaseSketch() or generateBaseSketch()
    • DOOR_WIDTH in upper case to assign a constant that always has the same value and typically can be store in the editor tab CONSTANTS.
    • width meant to define the width of a component
    • widthParameter meant to define the parameter linked to the property width for example
    • maxWidth meant to define the max value of widthParameter
  • interfaces:
    • Properties to define the type of objects with the first letter in upper case meant to store the properties types.

An example with the above e.g. located in GEOM3D:

interface ModelData {
width: number
depth: number
}

export function generateModel(modelData: ModelData) {
const { width, depth } = modelData
const DOOR_THICKNESS = 30

const model = new SKYCAD.ParametricModel()
const baseSketch = GEOM2D.generateBaseSketch(width, depth)
const refPlane = new SKYCAD.Plane(0, 0, 1, 0)
model.addExtrude(baseSketch, refPlane, DOOR_THICKNESS)

return model
}

For declaration of variables we use const when it is a constant that does't change in value, and let when it's meant to change. If you try to change the value of a const you will get an error right away (very useful!). So start having everything as const and switch to let when you need to. Try to avoid using var for variables since it causes unwanted bugs due to JavaScript, so use let instead.

Read more about declaration of variables here. Although you can name things how you want in the language you want (as long as you are consistent), it's good to follow a standard naming convention with English as default language. Doing the tutorials and reading the code in the docs in general is a good start to practice naming variables.

Functions

A function in TypeScript is defined as follow:

function getMaterial(width: number) {
if (width === 100){
return 'steel'
} else {
return 'wood'
}
}

See that function has to be before the name of the function getMaterial. It might take some inputs (i.e. width) and it might optionally return an output (material as a string).

  • So how do I use it? Simply call it like:

    const material = getMaterial(width)

    See this function takes width as input, so width has to be defined wherever it's used. In this case the function getMaterial returns something, so you should assign it to something. Having the following does nothing:

    getMaterial(width) // it returns something, but it is not assigned to anything. So it won't do anything

    const material = getMaterial // a function without input or brackets means "nothing". material here will be a "function", something very strange to have.
  • In a similar way, if you don't return anything in a function, whatever you assign its value will be undefined. For example:

    function getMaterial(width: number) {
    let outputMaterial
    if (width === 100) {
    outputMaterial = 'steel'
    } else {
    outputMaterial = 'wood'
    }
    }

    const material = getMaterial(width) // material = undefined
  • The advantage of using TypeScript is that you can use types of variables to assist you and detect errors much more easily. If we said that getMaterial() takes an input (whatever name) has to be a number, the language will give you an error if you send something different (e.g. a string). For example:

     const reinforcedType = 'Carbon fiber'
    const material = getMaterial(reinforcedType) // this will be highlighed in red as error saying "this is not a number"

    If you don't define the type of the input, it's ok but you will eventually give you errors sooner or later because of that.

    function getMaterial(width) {
    if (width === 100) {
    return 'steel'
    } else {
    return 'wood'
    }
    }
    const reinforcedType = 'Carbon fiber'
    const material = getMaterial(reinforcedType) // this won't give you an error, and still return 'wood' because of the logic in the function.
    // And you might wonder later "why it gives wood if I have width 100?" - Well, you sent something that is not a number. So define types!

See that we haven't talked about components or apps. This type of function is totally independent and can be written anywhere. Remember: it takes an input and gives an output. However, you might have noticed that a component has functions within the class. These class functions are dependent on the component and its properties, so they are callable if you have a component. For example, in the component template there's generateGeometry() and uses directly the properties from the component through this.

   generateGeometry() {
const depth = this.properties.depth
const height = this.properties.height
const width = this.properties.width

const baseSketch = SKYCAD.generateRectangleSketch(0, 0, width, depth)

const model = new SKYCAD.ParametricModel()
const plane = new SKYCAD.Plane()

model.addExtrude(baseSketch, plane, height)

// material and color

const geometryGroup = new SKYCAD.GeometryGroup()
geometryGroup.addGeometry(model, { materials })

// layout with dimension

return geometryGroup
}

Now this function is callable from another class function if needed. For example, let's say we want to create a function named generateFrontProjection to have a projection from the geometry, that is going to be used in the drawing. So then you can call it like:

export class Component extends STUDIO.BaseComponent<Properties> {
constructor() {
super()

this.properties = {
width: 100,
depth: 100,
height: 100,
}
}

generateGeometry() {
// logic to create geometry
}

generateFrontProjection(){
const geometryGroup = this.generateGeometry()
const frontPlane = new SKYCAD.Plane(0, -1, 0, 0)
const projection = geometryGroup.generateProjection(frontPlane)
return projection
}
}

Alright! I create the function but how do I use it in the drawing? If you create a drawing template, there's a function there called generateDrawing:

export function generateDrawing(component: MYCOMPONENT) {
const layout = new SKYCAD.Layout()

const drawing = new SKYDRAWING.Drawing()
// rest of logic to add content to drawing (e.g. header)
return drawing
}

Assuming that you have already imported your component in the drawing (let's say it's called MyComponent), then you can see that, the intellisense will assist you with all the functions available in component. Then with code completion, you can write:

export function generateDrawing(component: MYCOMPONENT) {
const layout = new SKYCAD.Layout()

const drawing = new SKYDRAWING.Drawing()

const frontProjection = component.generateFrontProjection()
const visibleSketch = frontProjection.visible
drawing.addContent(visibleSketch, { anchor: 'center' })

// rest of logic to add content to drawing (e.g. header)
return drawing
}

Apart from the class functions (i.e. generateGeometry(), generateFrontProjection() and more default ones), you can use whatever is within the constructor with defines the identity of the component with properties. But could I add more things like this.name = 'Amazing Cube'? Of course, however, the components are prepared so that you only use properties and nothing else (for simplicity). Then you should have it as:

export interface Properties {
width: number
depth: number
height: number
name: string // don't forget to define the type to assist you
}

export class Component extends STUDIO.BaseComponent<Properties> {
constructor() {
super()

this.properties = {
width: 100,
depth: 100,
height: 100,
name: 'Amazing Cube'
}
}

generateGeometry() {
// logic to generate geometry
}
}

It is important not to lose track of (), where the inputs are, and {} where the logic of the function is. If you start adding complexity (e.g. more functions) within functions consider that the code might get messy and you might delete something and you don't know anymore where the functions start and end. If you feel that the code is getting complex, consider making sub-functions of independent logic and call those instead. It will be much easier not only for you but also for yourself in 2 months when you forgot what you did! For example the class function update() of a room as an assembly with multiple subcomponents (windows, doors, furniture, etc):

update() {
this.updateDoors()
this.updateWindows()
this.updateVentilation()
this.updateFurniture()
}

Libraries

Another common mistake is how to use the libraries and their functions correctly. In DynaMaker you can use a library to create "things" or call in-built functions. For example if you want to create a custom sketch you would use the object Sketch built in SKYCAD:

const sketch = new SKYCAD.Sketch()
sketch.moveTo(0, 0)
sketch.lineTo(50, 0)
// etc

However if you want to generate a circle, instead of creating an empty sketch and add 2 curves, you would use the function generateCircleSketch() built in SKYCAD:

const circleSketch = SKYCAD.generateCircleSketch(0, 0, 25)

See that generateCircleSketch() is a function that returns a sketch. Therefore there's nothing new to create. So the main difference, apart from the spelling (library functions always start with lower case, while new objects start with upper case), is that one creates an empty object (usually meant for modifications or adding other things to it) whereas the other generates (or checks) something based on some inputs.

The mistake comes from mixing these two concepts and ending up missing the word new or inputs in a function. These however are detected by the Intellisense and are less frequent.

Editor Tabs

What we see at the very right of the code editor are some tabs. E.g. COMPONENT, GEOM3D and GEOM2D can be found in the Component Editor. These are merely containers meant for placing functions and constants where they should be.

The Component, Drawing and UI Editors are built in such a way where you can use functions from tabs in other tabs within the same Editor. There's usually a main tab (COMPONENT in Component Editor, UI in UI Editor, etc) that should never be used in other editor tabs. Except for the Component Editor and all Presets, the rest of secondary tabs are not meant to be used between them. For example:

  • In COMPONENT you could generate a model from GEOM3D but should never be the other way around.
  • In GEOM3D you could generate a sketch from GEOM2D and viceversa (in case of a projection perhaps).
  • In GEOM3D you could generate an extrusion with a length given by CONSTANTS, but should never be the opposite.
  • In UI you could trigger some function from ACTIONS in a button, but should never be the other way around.

Similarly to the libraries functions written in GEOM3D can be called in COMPONENT like const model = GEOM3D.generateModel(inputA, inputB).

A common mistake is to think that a circle sketch can be generate in GEOM3D like GEOM3D.generateCircleSketch() because of mixing SKYCAD with GEOM3D.