You are browsing as a guest. Sign up (or log in) to start making projects!

simplyrohan

@simplyrohan

Joined June 3rd, 2026

  • 18Devlogs
  • 4Projects
  • 0Ships
  • 0Votes
trying to make cool shit
Open comments for this post

8h 21m 35s logged

Bidirectional Serialization

I’ve been building up to this feature for a while but I finally got lossless and bidirectional conversion between the AST and UI representations. This means you can design something, pull up just the Python file on another device, and continue working seamlessly. This also means you can edit the code in real-time and see it immediately reflect in the UI and vice versa.

0
0
9
Open comments for this post

8h 4m 15s logged

Fillet feature and reparsable AST

Completely forgot to log for a while but got a lot done. I wanted to add the fillet feature and in order to get there had to be able to select edges of the model.

This was mostly just duplicating the same logic that I used for face selection. I basically just export the edge as it’s own poly-line in the .GLB file. Adding the fillet feature was pretty easy after this since the framework I made before makes it pretty simple.

Then I added back the script view on the left to show a live preview of the code. Each feature exports python AST, which depending on the context can be run on Pyodide or be ran through a quick transformation to export.

I’m currently working on making the script editable. Each feature and expression now has a fromAST method which gives an instance of that feature/expression based on the code. This gives a bi-directional and lossless conversion between the UI representation and code.

0
0
20
Open comments for this post

3h 42m 35s logged

More consistent dependency tracking and more!

I generally cleaned up a lot of the jank from my rush to get an MVP working. Big thing is I actually have a somewhat working “timeline” now so each feature saves its output and it doesn’t get overwritten by the next one. Also added a new feature called “Script” which is sort of a back-up feature which allows you to inject arbitrary build123d code into the project and build off of it. This allowed me to remove the code editor along with the weird code to deal with manual code generation that wasn’t a feature.

Overall, much less buggy experience and stuff working!

1
0
28
Open comments for this post

7h 13m 26s logged

Working extrude!

It works! I expanded a lot on the idea I had of Primitives and chunked the entire code-generation architecture into “Tools”, “Expressions”, “Primitives”, and “Bindings”. These all work with py-ast to generate an AST for Python and the AST get analyzed for dependencies (eg. the model its operating on, the face its extruding) and the deps are looked up in a “symbol table” which Pyodide then injects into the global namespace.

All that to say, I can write features and have them operate on the model without rerunning the whole script and without duplicating a bunch of code.

Here is an example of me selecting a face on the auto-generated key cap and extruding it 10mm. Since we can’t sketch yet, I need to auto-generate a model to be able to get faces in the scene.

0
0
26
Open comments for this post

6h 30m 39s logged

RPC with worker

I started using Comlink to implement RPC with the worker. The idea was to be able to interact with PyProxies from the main thread through Comlink, but unfortunately since PyProxies are already proxies it makes the whole system incredibly weird. Instead, I started using a “registry” for PyProxies and referenced them with a string-type key in the main thread.

This all needed a lot of refactoring and I also improved the types across the project. No new features have been added but I should be able to actually implement working features/tools now.

P.S: Model regen is taking 200sec+ on my Mac which is very concerning, I need to look into it.

0
0
15
Open comments for this post

5h 5m 11s logged

Feature Menu

I expanded on the feature templates, honestly went through 3 different iterations before settling on this one. This new one introduces dynamic fields, meaning sections can be shown or hidden based on the values of other fields.

I also wrote a nicer interface for the menu, and got the a lot of different data-type inputs working. The nice thing about my custom schema-format for the fields is primitive inputs like numbers and check boxes are just as seamless as custom ones like face selectors.

The next obvious step is making the feature actually work, which will require a small bit of refactoring. It would be really inefficient to recompute the entire script each time a feature is modified (especially if I want live updates while editing the feature) so I’d like to use Pyodide’s ability to interact with Python objects directly. Unfortunatly, the object responsible for that (PyProxy) is not serializable and can’t be shared between the worker and UI.

The fix is setting up an RPC system and having all the features/tools live on the worker and the UI just uses comlink to call them.

