Category Archives: Art

3D Design: Slices on Canvas (Parametric Canvas)


  • 2024/01/26: published
  • 2024/01/20: adding more examples and mounting tool/ruler
  • 2024/01/15: starting write-up


Since a while I was wondering how to create large(r) scale 3D prints like 1m / 1000mm or more, and I thought to use wood planks as slices and make “parametric wall” like sculptures. In order to get an idea of the procedure, I started with “parametric canvas” or Slices on Canvas.


I used OpenSCAD to put together a few examples with 200×150 in size, and settled for 40 slices, which are then scaled up for 400x300mm canvas, the actual size is 340x240mm giving on each side 30mm margin to the edge of the canvas.

3D Printing Slices

In order to test the concept, I used 3D printed slices printed with cold-white PLA+ in order to get a strong contrasts to the black canvas:

Each slice is 240mm wide, and 2.5mm thick and various height depending on the model.

After printing 40 slices finished, I mounted them on the canvas:

As shown on the photo, I used a mounting tool / rulers, also 3D printed, which helped me to keep the slices well aligned and spaced to each other – then glued each slice on the canvas.

40 slices with 240mm width and 2.5mm thickness takes about 20hrs to print (4 slices ~ 2hrs print time) and ~520g of filament like for the Sinus themed sculptures.

Raw slice bundles: Smooth Sinus Meadow, Quarter Drop, Drop each bundle apprx. 520g PLA+

With 2.5mm thickness x 40 and 340mm canvas width, it’s about ~25% or 1/4 of actual volume of the model, and the rest is empty space in between.

Sinus Mountain Range



Smooth Sinus Meadow

Various Examples


It’s relatively easy to create a Slices on Canvas (parametric canvas) but it takes its time to print and assemble – due the thin slices the sculpture changes its appearance drastically depending on viewing angle, and so is an eye catcher.

It certainly is a viable approach for larger scale sculptures, the saving in material is compensated with additional manual work like aligning and fastening the slices.


  • LabSlicer: used to slice the model into SVG slices (PrusaSlicer also supports this functionality)
  • Prynt3r: for printing the individual SVG slices directly

3D Design: 3D Lissajous


  • 2024/01/22: published without much reflection & conclusion as research is ongoing
  • 2023/12/02: adding more examples and refining details
  • 2023/10/22: start writeup


While studying continuous fiber 3D printing and its main nature is to find ways to lay fiber without interruption. In order to refresh my memory I revisited the Lissajous forms, which until recently only knew in their 2D form, the swirling strings or lines – and now extending it into 3D as well.

The main idea is to realize how a line, string or fiber can be used to fill non-planar and circumvent a 3D structure and how angular shifting in Lissajous context affects such form.

3D Lissajous

  • angle: 0 .. 2pi or 0 .. 360°
  • p, n, m: 0 .. 1000, the amount of loops
  • phi0, phi1, phi2: the angular offsets 0 … 2pi or 0 .. 360°
  • X = sin(angle*p+phi0)*r
  • Y = sin(angle*n+phi1)*r
  • Z = sin(angle*m+phi2)*r

I did a lot of experimenting – I could post hundreds of forms – but let me focus on one a bit closer, which got my attention:

It is a very interesting transition, 8/13/21 with phi0=0° gives almost a cube-like structure, and shifting the X loop to 90° we get a tetrahedron:

Spherical Lissajous

While playing with 3D Lissajous, I thought to adapt the cyclic nature, but apply it to a circle laying in the XY plane and then rotate in X axis, and Y axis as well, and optionally cyclic translation as well:

  • d: diameter
  • angle: 0 .. 2pi or 0 .. 360°
  • p: amount of loops as in X=sin(angle*p)*d/2, Y=cos(angle*p)*d/2
  • q: amount of X rotations: rotateX(angle*q)
  • r: amount of Y rotations: rotateY(angle*r)
Spherical Lissajous 12.23 with spreading struts

The model was printed with MSLA white resin at XYZ 50um resolution with 120mm diameter, with a few support structures near the bottom:

Spherical Lissajous with Translations

Using the Spherical Lissajous and extend it slightly:

  • [A,B,C]loop/offset/radius: translate([ sin(angle*AL+AO)*AR], sin(angle*BL+BO)*BR], sin(angle*CL+CO)*CR ])

