I’ve been developing a model for Maker World, using OpenSCAD and BOSL2 libraries, and while it works on smaller versions of the model, it times out when the model gets larger.
Is there a way to figure out what all can be done to optimize a model so that it completes within what appears to be the 10 second timeout limit on Parametric Model Maker?
Here is the specific model in question:
If you generate that model with default parameters, it will work, however if you instead change the parameters as follows:
Then the model will timeout on the web generator and never fully complete. With these inputs it should generate 4 plates worth of print assets, and when generating them locally on an M2 Macbook Air with OpenSCAD 2025.10.27 it is rendered in about 16 seconds. If I run the default parameters, then the render completes locally in about 9.7 seconds.
Nice catch! You are absolutely right, those calls aren’t allowed in the model maker. However, I also made a mistake when creating the gist, since those calls aren’t found on the actual code uploaded for the model in question. I had added those lines for my local testing so that I could see how long it would take to render multiple plates when just using OpenSCAD locally, and then I forgot to remove them when uploading the code to the gist for sharing. I have now fixed the gist, so those lines aren’t listed, but unfortunately that’s not the root cause of the problem.
I’m leaning towards a solution where I just upload 3 separate .scad files that each do about 1/3 of the objects, and thus should render in about 1/3 the amount of time. That is probably the fastest way to solve this. Or maybe there is some way to cache and reuse the same objects that I’m generating multiple times in different locations, so that it doesn’t take longer just to have multiple copies of the same object?
Interesting. What version of OpenSCAD are you running locally? I’m running OpenSCAD version 2025.10.27 (git aa785fe4a) and this is the output I get when just doing plate 1:
Loaded design '/Users/justinwagner/projects/open-scad-projects/frame_led_channel_parts.scad'.
Compiling design (CSG Tree generation)...
ECHO: "width_after_margin", 587
ECHO: "height_after_margin", 889
ECHO: "width_ch_length", 195.667
ECHO: "height_ch_length", 177.8
ECHO: "total_width_pieces", 6
ECHO: "total_height_pieces", 10
ECHO: "total_channels", 16
Compiling design (CSG Products generation)...
Geometries in cache: 11
Geometry cache size in bytes: 22664
CGAL Polyhedrons in cache: 0
CGAL cache size in bytes: 0
Compiling design (CSG Products normalization)...
Normalized tree has 192 elements!
Compile and preview finished.
Total rendering time: 0:00:05.209
And this is the version (git commit) of BOSL2 I’m usually locally:
Its slow not because the geometry is complex, but because BOSL2 features are expensive.
Use BOSL only where it actually adds value and go bare metal OpenSCAD elsewhere.
Avoid global fn, it massively hurts performance on small parts.
Instead, assign fn per part and derive it from a target resolution.
If using difference with more than two operands, wrap the union in render to reduce CSG overhead.
Whoa, nice tips @Professional3D ! I’m going to work through them one by one to fully comprehend and determine just how much speedup each ends up getting on this problem.
Tip 1) Don’t use global $fn, but rather only use it where it’s required. Sub-tip: derive it from a resolution.
It’s not clear to my why deriving this from a resolution would improve performance, but perhaps it’s just to have the number expressed in a way such that lower numbers create smoother circles? @Professional3D can you elaborate on this sub tip a bit more, I’d like to understand the reasoning here better.
I went ahead and did some performance benchmarking to see just how much benefit this particular problem would get from this tip relating to global use of $fn, and I did see some speedup. However, the speedup was all less than 1%, so this optimization alone certainly won’t be the sole fix to this problem. For each iteration of the code changes, I ran 5x previews, and 5x renders and took their average time. I captured all data here: OpenSCAD Benchmarking - Google Sheets
In my approach, resolution represents the physical length of each polygon segment, analogous to the XY resolution of a 3D printer. Why drive a crazy $fn if the user cannot see it and the printer cannot print it?
A global fn forces the same high segment count onto every circle, cylinder sphere, linear_extrude, rotate_extrude and offset, regardless of size.
circle(d=1, $fn=200) costs essentially the same as circle(d=2000, $fn=200), even though the small one gains nothing visually.
Deriving $fn from a target resolution keeps segment length roughly constant, so small features use few segments and large ones only get more where needed.
That cuts polygon count early, before CSG evaluation, which is where OpenSCAD actually gets slow.
Nothing becomes magically smoother, you are just expressing smoothness in physical units instead of an arbitrary global number.