Online generator of Gridfinity components such as divider bins of any size with arbitrary internal compartments, light bins and base-plates. Generates STL files.
This is a short description of the design of Gridfinity Creator. It doesn’t follow any specific format or method, it’s just a free-format overview of the interesting bits
The application is written using Flask, which is a web-application framework for Python. It lets you map URLs to functions, so for example:
# Handle POST and GET requests for "/"
@app.route('/', methods=['GET', 'POST'])
def index():
return "<html><head><title>Title</title></head><body>Hello Flask!</body>"
This means any GET or POST request for the root (so just plain “www.yoursite.com”) will call this function and return the result to the user’s browser.
Flask uses the Jinja template engine, which I have used in the past and which is pretty cool too.
Bootstrap is a web frontend toolkit. It saves you from all the nitty-gritty details that go into making a site that works across browsers, OS’s, screen-sizes, resolutions, dark/light modes etc. For me, the main benefit is that there are some really cool Bootstrap themes available from bootswatch. For Gridfinity Creator I chose the Flatly theme.
WTForms is a form validation and rendering library for Python. It lets you define a form in code, which you can then render as HTML. When the form gets submitted (via a POST request) the result in Python is a form object you can query to get at the values filled in by the user.
The heavy lifting of the STL generation is done using CadQuery. I had been looking for a Python-based alternative to OpenSCAD, and this seemed to be the main contender. After using it in this project I have to say … ehm … wow. I get the idea, and I got it working in the end, but it took a LOT of reading and re-reading the documentation and even then I often found myself resorting to trial and error until I had something that looked right. I’ll probably use it again, since it seems to be pretty much the only game in town (not surprising, given how much work such a project takes), and it does work, but there’s definitely a steep learning curve. Much of this has to do with how you tell the system which edge or face you mean. In a 3D CAD package you simply point at it and click, but in code you can’t do this. How to select exactly the right edge to chamfer, and nothing else, was sometimes a vexing problem.
The entire application runs in a miniconda docker container that has cadquery installed via conda-forge. I used this guide to set this up.
The main design feature that is anything special is the way it handles object generators. On startup, the application scans the folder assigned to contain the generators. Each generator is contained in a subdirectory, and must contain a main.py. If this is the case, I use some importlib shenanigans (which I could never have come up with myself. StackOverflow FTW!) to load the generator as a module. Each generator must implements 3 functions: get_form, handles and process, which have the following purpose:
The upshot of all this is that adding a generator for a new object type is very easy. All that I need to do is create a new subdir in the generators location and make sure there is a main.py implementing the 3 functions above and an empty __init__.py present. The application will automatically pick up the new generator and everything will just work.