0
0
14
Open comments for this post

4h 36m 21s logged

Feature Templates

I want to start getting sketching and other features working and created a reusable object oriented way to make them.
This forced me to learn a lot about TypeScript and I’m not even sure if I understand it now. But the end result is a Tool
class that has a Zod schema defining the parameter types for the tool’s
callback function. The function is automatically typed based on the
schema, as well as a defaults object. This was crazy
complicated because I had to juggle generic types, static vs instance
properties, and a bunch of other weird typing stuff.
There’s not much to show here but now when I click a feature a pop-up
shows the parameter names and types. Next I’ll write a UI “generator”
which has inputs for the parameter, even custom types like faces/planes.

0
0
28
Open comments for this post

2h 43m 19s logged

Face Selection

I was going to start working on sketching and other features but realized I needed to be able to select faces first. Three.js does have a Raycaster to select objects in the scene but it returns the whole object or triangles since it has no knowledge of the B-REP model (which stores the actual faces we want rather than triangle approximations ) after exporting it.

The solution was replacing build123d’s builtin export for a more manual process. I used the trimesh library to manually add each face of the model as it’s own mesh and exporting them all together as a scene. Three.js load’s the whole scene as a Group which is practically identical to a normal mesh in code. Now when the Raycaster returns a Mesh, it’s actually a face.

0
0
17
Open comments for this post

2h 59m 27s logged

GLB Optimizations and Improved Toolbar

I got the regenerate+re-render times down to about 800ms. The biggest part was actually just letting the browser’s JIT compile the hot parts so that subsequent regens would run way faster. It only takes 1 eval to get there, although that one eval is about 15 seconds. After that its super fast.
Another thing I did was switch to the GLB file format for transfering mesh data between build123d and three.js. GLB is very compact and encodes+decodes super fast. This took the encode + parse time from 3 seconds to about 100ms. I’d really like to be able to cache the “JIT”ed WASM between page loads and apparently the browser should do this already but it’s clearly not.

I also worked on the toolbar and used Bits UI to get a really nice search function with the features. I want to have a nice reusable interface for defining features with an automatic UI builder which would also make an equivalent to OnShape’s FeatureScripts super easy to implement (literally just a build123d generator with some UI bindings).

0
0
8
Open comments for this post

7h 15m 21s logged

The Idea

OpenVDE (need a better name) is on the surface a standard CAD software to design parts and assemblies.

I was frustrated with existing solutions like OnShape because it’s completely cloud-based (you will own nothing and be happy), and only runs in the browser which often lags a lot with WebGL and both of these mean offline use is impossible. However, these together do give the convenience of seamless collaboration.

On the other hand, apps like Fusion360 (and I’m assuming SolidWorks although I’ve never used it) do run locally but run like garbage because they’re from the 20th century (I’m not even kidding) and will crash unless you make a sacrifice to Andrew Anagnost himself. As a side effect of running locally, the collaboration features are lacking and don’t work well with modern workflows.

OpenVDE

My solution is CodeCAD, which is an approach to designing parts using code to call a CAD kernel in order to generate parts. OpenVDE is a generator for build123d Python scripts. You use it just like any other CAD software but it saves to a Git repository (or whatever you want to use) which allows for advanced version control and collaboration (eg. live editing of the same file). Storing designs as text also unlocks true parametric design and can be used to also write generators for parts using the logic flows programming languages provide.

I want this app to be an cross-platform and not look like crap, so I decided to go with a Tauri app with a Svelte front-end. A big feature of OpenVDE is the hybrid RPC CAD kernel, which is just jargon for you can run the heavy CAD operations natively, in WASM, in a cloud server, or on your own self-hosted server. This works because at it’s core OpenVDE just generates Python code and it can either be run through Pyodide in WASM, Py03 for native via Rust, or by calling a server.

Progress

I setup the project with some basic styles, Three.js, and Pyodide. Huge thanks to this project which provides the WASM compiled wheels for build123d (although I’m pretty sure the project is vibe coded). After getting that all setup plus IndexedDB caching of the packages and an async Web Worker to free the main thread, I got a bare-minimum example of a build123d sandbox in the browser.

