Skip to main content

My First Model

In this tutorial, you will learn how to create a first simple model with the Solid API. First, we will start with a simple box. Then, to get an idea about what's possible with the Solid API, we're going to make the model more and more complex.

Let's follow these steps:

  1. Create a simple box
  2. Modify model by adding more features
  3. Make it a real example
  4. Make the model configurable

1. Create a simple box#

First, you must create a new code environment where you will make your first example.

  • Create a copy of templateCreator.ts in the solid folder and name it, for example, cube.ts
  • You will now have an empty create method where you can put code into it.
import { ApiNoHistory, solid } from '@buerli.io/headless'
import * as THREE from 'three'
import { Param, Create } from '../../store'
export const paramsMap: Param[] = [].sort((a, b) => a.index - b.index)
export const create: Create = async (apiType, params) => {
const api = apiType as ApiNoHistory
// Start creating your model here...
// ...
// ...
return 0 // solid id
}
export const getBufferGeom = async (solidIds: number[], api: ApiNoHistory) => {
if (!api) return
const meshes: THREE.Mesh[] = []
for await (const solidId of solidIds) {
const geom = await api.createBufferGeometry(solidId)
const mesh = new THREE.Mesh(
geom,
new THREE.MeshStandardMaterial({
transparent: true,
opacity: 1,
color: new THREE.Color('rgb(255, 120, 255)'),
}),
)
meshes.push(mesh)
}
return meshes
}
export const cad = new solid()
export default { create, getBufferGeom, paramsMap, cad }
  • Create a simple box with length = 32, width = 16 and height = 9.6
  • Return the id of the box
const box = api.box(16, 9.6, 32)
return box
  • As result you will see a simple colored box

💡 Tip: Length, width and height of the box relates to x-, y- and z-axis in global coordinate system.


drawing

Simple colored box


2. Modify model by adding more features#

There are many features we can use to modify this simple cube. First, let's make the cube hollow at the bottom with a defined thickness. Then, follow the next steps to get the result.

  • First of all, create some variables for width, height, length, and thickness
  • Create another box that is a bit smaller than the first one
  • Move the new box to the correct position
  • Create a boolean operation, in that case, a subtraction, to subtract the second box from the first one
const width = 16
const height = 9.6
const length = 32
const thickness = 1.6
const box = api.box(width, height, length)
const subBox = api.box(width - 2 * thickness, height - thickness, length - 2 * thickness)
api.moveTo(subBox, [0, -thickness, 0])
api.subtract(box, false, subBox)
return [await box]
  • As result you will see a red box which is hollow at the bottom

drawing

Simple colored box which is hollow


3. Make it a real example#

In the previous chapter, we learned that we could use features to modify our model. We used moveTo() and subtract(), but there are many more to explore. Visit Solid API for a list of all methods we can use.

At the moment, it's only a hollow box; let's add some more features to make it a real example. Add the following code to your template.

const width = 16
const height = 9.6
const length = 16
const thickness = 1.6
const dotHeight = 1.7
const dotRadius = 2.4
const dotGap = 4
const tubeHeight = 8
const tubeRadius = 3.25
// body
const box = api.box(width, height, length)
const subBox = api.box(width - 2 * thickness, height - thickness, length - 2 * thickness)
api.moveTo(subBox, [0, -thickness, 0])
api.subtract(box, false, subBox)
// dots
const dot = api.cylinder(dotHeight, 2 * dotRadius)
api.rotateTo(dot, [Math.PI / 2, 0, 0])
api.moveTo(dot, [width / 2 - dotGap - 2 * dotGap, (height + dotHeight) / 2, length / 2 - dotGap - 2 * dotGap])
api.union(box, true, dot)
api.moveTo(dot, [width / 2 - dotGap, (height + dotHeight) / 2, length / 2 - dotGap])
api.union(box, true, dot)
api.moveTo(dot, [width / 2 - dotGap, (height + dotHeight) / 2, length / 2 - dotGap - 2 * dotGap])
api.union(box, true, dot)
api.moveTo(dot, [width / 2 - dotGap - 2 * dotGap, (height + dotHeight) / 2, length / 2 - dotGap])
api.union(box, true, dot)
api.clearSolid(dot)
// tubes
const tube = api.cylinder(tubeHeight, 2 * tubeRadius)
const subCyl = api.cylinder(tubeHeight, 2 * (tubeRadius - thickness))
api.subtract(tube, false, subCyl)
api.rotateTo(tube, [Math.PI / 2, 0, 0])
api.moveTo(tube, [0, -thickness / 2, 0])
api.union(box, true, tube)
api.clearSolid(tube)

Do you have any idea what the code will create? Then, copy the code to the template and see what you get on the screen!


4. Make the model configurable#

If the result of the last chapter looks like a lego brick, well done! You've created your first real example by code. The next step will be to make the model configurable. Currently, we're only able to create a brick of the size 2 x 2. So what do we need to add to the code to make various bricks? Follow the next steps to create a configurable lego brick:

  • Add rows and columns as new variables to the code. With these variables, we will control the size of the brick.
  • Refactor existing variables. Make them depend on each other.
// variables
const rows = 2
const columns = 4
const unitLength = 8
const width = rows * unitLength
const length = columns * unitLength
const thickness = 1.6
const height = unitLength + thickness
const dotHeight = 1.7
const dotRadius = 2.4
const dotGap = dotRadius + thickness
const tubeHeight = height - thickness
const tubeRadius = (2 * dotGap * Math.sqrt(2) - 2 * dotRadius) / 2

Now, the size of the brick (width, length) depends on the number of rows and columns. The code section where the body is built, is fine like it is. No changes are needed. We need to update now the dots and tubes.

  • Create a loop to iterate over the number of columns
  • Within the loop create another loop to iterate over the number of rows
  • Each dot will be moved a specific distance and united with the box
// dots
const dot = api.cylinder(dotHeight, 2 * dotRadius)
api.rotateTo(dot, [Math.PI / 2, 0, 0])
for (let i = 0; i < columns; i++) {
for (let j = 0; j < rows; j++) {
api.moveTo(dot, [
width / 2 - dotGap - j * (2 * dotGap),
(height + dotHeight) / 2,
length / 2 - dotGap - i * (2 * dotGap),
])
api.union(box, true, dot)
}
}
api.clearSolid(dot)
  • Do the same with the tubes
// tubes
if (rows > 1 && columns > 1) {
const tube = api.cylinder(tubeHeight, 2 * tubeRadius)
const subCyl = api.cylinder(tubeHeight, 2 * (tubeRadius - thickness))
api.subtract(tube, false, subCyl)
api.rotateTo(tube, [Math.PI / 2, 0, 0])
api.moveTo(tube, [0, -thickness / 2, 0])
for (let i = 0; i < columns - 1; i++) {
for (let j = 0; j < rows - 1; j++) {
api.moveTo(tube, [
width / 2 - 2 * dotGap - j * (2 * dotGap),
-thickness / 2,
length / 2 - 2 * dotGap - i * (2 * dotGap),
])
api.union(box, true, tube)
}
}
api.clearSolid(tube)
}

That's all! You can now change row and column to get an individual lego brick. Of course, we could extend the brick even more. But this will be fine to get the idea of how code could help us make models individually.

drawing

Lego brick from top view

drawing

Lego brick from bottom view

💡 Tip: You can export the model as stp file (not available in the free version!) or in our native file format ofb.