Skip to main content

Getting Started


This guide will show you how to build a simple application using the Buerli headless API with Docker. Check out the Setup Environment section for deeper insights into setting up the ClassCAD server (with and without Docker) as well as the client.


Scaffold A New Project#

First, scaffold a new Vite project. Vite is a common build tool that aims to provide a faster and leaner development experience for modern web projects. You can use any other build tool you prefer, but Vite is recommended for its speed and simplicity.

npm create vite
# Choose a projects name
# Pick the "React" template
# Pick either Javascript or Typescript
cd projectName
npm install
npm run dev

By now you will have the following folder structure (you can remove files you do not need):


After you execute npm run dev Vite will show you a URL where you can preview your application. Open the URL in your browser to see the default Vite application.

VITE v5.1.6 ready in 93 ms
➜ Local: http://localhost:5173/
➜ Network: use --host to expose
➜ press h + enter to show help

Set up the server#

We will now start the ClassCAD server. The server is a Node.js application that runs the ClassCAD business logic. It is responsible for handling the ClassCAD API requests and for serving the ClassCAD client application. Refer to docs/setup-environment/server for more information on how to set up the server.

Download a *.capp file#

Regardless of the host platform you use, you need the ClassCAD application package, the so-called class file (ccapp). This file contains the ClassCAD business logic. Without it you will not be able to start the ClassCAD server.

Visit, log in, and go to your profile. There you can download the ClassCAD application package.

Set up Docker#

Go to your project folder and create a new folder called docker in the root of your project. Place the downloaded *.capp file in this folder.

Create a new file called dockerfile in the /docker folder. This file contains the instructions to build a Docker image. The Docker image is a lightweight, standalone, executable package that contains the ClassCAD server.

FROM ubuntu:22.04
RUN apt update
# Install linux dependencies
RUN apt install -y libarchive-dev libgomp1 libglu1-mesa-dev ocl-icd-opencl-dev curl
# Language settings
# Install node and npm by using nvm
ENV NVM_DIR /usr/local/nvm
RUN mkdir $NVM_DIR
RUN curl -o- | bash
RUN echo "source $NVM_DIR/ && nvm install $NODE_VERSION && nvm alias default $NODE_VERSION && nvm use default" | bash
# Install ClassCAD
RUN mkdir -p /classcad
WORKDIR /classcad
RUN npm init -y
RUN arch=$(arch | sed s/aarch64/arm64/ | sed s/x86_64/x64/) && \
npm i "@classcad/linux-${arch}" && \
chmod +x "./node_modules/@classcad/linux-${arch}/ClassCADInstance"
# Copy the .ccapp downloaded from
# Replace <PATH-TO-CCAPP-FILE> with the path pointing to the downloaded .ccapp file.
COPY <PATH-TO-CCAPP-FILE>.ccapp modeling.ccapp
# Start the server
# In multi-user scenarios you can run multiple ClassCAD instances by setting the instances parameter
EXPOSE 9091/tcp
CMD npx classcad --ip --port 9091 --instances 2 --ccappfile modeling.ccapp
  • Please do not forget to replace PATH-TO-CCAPP-FILE with the path to your downloaded class file.
  • Please do not forget to bind the port when starting the docker container
  • @classcad/linux-arm64 does not support DXF/SVG export!

It would be a good idea to add a docker-compose.yml as well since it makes it easier to orchestrate the server.

version: "3.5"
context: ./
dockerfile: dockerfile
image: classcad/server
container_name: classcad-server
tty: true
stdin_open: true
- 9091:9091
restart: unless-stopped

Start the server#

First, make sure to link the right *.capp file in the dockerfile.

# Copy the .ccapp downloaded from
# Replace <PATH-TO-CCAPP-FILE> with the path pointing to the downloaded .ccapp file.
- COPY <PATH-TO-CCAPP-FILE>.ccapp modeling.ccapp
+ COPY FreeBaseModeling-0.0.8.ccapp modeling.ccapp

Now you can start the server. If your IDE has docker integration you can start the server simply by right-clicking docker-compose.yml and selecting "compose up".

You might want to make sure that the server is running. You can check the accepted status in your Docker dashboard. You should see something like this

SYSTEM initializing ...
SYSTEM Starting GC ...
GC is OK
SYSTEM Handling CAPP ...
Extract '/classcad/modeling.ccapp' to '/root/.classcad'
Extraction succeeded
WS accept ws:// -> ws
IO accept -> http
HTTP accept
HTTP accept
HTTP accept
SYSTEM ◼ ◼ ◼ Worker User Task
WORKER ◼ spawning a017ef4e-6095-4f50-a139-00e6387a38ed
/classcad/node_modules/@classcad/linux-arm64/ClassCADInstance socketclient --port 9707 --ccwss --binary --debug --id a017ef4e-6095-4f50-a139-00e6387a38ed
WORKER ◼ env {"LD_LIBRARY_PATH":"/classcad/node_modules/@classcad/linux-arm64:$LD_LIBRARY_PATH"}
WORKER ◼ spawning 0b209cea-3f63-48c7-9715-ea1e2d25f0df
WORKER ◼ env {"LD_LIBRARY_PATH":"/classcad/node_modules/@classcad/linux-arm64:$LD_LIBRARY_PATH"}
WORKER ◼ accepted
WORKER ◼ accepted

Visit in your browser to confirm the service is active. You will see a JSON response:

config: {
configurationData: '/classcad/node_modules/@classcad/linux-arm64/ClassCAD.ini',
protocol: 'http',
serverOptions: {},
ip: '',
privatePort: 9707,
publicPort: 9091,
binary: true,
multipart: true,

Write your first Buerli app#

First, install the necessary packages. We need threejs, react-three-fiber, the Buerli headless API and the Buerli React API.

# Client packages
npm install three @types/three @react-three/fiber @react-three/drei
# Buerli packages
npm install

Modify index.css

* {
box-sizing: border-box;
#root {
width: 100%;
height: 100%;
margin: 0;
padding: 0;

Modify App.jsx

import { Canvas } from '@react-three/fiber'
import { AccumulativeShadows, RandomizedLight, Center, OrbitControls } from '@react-three/drei'
import { solid } from ''
import { headless } from ''
const { cache } = headless(solid, 'ws://')
export default function App() {
return (
<Canvas shadows camera={{ position: [0, 0.5, 10], fov: 35 }}>
<color attach="background" args={['#f0f0f0']} />
<ambientLight intensity={0.5 * Math.PI} />
<directionalLight decay={0} position={[10, 15, 15]} castShadow />
<directionalLight decay={0} position={[-10, 15, -15]} />
<group position={[0,-1,0]}>
<Center top>
<Cutout dHole={55} scale={0.025} />
<AccumulativeShadows temporal frames={100} color="orange">
<RandomizedLight radius={1} position={[5, 5, 5]} />
<OrbitControls />
function Cutout({ lOuterBox = 90, lInnerBox = 70, dHole = 55, ...props }) {
const geo = cache(
async api => {
const box =, lOuterBox, lOuterBox)
const inner =, lInnerBox, lInnerBox)
api.subtract(box, false, inner)
const cyl = api.cylinder(2 * lOuterBox, dHole)
api.subtract(box, false, cyl)
return await api.createBufferGeometry(box)
['test', lOuterBox, lInnerBox, dHole],
return (
<mesh castShadow receiveShadow geometry={geo} {...props}>
<meshStandardMaterial color="orange" />

In case your Vite dev server isn't running, start it with npm run dev. Open the URL in your browser to see the application. You should see a box with cut outs.