I’ll try optimizing it, but the WASM version is running extremely slowly right now (15sec+ to generate this simple part).

0
0
14
Open comments for this post

5h 41m 3s logged

Custom cable ducts and skirts

I scrapped the OpenSCAD cable duct idea mainly because it couldn’t export to STEP (totally not because I didn’t want to learn it for 10 hours). Instead, I just redesigned them from scratch in OnShape and made sure to use its configuration features so I can generate different lengths and bends. The hardest part was figuring out how to mount them to the DIN rails in a customizable way. I realized that it was dependent on the spacing of the rails, and I somehow made mine a perfect multiple of 35mm which is exactly what DIN rails use. So I have a grid of holes space 17.5mm (35/2) apart which lets me screw in DIN clips anywhere along the duct. I’ll publish these at some point because they’re pretty useful. I do want to make them configurable outside of OnShape though, so I’ll port them to build123d soon™. I also printed a small version of them to test the snap fit for the cover (it’s perfect).

After that, I started getting the whole layout setup for the electronics. I then moved on to finishing up the skirts and adding mounts for the power plug, switch, fans, and motor drivers. This was surprisingly hard since I had to make cuts across pieces of the skirt. The under-bed electronics design is mostly done now with the exception of the screen (I need to make a case/mount for it on the front of the machine).

While it’s not in CAD because STEP files aren’t provided, there will be a handful of WAGO connectors to split power among components.

0
0
22
Open comments for this post

3h 51m 30s logged

Making a Voron rip-off pretty much

I started getting the under-bed mounts setup and went down a small rabbit-hole. Turns out all Voron models use “cable ducts”/“wiring ducts”. These are plastic or PVC tubes that have a comb on the sides and are used to route wires. I really liked these for managing cabling. I found a great model some one made for Vorons which I can adapt for my layout. Unfortunatly these mount onto a sheet Vorons have below the bed which my CNC does not. Instead I’m trying to make a version that mounts directly onto the DIN rails. I’m also trying to make it parametric in OpenSCAD but haven’t made much progress.

Aside from that, I found some cheap DIN rails and started assembling things in CAD. There are a ton of models online of DIN rail mounts for different components which is super useful. My original layout didn’t account for how spaced out the rails are and also placed the power port in an inconvenient spot which I’ve reorganized but the wiring is the same.

Researching Voron machines so much did kinda make me want to copy another aspect I really liked. They use 3D printed “skirts” to cover the under-bed electronics which both makes the machine look cleaner and provides a good mounting spot for components and plugs. After looking at a couple designs, I realized I had no idea how to CAD them and went with a basic hex mesh. I also added some plastic feet (will be 100% infill) to provide clearance for the PSU.

0
0
4
Open comments for this post

1h 29m logged

More Electrical Nonsense and Bed

I spent a bit too long worrying about how this machine will look (aesthetically) and decided it would mainly look better, but also use less wire and be easier to assemble, if I mounted all the electronics below the bed.

I was also thinking a lot how my bed should work. While it’s not the most common option, a lot of aluminum cutting mills do use an MDF spoil board, which lets me also cut wood and polycarbonate in addition to metal. Only issue is it makes mounting/clamping the stock harder. I have a few options (tape, toe clamps, T nuts) but the best option would be embedding T slots into the MDF. Honestly though, I should be able to add that later on after I build the machine so I won’t worry about it right now. Mainly, my new idea moves the mounting structure to leave room for the electronics below and also fixes an issue with the Z range I had on MK1.

For the electronics, I spent a lot of time looking at Voron machines (specifically the Trident R2 and the Zero). I spent some time making an new fully detailed wiring diagram which is also how the parts will be arranged physically. Green lines are DIN rails which everything is mounted to. For the cabling ducts, I’ll be using some 3D printed ones used on Voron mods. Fans, ports, and switches will be mounted on 3D printed mesh plates just like a Voron.

0
0
5
Open comments for this post