which spreads the ribbons away from the spherical surface origins.

Spherical Lissajous 5.11 AL=3, AR=5

Spherical Lissajous 5.11 AL=3, AR=5

It’s symmetric X- and Z-wise, in Y-axis it isn’t.

The model was printed with MSLA white resin at XY 35um / Z 50um, at 60mm in Z height, ~94mm width; with a some support structures:

Spherical Lissajous 11.15 AL=2, AR=5

A more elaborate form is 11.15 AL=2, AR=5:

Spherical Lissajous 11.15 AL=2, AR=5 with spreading struts

So, there is no X-, Y- or Z-wise symmetry.

The model was printed with MSLA white resin at XY 35um / Z 50um, at 60mm in Z height, ~94mm width; with a some support structures:

and printing it larger with ~200mm width with manually positioned support:

That’s it (for now).


3D Printing: MSLA printing Triply Periodic Minimal Surfaces (TPMS) – Gallery


  • 2023/07/25: adding 20mm/40mm TPMS photos
  • 2023/03/12: starting write-up, and published

20mm cubes of several Triply Periodic Minimal Surfaces (TPMS) as explored at Generative Parametric Infill Geometries printed with MSLA (Anycubic Photon Mono 4K) at 35 μm XY, 50 μm Z:

Most of the cubes were printed without support, the cylindrical and spherical projections required supports.


20mm and 40mm cubes of TPMS mounted on canvases:


3D Modeling: Random Snapshots 2020

3D Modeling: Elegant Pieces in OpenSCAD with rcube(), rcylinder() and chainhull()


  • 2020/12/31: rcube() extended, RCUBE_FLAT{BOTTOM, TOP, FRONT, BACK, LEFT, RIGHT} support added, rcylinder() with RCYLINDER_FLAT{TOP, BOTTOM}
  • 2020/12/30: rcube() source code extended, support RCUBE_FLATX, RCUBE_FLATY, RCUBE_FLATZ
  • 2020/12/28: inital post

While working on Ashtar D (Classic XY) I looked at some pieces I rushed to design with cube() and hull() and they didn’t appeal to me – yes, it kind of hurt my eyes.

A while back I coded a simple rcube([x,y,z],r) which takes r as a radius for the edges, internally it’s an OpenSCAD module which uses 8 spheres and hulls them together, providing round edges; but I hesitated to actually use it in my designs – until now. Further I thought, let’s do the same with cylinder() using rcylinder(d=10,h=5,r=1) providing round edges by using two torii and hull them together.

These two new functions, rcube([x,y,z],r) and rcylinder(h,d,r) allow to create more organic and elegant pieces, see for yourself:

From Bulky To Elegance

The position of the Y pulley mount is given, a bit of an X- & Y-offset to ensure printable area is not sacrificed for the Y carriage:

Using Chained Hulls

And another example . . . replacing hull() with chainhull():

The final version is composed by only 3 pieces chain hulled together:

difference() {
   chainhull() {
      translate([0,0,-20]) rcube(...);
      translate([...,-60]) rcube([5,20,50],2); // 2020 mount plate
   rcube(...);     // pulley cutout

rcube() & rcylinder()

translate([5,0,0]) rcube(0.75);
translate([10,0,0]) rcube([2,1,1],0.2);

translate([0,2,0]) rcube([2,1,1],0.2,false);
translate([5,2,0]) rcube([2,1,1],0.2,true);

translate([0,4,0]) rcube([2,1,1],0.2,RCUBE_FLATX);
translate([5,4,0]) rcube([2,1,1],0.2,RCUBE_FLATY);
translate([10,4,0]) rcube([2,1,1],0.2,RCUBE_FLATZ);

translate([0,6,0]) rcube([2,1,1],0.2,RCUBE_FLATBOTTOM);
translate([5,6,0]) rcube([2,1,1],0.2,RCUBE_FLATTOP);

translate([0,8,0]) rcube([2,1,1],0.2,RCUBE_FLATFRONT);
translate([5,8,0]) rcube([2,1,1],0.2,RCUBE_FLATBACK);

translate([0,10,0]) rcube([2,1,1],0.2,RCUBE_FLATLEFT);
translate([5,10,0]) rcube([2,1,1],0.2,RCUBE_FLATRIGHT);

translate([0+1,14,0]) rcylinder(3,1.5,0.2);
translate([3+1,14,0]) rcylinder(3,1.5,0.2,false);
translate([6+1,14,0]) rcylinder(3,1.5,0.2,RCYLINDER_FLATBOTTOM);
translate([9+1,14,0]) rcylinder(3,1.5,0.2,RCYLINDER_FLATTOP);

The library code (I might later release it as a separate library):

// Title: rcube(), rcylinder() & torus()
// Author: Rene K. Mueller
// License: MIT License 2020
// Version: 0.0.2

RCUBE_FLATX = [false,true,true];
RCUBE_FLATY = [true,false,true];
RCUBE_FLATZ = [true,true,false];
RCUBE_FLATBOTTOM = [false,false,false,false,true,true,true,true];
RCUBE_FLATTOP = [true,true,true,true,false,false,false,false];
RCUBE_FLATFRONT = [false,false,true,true,false,false,true,true];
RCUBE_FLATBACK = [true,true,false,false,true,true,false,false];
RCUBE_FLATLEFT = [false,true,true,false,false,true,true,false];
RCUBE_FLATRIGHT = [true,false,false,true,true,false,false,true];

module rcube(a=1,r=0.1,rd=[true,true,true],center=false,$fn=32) {
    else {
       x = len(a) ? a[0] : a;
       y = len(a) ? a[1] : a;
       z = len(a) ? a[2] : a;
       rd = len(rd) ? rd : [rd,rd,rd];

          if((len(rd)==3 && rd[0] && rd[1] && rd[2]) || (len(a)==0 && rd)) // rd=[true,true,true] or true
             hull() {
                translate([r,r,r]) sphere(r);
                translate([x-r,r,r]) sphere(r);
                translate([x-r,y-r,r]) sphere(r);
                translate([r,y-r,r]) sphere(r);
                translate([r,r,z-r]) sphere(r);
                translate([x-r,r,z-r]) sphere(r);
                translate([x-r,y-r,z-r]) sphere(r);
                translate([r,y-r,z-r]) sphere(r);
          else                                                        // anything else
             hull() {
                translate([r,r,r]) rcube_prim(r,rd,0);
                translate([x-r,r,r]) rcube_prim(r,rd,1);
                translate([x-r,y-r,r]) rcube_prim(r,rd,2);
                translate([r,y-r,r]) rcube_prim(r,rd,3);
                translate([r,r,z-r]) rcube_prim(r,rd,4);
                translate([x-r,r,z-r]) rcube_prim(r,rd,5);
                translate([x-r,y-r,z-r]) rcube_prim(r,rd,6);
                translate([r,y-r,z-r]) rcube_prim(r,rd,7);

module rcube_prim(r,rd,i) {
    a = len(rd);
    if(a<=3) {
       if(a && rd[0] && rd[1] && rd[2]) 
       else if(a && rd[0] && rd[1])
          translate([0,0,-r]) cylinder(r=r,h=r*2);
       else if(a && rd[1] && rd[2])
          translate([-r,0,0]) rotate([0,90,0]) cylinder(r=r,h=r*2);
       else if(a && rd[0] && rd[2])
          translate([0,-r,0]) rotate([-90,0,0]) cylinder(r=r,h=r*2);
          translate([-r,-r,-r]) cube(r*2);
    } else 
          translate([-r,-r,-r]) cube(r*2);

RCYLINDER_FLATTOP = [true,false];

module rcylinder(h=2,d=1,r=0.1,rd=[true,true],$fn=40) {
       hull() { 
             if(len(rd) && rd[0]) torus(do=d,di=r*2); else translate([0,0,-r]) cylinder(d=d,h=r);          
             if(len(rd) && rd[1]) torus(do=d,di=r*2); else cylinder(d=d,h=r);

 module torus(do=2,di=0.1,a=360) {
    rotate_extrude(convexity=10,angle=a) {
       translate([do/2-di/2,0,0]) circle(d=di,$fn=20);


module chainhull() {
       hull() {

There is one drawback using chainhull() { } as you can’t use conditional if else with { } within as it combines them as a group and becomes a child structure and so it will act as hull(), so you only can list non-conditional pieces within chainhull() as of OpenSCAD 2019.05, perhaps at a later time this limit vanishes.

That’s it.