4h 35m 19s logged

Wiring and Klipper Setup

Now that I have Klipper setup with the screen, I need to connect it to my motherboard. This was as simple as compiling the Klipper firmware for the STM32 and using the correct configuration for the board. This was my first time using Klipper, and I was concerned I would need to reflash the firmware every time I made a configuration change. Luckily, Klipper abstracts that away to the RPi, meaning all definitions like GPIO pins and speeds can be changed easily. After flashing the firmware, I had to make a few modifications to the config. First, my Z and Y axes are swapped to take advantage of the two Z ports on my board. I also needed to set my mm/rev for each motor and set the speeds. Initially, my speeds were way to fast and the motors started overheating like crazy.

When I tried moving the axes, I ran into an issue. Klipper doesn’t let me move axes until the “printer” is homed which is an issue since I don’t have any way to home the axes. Instead, I enabled force movement, and had to manually send a command to zero the machine. In the future, I will make this a macro and maybe even a button on the screen.

I want to upgrade this machine to use NEMA23s which comes with a problem. I’ve been reusing a BTT SKR Mini E3 V2 which uses TMC2209 drivers to control NEMA17s. Unfortunately, the high power (important to note NEMA17/23 is just the mounting size, but usually is more powerful) NEMA23s I want to use will draw too much current. I’ll instead switch to a custom control system. I’ll use TB6600 drivers (subject to change) with an RP2040 XIAO which is connected via UART to the RPi running Klipper. I also want to have automatic spindle control which will use another RP2040, but I’ll talk more about that in another devlog.

I went over a few iterations of how everything is organized but this is what I settled for. Things in a white box are together in a container physically.

0
0
4
Open comments for this post

2h 15m logged

Finished Z Axis

Finished up the Z axis fixes and ended up switching back to 4040 extrusions. To bring the weight closer, the main difference is that I removed the X carriage. I also tucked the lead screw in between the linear rails which also saves space. Hopefully this will all result in a much more sturdy Z axis.

I’m considering adding some sort of material inside the clamp to grip the router better but except for grip tape, all options I can think of would add slop and make the router less rigid.

I also forgot to add images of this previously, but I have new models for the ballscrew mounts.

2
0
8
Open comments for this post

2h 40m 31s logged

Klipper Setup w/ KlipperScreen

I reflashed my RPi Zero 2 W with a stock Debian install and started installing Klipper-for-CNC with Kiauh. That was simple enough but I also wanted to get KlipperScreen working with a 3.5” capacitive touchscreen I had lying around.

KlipperScreen outputs video to the Linux framebuffer with X11 but without HDMI this wasn’t visible. I’m using an ST7796 display over SPI. After connecting the screen to GPIO, I thought an easy to use driver would already exist for this display. There was this one which I tried setting up. Unfortunately this a) didn’t support the RPi Zero 2 W, but that was easy to fix and b) relied on the old VideoCore framework which Raspberry Pi OS doesn’t ship with anymore.
After that, I went digging for another solution. I found this repo and this forum post which showed that the kernel already had support for generic displays like these, so I just had to add the init sequence of bytes for my display. After hours of tweaking with boot settings I finally got it working!
Now I needed touch to work, which used an FT6336U driver. At the bottom of some forum post I was able to find a repo which had drivers for the OrangePi for my exact screen. This probably would’ve been helpful getting the screen working but I anyways like my solution better. I compiled the driver in the repo and remade the DTS file for an RPi Zero 2 W rather than an Orange Pi. Surprisingly, this just worked! The touch coordinate orientation was correct, and even gestures like scrolling worked perfectly!

Now I have Klipper fully setup with my display and need to connect it to my motherboard.

4
0
78
Open comments for this post

2h 11m 1s logged

I updated the Z axis to use 2020 extrusions (smaller and lighter) and 2 linear rails to support the Z carriage.

The previous version of the X carriage got ripped up because there was too much strain on it over time. This updated version distributes the weight on two rails and brings the mass (heavy router) closer (smaller cantilever).

0
0
5

Followers

Loading…