discuss@lists.openscad.org

OpenSCAD general discussion Mailing-list

View all threads

is color an actual operator module ?

V
vulcan_@mac.com
Mon, Jul 28, 2025 11:18 PM

ir is i just a low priority operator like echo and assert?

ir is i just a low priority operator like echo and assert?
JB
Jordan Brown
Mon, Jul 28, 2025 11:36 PM

On 7/28/2025 4:18 PM, vulcan_--- via Discuss wrote:

ir is i just a low priority operator like echo and assert?

Colors is an actual operator module.

There are only three of the "special" expression operators:  let, echo,
assert.
They are similar to, but different from, the operator modules let, echo,
and assert.
And those are different from the list comprehension module let.

On 7/28/2025 4:18 PM, vulcan_--- via Discuss wrote: > > ir is i just a low priority operator like echo and assert? > Colors is an actual operator module. There are only three of the "special" expression operators:  let, echo, assert. They are similar to, but different from, the operator modules let, echo, and assert. And those are different from the list comprehension module let.
V
vulcan_@mac.com
Wed, Jul 30, 2025 7:38 PM

oi

so when i a statement do i need to be concerned that i dont know if (let echo assert) are operators or modules?

if i write

xxx= ( assert(true) 2 ) + 3 // i would think this assert is an operator in an expression so, as it is inside parens to force precedence right?

but

assert( true ) translate( [1,1,1] ) cube(); // here it is an operator module, yes?

are there any differences in operation between operator and  module forms of (let echo assert) ?

are there any syntactic differences in how they are used in a script?

oi so when i a statement do i need to be concerned that i dont know if (let echo assert) are operators or modules? if i write xxx= ( assert(true) 2 ) + 3 // i would think this assert is an operator in an expression so, as it is inside parens to force precedence right? but assert( true ) translate( \[1,1,1\] ) cube(); // here it is an operator module, yes? are there any differences in operation between operator and module forms of (let echo assert) ? are there any syntactic differences in how they are used in a script?
AM
Adrian Mariano
Wed, Jul 30, 2025 11:32 PM

The execution order is different between modules and expressions, because
expressions run first, before all modules.

If you write this

assert(x>0);  // assert is a module
y=f(x);  // function f requires that x>0
sphere(y);

then your code will fail if x<=0 when f() is evaluated and the assert will
never do anything.  You have to rewrite it as:

dummy = assert(x>0);  // assert is in an expression
y=f(x);
sphere(y);

in order for the assertion to prevent f() from being invoked incorrectly.
I was totally mystified the first time I encountered this behavior and I
could only fix it by moving the assert() into f().  I rarely put an assert
inside an expression that does something else.  It seems less clear and
binds together two things that may not necessarily belong together.  Also
it may not be obvious that you can chain them like dummy = assert(cond1)
assert(cond2) assert(cond3);

On Wed, Jul 30, 2025 at 3:38 PM vulcan_--- via Discuss <
discuss@lists.openscad.org> wrote:

oi

so when i a statement do i need to be concerned that i dont know if (let
echo assert) are operators or modules?

if i write

xxx= ( assert(true) 2 ) + 3 // i would think this assert is an operator in
an expression so, as it is inside parens to force precedence right?

but

assert( true ) translate( [1,1,1] ) cube(); // here it is an operator
module, yes?

are there any differences in operation between operator and module forms
of (let echo assert) ?

are there any syntactic differences in how they are used in a script?


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

The execution order is different between modules and expressions, because expressions run first, before all modules. If you write this assert(x>0); // assert is a module y=f(x); // function f requires that x>0 sphere(y); then your code will fail if x<=0 when f() is evaluated and the assert will never do anything. You have to rewrite it as: dummy = assert(x>0); // assert is in an expression y=f(x); sphere(y); in order for the assertion to prevent f() from being invoked incorrectly. I was totally mystified the first time I encountered this behavior and I could only fix it by moving the assert() into f(). I rarely put an assert inside an expression that does something else. It seems less clear and binds together two things that may not necessarily belong together. Also it may not be obvious that you can chain them like dummy = assert(cond1) assert(cond2) assert(cond3); On Wed, Jul 30, 2025 at 3:38 PM vulcan_--- via Discuss < discuss@lists.openscad.org> wrote: > oi > > so when i a statement do i need to be concerned that i dont know if (let > echo assert) are operators or modules? > > if i write > > xxx= ( assert(true) 2 ) + 3 // i would think this assert is an operator in > an expression so, as it is inside parens to force precedence right? > > but > > assert( true ) translate( [1,1,1] ) cube(); // here it is an operator > module, yes? > > are there any differences in operation between operator and module forms > of (let echo assert) ? > > are there any syntactic differences in how they are used in a script? > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org >
NH
nop head
Thu, Jul 31, 2025 7:55 AM

I would do:

y = assert(x>0) f(x);

That avoids the dummy variable and makes it clearer why the condition must
hold, i.e. to satisfy f().

On Thu, 31 Jul 2025 at 00:32, Adrian Mariano via Discuss <
discuss@lists.openscad.org> wrote:

The execution order is different between modules and expressions, because
expressions run first, before all modules.

If you write this

assert(x>0);  // assert is a module
y=f(x);  // function f requires that x>0
sphere(y);

then your code will fail if x<=0 when f() is evaluated and the assert will
never do anything.  You have to rewrite it as:

dummy = assert(x>0);  // assert is in an expression
y=f(x);
sphere(y);

in order for the assertion to prevent f() from being invoked incorrectly.
I was totally mystified the first time I encountered this behavior and I
could only fix it by moving the assert() into f().  I rarely put an assert
inside an expression that does something else.  It seems less clear and
binds together two things that may not necessarily belong together.  Also
it may not be obvious that you can chain them like dummy = assert(cond1)
assert(cond2) assert(cond3);

On Wed, Jul 30, 2025 at 3:38 PM vulcan_--- via Discuss <
discuss@lists.openscad.org> wrote:

oi

so when i a statement do i need to be concerned that i dont know if (let
echo assert) are operators or modules?

if i write

xxx= ( assert(true) 2 ) + 3 // i would think this assert is an operator
in an expression so, as it is inside parens to force precedence right?

but

assert( true ) translate( [1,1,1] ) cube(); // here it is an operator
module, yes?

are there any differences in operation between operator and module forms
of (let echo assert) ?

are there any syntactic differences in how they are used in a script?


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

I would do: y = assert(x>0) f(x); That avoids the dummy variable and makes it clearer why the condition must hold, i.e. to satisfy f(). On Thu, 31 Jul 2025 at 00:32, Adrian Mariano via Discuss < discuss@lists.openscad.org> wrote: > The execution order is different between modules and expressions, because > expressions run first, before all modules. > > If you write this > > assert(x>0); // assert is a module > y=f(x); // function f requires that x>0 > sphere(y); > > then your code will fail if x<=0 when f() is evaluated and the assert will > never do anything. You have to rewrite it as: > > dummy = assert(x>0); // assert is in an expression > y=f(x); > sphere(y); > > in order for the assertion to prevent f() from being invoked incorrectly. > I was totally mystified the first time I encountered this behavior and I > could only fix it by moving the assert() into f(). I rarely put an assert > inside an expression that does something else. It seems less clear and > binds together two things that may not necessarily belong together. Also > it may not be obvious that you can chain them like dummy = assert(cond1) > assert(cond2) assert(cond3); > > > > On Wed, Jul 30, 2025 at 3:38 PM vulcan_--- via Discuss < > discuss@lists.openscad.org> wrote: > >> oi >> >> so when i a statement do i need to be concerned that i dont know if (let >> echo assert) are operators or modules? >> >> if i write >> >> xxx= ( assert(true) 2 ) + 3 // i would think this assert is an operator >> in an expression so, as it is inside parens to force precedence right? >> >> but >> >> assert( true ) translate( [1,1,1] ) cube(); // here it is an operator >> module, yes? >> >> are there any differences in operation between operator and module forms >> of (let echo assert) ? >> >> are there any syntactic differences in how they are used in a script? >> _______________________________________________ >> OpenSCAD mailing list >> To unsubscribe send an email to discuss-leave@lists.openscad.org >> > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org >
AM
Adrian Mariano
Thu, Jul 31, 2025 10:36 AM

Real examples are not so simple, and it rarely makes sense, at least to
me,  to try to attach the assertion to some specific calculation.  There
may be 5 or 10 assertions checking the validity of input to a module.  And
then there may be a dozen expressions, possibly with different conditions
based on the parameters.  How do I decide which calculation to attach the
assertions to?  Determining at which point invalid input causes a problem
may require effort, and I don't think it's going to increase clarity for
someone reading the code.  In fact, I would argue that it's not trivial to
determine whether you can get away with the module form of assert.  It
requires examining the code to figure out whether anything goes wrong
before the modules run.

Algorithmically the assertions are separate operations, not part of some
computation.  Attaching ten assertions to a computation just makes the code
more confusing and harder to read by mixing assertion and calculation
together and putting a huge space between the variable and the calculation
for that variable.    And if I were to somehow associate each assertion
with a different computation, that would be pretty confusing as well, since
now I have the same problem repeatedly.  Also note that in real code, an
assertion doesn't look like "assert(x>0)", it's 80 characters with some
condition to check and a text error message to display.  The calculation
also doesn't look like "f(x)" but may be a long calculation with
conditionals.

On Thu, Jul 31, 2025 at 3:55 AM nop head via Discuss <
discuss@lists.openscad.org> wrote:

I would do:

y = assert(x>0) f(x);

That avoids the dummy variable and makes it clearer why the condition must
hold, i.e. to satisfy f().

On Thu, 31 Jul 2025 at 00:32, Adrian Mariano via Discuss <
discuss@lists.openscad.org> wrote:

The execution order is different between modules and expressions, because
expressions run first, before all modules.

If you write this

assert(x>0);  // assert is a module
y=f(x);  // function f requires that x>0
sphere(y);

then your code will fail if x<=0 when f() is evaluated and the assert
will never do anything.  You have to rewrite it as:

dummy = assert(x>0);  // assert is in an expression
y=f(x);
sphere(y);

in order for the assertion to prevent f() from being invoked
incorrectly.  I was totally mystified the first time I encountered this
behavior and I could only fix it by moving the assert() into f().  I
rarely put an assert inside an expression that does something else.  It
seems less clear and binds together two things that may not necessarily
belong together.  Also it may not be obvious that you can chain them like
dummy = assert(cond1) assert(cond2) assert(cond3);

On Wed, Jul 30, 2025 at 3:38 PM vulcan_--- via Discuss <
discuss@lists.openscad.org> wrote:

oi

so when i a statement do i need to be concerned that i dont know if (let
echo assert) are operators or modules?

if i write

xxx= ( assert(true) 2 ) + 3 // i would think this assert is an operator
in an expression so, as it is inside parens to force precedence right?

but

assert( true ) translate( [1,1,1] ) cube(); // here it is an operator
module, yes?

are there any differences in operation between operator and module forms
of (let echo assert) ?

are there any syntactic differences in how they are used in a script?


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

Real examples are not so simple, and it rarely makes sense, at least to me, to try to attach the assertion to some specific calculation. There may be 5 or 10 assertions checking the validity of input to a module. And then there may be a dozen expressions, possibly with different conditions based on the parameters. How do I decide which calculation to attach the assertions to? Determining at which point invalid input causes a problem may require effort, and I don't think it's going to increase clarity for someone reading the code. In fact, I would argue that it's not trivial to determine whether you can get away with the module form of assert. It requires examining the code to figure out whether anything goes wrong before the modules run. Algorithmically the assertions are separate operations, not part of some computation. Attaching ten assertions to a computation just makes the code more confusing and harder to read by mixing assertion and calculation together and putting a huge space between the variable and the calculation for that variable. And if I were to somehow associate each assertion with a different computation, that would be pretty confusing as well, since now I have the same problem repeatedly. Also note that in real code, an assertion doesn't look like "assert(x>0)", it's 80 characters with some condition to check and a text error message to display. The calculation also doesn't look like "f(x)" but may be a long calculation with conditionals. On Thu, Jul 31, 2025 at 3:55 AM nop head via Discuss < discuss@lists.openscad.org> wrote: > I would do: > > y = assert(x>0) f(x); > > That avoids the dummy variable and makes it clearer why the condition must > hold, i.e. to satisfy f(). > > On Thu, 31 Jul 2025 at 00:32, Adrian Mariano via Discuss < > discuss@lists.openscad.org> wrote: > >> The execution order is different between modules and expressions, because >> expressions run first, before all modules. >> >> If you write this >> >> assert(x>0); // assert is a module >> y=f(x); // function f requires that x>0 >> sphere(y); >> >> then your code will fail if x<=0 when f() is evaluated and the assert >> will never do anything. You have to rewrite it as: >> >> dummy = assert(x>0); // assert is in an expression >> y=f(x); >> sphere(y); >> >> in order for the assertion to prevent f() from being invoked >> incorrectly. I was totally mystified the first time I encountered this >> behavior and I could only fix it by moving the assert() into f(). I >> rarely put an assert inside an expression that does something else. It >> seems less clear and binds together two things that may not necessarily >> belong together. Also it may not be obvious that you can chain them like >> dummy = assert(cond1) assert(cond2) assert(cond3); >> >> >> >> On Wed, Jul 30, 2025 at 3:38 PM vulcan_--- via Discuss < >> discuss@lists.openscad.org> wrote: >> >>> oi >>> >>> so when i a statement do i need to be concerned that i dont know if (let >>> echo assert) are operators or modules? >>> >>> if i write >>> >>> xxx= ( assert(true) 2 ) + 3 // i would think this assert is an operator >>> in an expression so, as it is inside parens to force precedence right? >>> >>> but >>> >>> assert( true ) translate( [1,1,1] ) cube(); // here it is an operator >>> module, yes? >>> >>> are there any differences in operation between operator and module forms >>> of (let echo assert) ? >>> >>> are there any syntactic differences in how they are used in a script? >>> _______________________________________________ >>> OpenSCAD mailing list >>> To unsubscribe send an email to discuss-leave@lists.openscad.org >>> >> _______________________________________________ >> OpenSCAD mailing list >> To unsubscribe send an email to discuss-leave@lists.openscad.org >> > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org >
V
vulcan_@mac.com
Thu, Jul 31, 2025 3:07 PM

when assert() is a module, is it an operator module or an object module?

my testing:

RGB=[0,0,1];
color("red") assert( RGB == [0,0,1])
translate([0,3,0])
cube(3);

this works, the assert passes and the cube is drawn.
Or i change the test to [0,0,2 ] and the assert fails

color("red")
translate([0,3,0])
cube(3) assert( RGB == [0,0,01]);

emits this:

[WARNING: module cube() does not support child modules in file ., line 14](14,C:/Program Files/OpenSCAD (Nightly))

and draws the red cube

so .. in a limited sense assert() is an operator module

it can be placed so:

assert( RGB == [0,0,2]);

and then it is being an Object Model as it works even when it has no children, which an operator module cannot do.

and it can be a function returning a value and both types of module.

when assert() is a module, is it an operator module or an object module? my testing: `RGB=[0,0,1];`\ `color("red") assert( RGB == [0,0,1])`\ ` translate([0,3,0])`\ ` cube(3);` this works, the assert passes and the cube is drawn.\ Or i change the test to \[0,0,2 \] and the assert fails `color("red") `\ ` translate([0,3,0])`\ ` cube(3) assert( RGB == [0,0,01]);` emits this: [WARNING: module cube() does not support child modules in file ., line 14](14,C:/Program Files/OpenSCAD (Nightly)) and draws the red cube so .. in a limited sense assert() is an operator module it can be placed so: `assert( RGB == [0,0,2]);` and then it is being an Object Model as it works even when it has no children, which an operator module cannot do. and it can be a function returning a value and both types of module.
NH
nop head
Thu, Jul 31, 2025 3:11 PM

There aren't any operator modules. Just modules used in statements and
functions used in expressions. Some are both like assert and echo.

On Thu, 31 Jul 2025, 16:08 vulcan_--- via Discuss, <
discuss@lists.openscad.org> wrote:

when assert() is a module, is it an operator module or an object module?

my testing:

RGB=[0,0,1];
color("red") assert( RGB == [0,0,1])
translate([0,3,0])
cube(3);

this works, the assert passes and the cube is drawn.
Or i change the test to [0,0,2 ] and the assert fails

color("red")
translate([0,3,0])
cube(3) assert( RGB == [0,0,01]);

emits this:

WARNING: module cube() does not support child modules in file ., line 14

and draws the red cube

so .. in a limited sense assert() is an operator module

it can be placed so:

assert( RGB == [0,0,2]);

and then it is being an Object Model as it works even when it has no
children, which an operator module cannot do.

and it can be a function returning a value and both types of module.


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

There aren't any operator modules. Just modules used in statements and functions used in expressions. Some are both like assert and echo. On Thu, 31 Jul 2025, 16:08 vulcan_--- via Discuss, < discuss@lists.openscad.org> wrote: > when assert() is a module, is it an operator module or an object module? > > my testing: > > RGB=[0,0,1]; > color("red") assert( RGB == [0,0,1]) > translate([0,3,0]) > cube(3); > > this works, the assert passes and the cube is drawn. > Or i change the test to [0,0,2 ] and the assert fails > > color("red") > translate([0,3,0]) > cube(3) assert( RGB == [0,0,01]); > > emits this: > > WARNING: module cube() does not support child modules in file ., line 14 > > and draws the red cube > > so .. in a limited sense assert() is an operator module > > it can be placed so: > > assert( RGB == [0,0,2]); > > and then it is being an Object Model as it works even when it has no > children, which an operator module cannot do. > > and it can be a function returning a value and both types of module. > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org >
AM
Adrian Mariano
Thu, Jul 31, 2025 4:53 PM

I think he is distinguishing between a module like cube which creates
geometry and does not accept children and a module like rotate which
operates on children and doesn’t produce any results itself. It does not
fail without children. It just does not produce a result.

So then cube is an “object” and rotate is an “operator”.

If you want to put the assert module into that framework it’s an operator.
It accepts children like rotate. It does not fail without children.

However the framework is not complete. A module can perfectly well produce
geometry and also process and operate on children.  It just happens that no
built in modules do that.

I don’t think there is ever a reason to give children to assert even though
you can.

On Thu, Jul 31, 2025 at 11:12 nop head via Discuss <
discuss@lists.openscad.org> wrote:

There aren't any operator modules. Just modules used in statements and
functions used in expressions. Some are both like assert and echo.

On Thu, 31 Jul 2025, 16:08 vulcan_--- via Discuss, <
discuss@lists.openscad.org> wrote:

when assert() is a module, is it an operator module or an object module?

my testing:

RGB=[0,0,1];
color("red") assert( RGB == [0,0,1])
translate([0,3,0])
cube(3);

this works, the assert passes and the cube is drawn.
Or i change the test to [0,0,2 ] and the assert fails

color("red")
translate([0,3,0])
cube(3) assert( RGB == [0,0,01]);

emits this:

WARNING: module cube() does not support child modules in file ., line 14

and draws the red cube

so .. in a limited sense assert() is an operator module

it can be placed so:

assert( RGB == [0,0,2]);

and then it is being an Object Model as it works even when it has no
children, which an operator module cannot do.

and it can be a function returning a value and both types of module.


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

I think he is distinguishing between a module like cube which creates geometry and does not accept children and a module like rotate which operates on children and doesn’t produce any results itself. It does not fail without children. It just does not produce a result. So then cube is an “object” and rotate is an “operator”. If you want to put the assert module into that framework it’s an operator. It accepts children like rotate. It does not fail without children. However the framework is not complete. A module can perfectly well produce geometry and also process and operate on children. It just happens that no built in modules do that. I don’t think there is ever a reason to give children to assert even though you can. On Thu, Jul 31, 2025 at 11:12 nop head via Discuss < discuss@lists.openscad.org> wrote: > There aren't any operator modules. Just modules used in statements and > functions used in expressions. Some are both like assert and echo. > > On Thu, 31 Jul 2025, 16:08 vulcan_--- via Discuss, < > discuss@lists.openscad.org> wrote: > >> when assert() is a module, is it an operator module or an object module? >> >> my testing: >> >> RGB=[0,0,1]; >> color("red") assert( RGB == [0,0,1]) >> translate([0,3,0]) >> cube(3); >> >> this works, the assert passes and the cube is drawn. >> Or i change the test to [0,0,2 ] and the assert fails >> >> color("red") >> translate([0,3,0]) >> cube(3) assert( RGB == [0,0,01]); >> >> emits this: >> >> WARNING: module cube() does not support child modules in file ., line 14 >> >> and draws the red cube >> >> so .. in a limited sense assert() is an operator module >> >> it can be placed so: >> >> assert( RGB == [0,0,2]); >> >> and then it is being an Object Model as it works even when it has no >> children, which an operator module cannot do. >> >> and it can be a function returning a value and both types of module. >> _______________________________________________ >> OpenSCAD mailing list >> To unsubscribe send an email to discuss-leave@lists.openscad.org >> > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org >
V
vulcan_@mac.com
Thu, Jul 31, 2025 11:02 PM

while the underlying implementation may be the same for Operator Modules and Object Modules in practice the differences are critical.

If one defines an Object Module it results in one or more shapes being drawn. An Operator Module must end with a call to children() and cannot itself draw shapes.

An operator at the end of a statement causes no error nor warning, but also does nothing. .. at least in the 2025.07.20 i am using

An object can only be at the end of a statement .. sort of

color("red")
cube(5)
translate([0,3,0])
;

this will run but emits a warning: WARNING: module cube() does not support child modules …

but it does draw the cube

This also draws the cube, with the warning, but does not draw the second object, the sphere()

color("red")
cube(5)
translate([0,3,0])
sphere(r=4);

So in real terms, there are

  1. functions that return a value, can only be used in expressions, and cannot draw geometry

  2. modules that draw geometry, must come last in a statement, and cannot call children()

  3. modules that operate on objects can only call other operator modules and must call children() as their last statement

and i have documented all of this after quite a lot of experimentation to be sure i was writing true things about modules

If you folks can correct my understanding of modules where i might be in error i would appreciate it so i can update the docs

thanks

while the underlying implementation may be the same for Operator Modules and Object Modules in practice the differences are critical. If one defines an Object Module it results in one or more shapes being drawn. An Operator Module must end with a call to children() and cannot itself draw shapes. An operator at the end of a statement causes no error nor warning, but also does nothing. .. at least in the 2025.07.20 i am using An object can *only* be at the end of a statement .. sort of `color("red")`\ ` cube(5)`\ ` translate([0,3,0])`\ ` ;` this will run but emits a warning: WARNING: module cube() does not support child modules … but it does draw the cube This also draws the cube, with the warning, but does not draw the second object, the sphere() `color("red")`\ ` cube(5)`\ ` translate([0,3,0])`\ ` sphere(r=4);` So in real terms, there are 1. functions that return a value, can only be used in expressions, and cannot draw geometry 2. modules that draw geometry, must come last in a statement, and cannot call children() 3. modules that operate on objects can only call other operator modules and must call children() as their last statement and i have documented all of this after quite a lot of experimentation to be sure i was writing true things about modules If you folks can correct my understanding of modules where i might be in error i would appreciate it so i can update the docs thanks
AM
Adrian Mariano
Thu, Jul 31, 2025 11:41 PM

First a few comments on your language.  In three you talk about "calling
children()".  Well, "children()" is a module that you can call any place a
module is allowed.  Another module can call it many times, and it need not
be at the end of anything.  Maybe you meant "children".

Another problem with the language is that modules may "call" other modules,
including children(), but they do that within the module definition, which
is not available to us for built-in modules.  When you are using a module
you write the modules name and then you give it a list of children, in
braces if there are more than one.  I would not describe this relationship
as "the module calling" the children.  It's more like the module "has"
children.  They are there for the module to use, which is can do any number
of times.    Also if you have an expression like

color("red")
translate([0,3,0])
sphere(r=4);

then color() is the first module.  It has one child which is
"translate([0.3,0])sphere(r=4)".  The notion that the child (children?) is
somehow last is mistaken.  Every module not followed immediately by a ";"
character has children.  Furthermore, you don't seem to be clearly
acknowledging that there might be more than 1 child.  For example:

color("red") { cube(5); translate([0,3,0]) sphere(r=4);}

Now the color module has 2 children.  Again, nothing is "called" they are
simply the children provided to the color module.

The problem is that your "real terms" aren't right because a module can
both draw geometry and call children.  Consider:

module both(size)
{
right(size*1.5) children();
cube(size);
}

both(10) sphere(4);

It draws a shape but also it acts on its children.  And both() can appear
anywhere in what you're calling a statement.  Based on your list it fails
2 because it can call children and it fails 3 because it need not call
children.  So it doesn't fit in your classification.  If your goal is to
classify ONLY the built-in modules in native OpenSCAD without any broader
applicability (no libraries or user written code) then I think it does
cover the (currently) available modules, but it's not fully general and it
also doesn't cover modules found in libraries or the range of what can be
written.  In other words, it's not a fundamental characteristic of modules
but more like a pragmatic division of the native modules.

In the BOSL2 library, for example, the cuboid() module draws geometry and
can be invoked without children, but it also optionally accepts children
and runs them.  There are very few modules in BOSL2 that satisfy condition
2 on your list because almost everything that creates geometry also accepts
children, and furthermore, BOSL2 redefines most of the native modules to
match BOSL2's general behavior.

So in BOSL2:

include<BOSL2/std.scad>
cuboid(10) attach(RIGHT,BOT) cyl(r=5,h=10);

produces this:
[image: image.png]

On Thu, Jul 31, 2025 at 7:02 PM vulcan_--- via Discuss <
discuss@lists.openscad.org> wrote:

while the underlying implementation may be the same for Operator Modules
and Object Modules in practice the differences are critical.

If one defines an Object Module it results in one or more shapes being
drawn. An Operator Module must end with a call to children() and cannot
itself draw shapes.

An operator at the end of a statement causes no error nor warning, but
also does nothing. .. at least in the 2025.07.20 i am using

An object can only be at the end of a statement .. sort of

color("red")
cube(5)
translate([0,3,0])
;

this will run but emits a warning: WARNING: module cube() does not support
child modules …

but it does draw the cube

This also draws the cube, with the warning, but does not draw the second
object, the sphere()

color("red")
cube(5)
translate([0,3,0])
sphere(r=4);

So in real terms, there are

1.

functions that return a value, can only be used in expressions, and
cannot draw geometry
2.

modules that draw geometry, must come last in a statement, and cannot
call children()
3.

modules that operate on objects can only call other operator modules
and must call children() as their last statement

and i have documented all of this after quite a lot of experimentation to
be sure i was writing true things about modules

If you folks can correct my understanding of modules where i might be in
error i would appreciate it so i can update the docs

thanks


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

First a few comments on your language. In three you talk about "calling children()". Well, "children()" is a module that you can call any place a module is allowed. Another module can call it many times, and it need not be at the end of anything. Maybe you meant "children". Another problem with the language is that modules may "call" other modules, including children(), but they do that within the module definition, which is not available to us for built-in modules. When you are using a module you write the modules name and then you give it a list of children, in braces if there are more than one. I would not describe this relationship as "the module calling" the children. It's more like the module "has" children. They are there for the module to use, which is can do any number of times. Also if you have an expression like color("red") translate([0,3,0]) sphere(r=4); then color() is the first module. It has one child which is "translate([0.3,0])sphere(r=4)". The notion that the child (children?) is somehow last is mistaken. Every module not followed immediately by a ";" character has children. Furthermore, you don't seem to be clearly acknowledging that there might be more than 1 child. For example: color("red") { cube(5); translate([0,3,0]) sphere(r=4);} Now the color module has 2 children. Again, nothing is "called" they are simply the children provided to the color module. The problem is that your "real terms" aren't right because a module can both draw geometry and call children. Consider: module both(size) { right(size*1.5) children(); cube(size); } both(10) sphere(4); It draws a shape but also it acts on its children. And both() can appear anywhere in what you're calling a statement. Based on your list it fails 2 because it can call children and it fails 3 because it need not call children. So it doesn't fit in your classification. If your goal is to classify ONLY the built-in modules in native OpenSCAD without any broader applicability (no libraries or user written code) then I think it does cover the (currently) available modules, but it's not fully general and it also doesn't cover modules found in libraries or the range of what can be written. In other words, it's not a fundamental characteristic of modules but more like a pragmatic division of the native modules. In the BOSL2 library, for example, the cuboid() module draws geometry and can be invoked without children, but it also optionally accepts children and runs them. There are very few modules in BOSL2 that satisfy condition 2 on your list because almost everything that creates geometry also accepts children, and furthermore, BOSL2 redefines most of the native modules to match BOSL2's general behavior. So in BOSL2: include<BOSL2/std.scad> cuboid(10) attach(RIGHT,BOT) cyl(r=5,h=10); produces this: [image: image.png] On Thu, Jul 31, 2025 at 7:02 PM vulcan_--- via Discuss < discuss@lists.openscad.org> wrote: > while the underlying implementation may be the same for Operator Modules > and Object Modules in practice the differences are critical. > > If one defines an Object Module it results in one or more shapes being > drawn. An Operator Module must end with a call to children() and cannot > itself draw shapes. > > An operator at the end of a statement causes no error nor warning, but > also does nothing. .. at least in the 2025.07.20 i am using > > An object can *only* be at the end of a statement .. sort of > > color("red") > cube(5) > translate([0,3,0]) > ; > > this will run but emits a warning: WARNING: module cube() does not support > child modules … > > but it does draw the cube > > This also draws the cube, with the warning, but does not draw the second > object, the sphere() > > color("red") > cube(5) > translate([0,3,0]) > sphere(r=4); > > So in real terms, there are > > 1. > > functions that return a value, can only be used in expressions, and > cannot draw geometry > 2. > > modules that draw geometry, must come last in a statement, and cannot > call children() > 3. > > modules that operate on objects can only call other operator modules > and must call children() as their last statement > > and i have documented all of this after quite a lot of experimentation to > be sure i was writing true things about modules > > > If you folks can correct my understanding of modules where i might be in > error i would appreciate it so i can update the docs > > thanks > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org >
V
vulcan_@mac.com
Sat, Aug 2, 2025 10:20 PM

thanks Adrian, for the feedback and guidance.

i first want to check a few things with you :

from you n other comments my breadth of language is a bit jarring for the reader .. ok

  1. object is now reserved for things made by the object() function .. unless .. is that also a module pretending to be a function ??

  2. i will use shape as the generic term for anything drawn into the model as lines or surfaces, and thus will not use “geometry” except when talking about math shapes that are geometrical concepts

  3. drawn will now be the word for making lines and surfaces appear in the model

  4. rendering will be the word for processing the shapes in the model into a human visible form, be that preview, generating an image or exporting a file

  5. is children() a placeholder for the objects that the operator module will be applied to at run-time? OR is it a funky function? or is it more of an object module ? or is it another of the funky operators let(), assert() etc.?

Now the discussion for thread:

the term “call” or “calling“ is time honored tradition to use when one chunk of code (program, subroutine whatever) makes a reference to another chunk of code .. be called a function, subroutine or method soo .

if there is something really truly NOT correct about using the term calling then i will change my approach

BUT

the appearance of the thing is that an openSCAD script can “call” modules, be they user defined or built-in and can “call” functions in the process of evaluating an expression with exactly the same meaning from when FORTRAN allowed the definition of subroutines .. actually i write an un-truth .. subroutines were available from the time the 8008 processor was built with a “call <address>” microcode that pushed the registers onto the stack, jumped to the <address> to continue processing until the “return” microcode when the stack was popped to reload the registers and the program counter reset to the instruction

so, most / many/ some people reading the scad docs and example code (especially!) will see modules and functions being “called“ so i propose to keep using that language to describe code calling code

That said; your comment raises a really valuable point .. the effect of some modules is to create shapes that get placed into a hierarchy .. thus creating parent-child relationships between shapes that have no connection to their underlying math, nor when in the process of execution they got created.

To return to the syntactical issue for a sec, most people reading code that uses braces will see them as creating lexical scope .. which is also true in scad, right? variables defined inside of a brace pair are local to that scope.

IN ADDITION scad is preserving the state of special variables on the stack to allow them to do .. well, something pretty nifty but that i don’t really have my head around yet.

AND IN FURTHER ADDITION braces are creating another generation of children

first .. is this all true? pretty close? where am i still going wrong?

back to children and parents .. so i am now planning to revise my text on object module versus operator module to say that they are variations on the single underlying module thing in the code. But i still feel strongly that the conceptual separation of operator versus object will help people coming new to the language get their head’s around it.

That a module can BOTH draw shapes AND operate on child objects via a call to children() is almost irrelevant to most users. There was no mention of this in the docs before i got into them  .. uhh .. at least not that i saw .. i could have missed it. There have already been a few tiny but important details that did get mention, but in places a bit hidden away.

But even so .. this ability can be covered as an exception to the general usages of modules, specifically user-defined modules, as the vast majority of these will be Either making objects or Operating on objects. A few folks have said stuff about BOSL2 and they way they have extended scad .. which is all to the good .. but it is hard to program anything really complex in scad because the fundamentals of the language are quite difference .. but use the same syntax as C, Java etc … by which i mean the same operators, the concept of stored routines that you call by name, functions that return values to stand in for complex calculations .. sure looks similar ..

i am trying to help two groups of readers

  1. expert scad coders that need a language reference

  2. people coming to scad from other programming traditions n tech

thanks Adrian, for the feedback and guidance. i first want to check a few things with you : from you n other comments my breadth of language is a bit jarring for the reader .. ok 1. object is now reserved for things made by the object() function .. unless .. is that also a module pretending to be a function ?? 2. i will use shape as the generic term for anything drawn into the model as lines or surfaces, and thus will not use “geometry” except when talking about math shapes that are geometrical concepts 3. drawn will now be the word for making lines and surfaces appear in the model 4. rendering will be the word for processing the shapes in the model into a human visible form, be that preview, generating an image or exporting a file 5. is children() a placeholder for the objects that the operator module will be applied to at run-time? OR is it a funky function? or is it more of an object module ? or is it another of the funky operators let(), assert() etc.? Now the discussion for thread: the term “call” or “calling“ is time honored tradition to use when one chunk of code (program, subroutine whatever) makes a reference to another chunk of code .. be called a function, subroutine or method soo . if there is something really truly NOT correct about using the term calling then i will change my approach BUT the *appearance* of the thing is that an openSCAD script can “call” modules, be they user defined or built-in and can “call” functions in the process of evaluating an expression with exactly the same meaning from when FORTRAN allowed the definition of subroutines .. actually i write an un-truth .. subroutines were available from the time the 8008 processor was built with a “call <address>” microcode that pushed the registers onto the stack, jumped to the <address> to continue processing until the “return” microcode when the stack was popped to reload the registers and the program counter reset to the instruction so, most / many/ some people reading the scad docs and example code (especially!) will see modules and functions being “called“ so i propose to keep using that language to describe code calling code That said; your comment raises a really valuable point .. the *effect* of some modules is to create shapes that get placed into a hierarchy .. thus creating parent-child relationships between shapes that have no connection to their underlying math, nor when in the process of execution they got created. To return to the syntactical issue for a sec, most people reading code that uses braces will see them as creating lexical scope .. which is also true in scad, right? variables defined inside of a brace pair are local to that scope. IN ADDITION scad is preserving the state of special variables on the stack to allow them to do .. well, something pretty nifty but that i don’t really have my head around yet. AND IN FURTHER ADDITION braces are creating another generation of children first .. is this all true? pretty close? where am i still going wrong? back to children and parents .. so i am now planning to revise my text on object module versus operator module to say that they are variations on the single underlying module thing in the code. But i still feel strongly that the conceptual separation of operator versus object will help people coming new to the language get their head’s around it. That a module can BOTH draw shapes AND operate on child objects via a call to children() is almost irrelevant to most users. There was no mention of this in the docs before i got into them .. uhh .. at least not that i saw .. i could have missed it. There have already been a few tiny but important details that did get mention, but in places a bit hidden away. But even so .. this ability can be covered as an exception to the general usages of modules, specifically user-defined modules, as the vast majority of these will be Either making objects or Operating on objects. A few folks have said stuff about BOSL2 and they way they have extended scad .. which is all to the good .. but it is hard to program anything really complex in scad because the fundamentals of the language are quite difference .. but use the same syntax as C, Java etc … by which i mean the same operators, the concept of stored routines that you call by name, functions that return values to stand in for complex calculations .. sure looks similar .. i am trying to help two groups of readers 1. expert scad coders that need a language reference 2. people coming to scad from other programming traditions n tech
NH
nop head
Sat, Aug 2, 2025 10:51 PM

An example of a module that creates geometry and places children is a
washer in NopSCADlib that draws a washer but if it has a child it places it
on top. The child could be a screw or a nut or a second washer.

On Sat, 2 Aug 2025, 23:20 vulcan_--- via Discuss, <
discuss@lists.openscad.org> wrote:

thanks Adrian, for the feedback and guidance.

i first want to check a few things with you :

from you n other comments my breadth of language is a bit jarring for the
reader .. ok

1.

object is now reserved for things made by the object() function ..
unless .. is that also a module pretending to be a function ??
2.

i will use shape as the generic term for anything drawn into the model
as lines or surfaces, and thus will not use “geometry” except when talking
about math shapes that are geometrical concepts
3.

drawn will now be the word for making lines and surfaces appear in the
model
4.

rendering will be the word for processing the shapes in the model into
a human visible form, be that preview, generating an image or exporting a
file
5.

is children() a placeholder for the objects that the operator module
will be applied to at run-time? OR is it a funky function? or is it more of
an object module ? or is it another of the funky operators let(), assert()
etc.?

Now the discussion for thread:

the term “call” or “calling“ is time honored tradition to use when one
chunk of code (program, subroutine whatever) makes a reference to another
chunk of code .. be called a function, subroutine or method soo .

if there is something really truly NOT correct about using the term
calling then i will change my approach

BUT

the appearance of the thing is that an openSCAD script can “call”
modules, be they user defined or built-in and can “call” functions in the
process of evaluating an expression with exactly the same meaning from when
FORTRAN allowed the definition of subroutines .. actually i write an
un-truth .. subroutines were available from the time the 8008 processor was
built with a “call <address>” microcode that pushed the registers onto the
stack, jumped to the <address> to continue processing until the “return”
microcode when the stack was popped to reload the registers and the program
counter reset to the instruction

so, most / many/ some people reading the scad docs and example code
(especially!) will see modules and functions being “called“ so i propose to
keep using that language to describe code calling code

That said; your comment raises a really valuable point .. the effect of
some modules is to create shapes that get placed into a hierarchy .. thus
creating parent-child relationships between shapes that have no connection
to their underlying math, nor when in the process of execution they got
created.

To return to the syntactical issue for a sec, most people reading code
that uses braces will see them as creating lexical scope .. which is also
true in scad, right? variables defined inside of a brace pair are local to
that scope.

IN ADDITION scad is preserving the state of special variables on the stack
to allow them to do .. well, something pretty nifty but that i don’t really
have my head around yet.

AND IN FURTHER ADDITION braces are creating another generation of children

first .. is this all true? pretty close? where am i still going wrong?

back to children and parents .. so i am now planning to revise my text on
object module versus operator module to say that they are variations on the
single underlying module thing in the code. But i still feel strongly that
the conceptual separation of operator versus object will help people coming
new to the language get their head’s around it.

That a module can BOTH draw shapes AND operate on child objects via a call
to children() is almost irrelevant to most users. There was no mention of
this in the docs before i got into them .. uhh .. at least not that i saw
.. i could have missed it. There have already been a few tiny but important
details that did get mention, but in places a bit hidden away.

But even so .. this ability can be covered as an exception to the general
usages of modules, specifically user-defined modules, as the vast majority
of these will be Either making objects or Operating on objects. A few folks
have said stuff about BOSL2 and they way they have extended scad .. which
is all to the good .. but it is hard to program anything really complex in
scad because the fundamentals of the language are quite difference .. but
use the same syntax as C, Java etc … by which i mean the same operators,
the concept of stored routines that you call by name, functions that return
values to stand in for complex calculations .. sure looks similar ..

i am trying to help two groups of readers

1.

expert scad coders that need a language reference
2.

people coming to scad from other programming traditions n tech

OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

An example of a module that creates geometry and places children is a washer in NopSCADlib that draws a washer but if it has a child it places it on top. The child could be a screw or a nut or a second washer. On Sat, 2 Aug 2025, 23:20 vulcan_--- via Discuss, < discuss@lists.openscad.org> wrote: > thanks Adrian, for the feedback and guidance. > > i first want to check a few things with you : > > from you n other comments my breadth of language is a bit jarring for the > reader .. ok > > 1. > > object is now reserved for things made by the object() function .. > unless .. is that also a module pretending to be a function ?? > 2. > > i will use shape as the generic term for anything drawn into the model > as lines or surfaces, and thus will not use “geometry” except when talking > about math shapes that are geometrical concepts > 3. > > drawn will now be the word for making lines and surfaces appear in the > model > 4. > > rendering will be the word for processing the shapes in the model into > a human visible form, be that preview, generating an image or exporting a > file > 5. > > is children() a placeholder for the objects that the operator module > will be applied to at run-time? OR is it a funky function? or is it more of > an object module ? or is it another of the funky operators let(), assert() > etc.? > > Now the discussion for thread: > > the term “call” or “calling“ is time honored tradition to use when one > chunk of code (program, subroutine whatever) makes a reference to another > chunk of code .. be called a function, subroutine or method soo . > > if there is something really truly NOT correct about using the term > calling then i will change my approach > > BUT > > the *appearance* of the thing is that an openSCAD script can “call” > modules, be they user defined or built-in and can “call” functions in the > process of evaluating an expression with exactly the same meaning from when > FORTRAN allowed the definition of subroutines .. actually i write an > un-truth .. subroutines were available from the time the 8008 processor was > built with a “call <address>” microcode that pushed the registers onto the > stack, jumped to the <address> to continue processing until the “return” > microcode when the stack was popped to reload the registers and the program > counter reset to the instruction > > so, most / many/ some people reading the scad docs and example code > (especially!) will see modules and functions being “called“ so i propose to > keep using that language to describe code calling code > > That said; your comment raises a really valuable point .. the *effect* of > some modules is to create shapes that get placed into a hierarchy .. thus > creating parent-child relationships between shapes that have no connection > to their underlying math, nor when in the process of execution they got > created. > > To return to the syntactical issue for a sec, most people reading code > that uses braces will see them as creating lexical scope .. which is also > true in scad, right? variables defined inside of a brace pair are local to > that scope. > > IN ADDITION scad is preserving the state of special variables on the stack > to allow them to do .. well, something pretty nifty but that i don’t really > have my head around yet. > > AND IN FURTHER ADDITION braces are creating another generation of children > > first .. is this all true? pretty close? where am i still going wrong? > > back to children and parents .. so i am now planning to revise my text on > object module versus operator module to say that they are variations on the > single underlying module thing in the code. But i still feel strongly that > the conceptual separation of operator versus object will help people coming > new to the language get their head’s around it. > > That a module can BOTH draw shapes AND operate on child objects via a call > to children() is almost irrelevant to most users. There was no mention of > this in the docs before i got into them .. uhh .. at least not that i saw > .. i could have missed it. There have already been a few tiny but important > details that did get mention, but in places a bit hidden away. > > But even so .. this ability can be covered as an exception to the general > usages of modules, specifically user-defined modules, as the vast majority > of these will be Either making objects or Operating on objects. A few folks > have said stuff about BOSL2 and they way they have extended scad .. which > is all to the good .. but it is hard to program anything really complex in > scad because the fundamentals of the language are quite difference .. but > use the same syntax as C, Java etc … by which i mean the same operators, > the concept of stored routines that you call by name, functions that return > values to stand in for complex calculations .. sure looks similar .. > > i am trying to help two groups of readers > > 1. > > expert scad coders that need a language reference > 2. > > people coming to scad from other programming traditions n tech > > > > > > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org >
AM
Adrian Mariano
Sun, Aug 3, 2025 12:37 AM

Vulcan,

Let me note that I'm involved in the BOSL2 project, which consumes a lot of
my time and effort and I don't have time to deeply review your
documentation effort for OpenSCAD.  I know OpenSCAD well and almost never
refer to its manual, so I'm not exactly the audience.  I'm not sure why
expert coders would need a language reference.  I only need to occasionally
look up how search() works or other things like that, mainly because the
way search() works is ridiculous.

I do have a bit of a concern that you seem to be trying to (re)write the
OpenSCAD manual while having a somewhat shallow and incomplete
understanding of OpenSCAD.

I think you do not understand how modules are defined and how children
work.  It is absolutely incorrect to describe modules as "calling"
children, in my opinion.  The best word would be that children are
"passed".

Users can define modules in their code, they aren't just magical things
provided by the language.  A module defined by a user can call other
modules in the normal sense of "calling".  That looks like this:

module foo(input)
{
other_module(3*input);
}

In this example, the module foo() has called the module other_module().
You would invoke foo by writing "foo(17);" in your code, perhaps.  And we
can see that foo() makes no use of children.

If you have a module that uses children, perhaps bar(), then when you call
it, you might write this:

bar(24) child();

In this case, bar() is being run and given one child.  I maintain that bar
does not "call" the child in this construction.  The most standard way to
describe the relationship is that the child is PASSED to bar as a
parameter, but it's a different kind of parameter than a variable.  It's a
parameter which is geometry, or I guess what you want to call "shape".
(I'm not a great fan of "shape" because geometry can be several
shapes...but I'm also used to calling it geometry.  That's what we call it
in the BOSL2 manual.)  So the other way to invoke bar() with children is
this:

bar(24)
{
child1();
child2();
child3();
}

Here I have passed three children to bar().  Again, in this code, no
children have been "called".  The children are parameters which are
geometry (shape) instead of data and they are being passed into bar which
can use them or ignore them as it chooses.

Now within bar() I may want to use the children.  The way to do that is to
call the children() module.  This is an ordinary module that invokes all of
the children of the current module().  I guess in your language it "draws
the shape" of the children.  The bar() module can call children() never,
or once, or as many times as it likes, just like with any other kind of
parameter.  It can also do children(0) which "draws the shape" of the first
child, which I called child1() above.

It MAY be a useful taxonomy for the native modules to split them apart into
shape modules and operator modules.  I don't know.  But it's important to
be aware that this doesn't apply to ALL modules, only the native ones
currently in existence.  But this is kind of like saying that in the C
language functions can either return a computed value or they can print
output.  It's an incomplete taxonomy of what functions in C can do.

Another thing to consider here is that a beginning user will be using the
modules provided by native OpenSCAD.  But as the user advances just a bit
they will start writing their own modules which may or may not fit into the
above framework.  Writing your own modules is not some kind of advanced
thing---it's a basic approach for creating readable code.  And if the user
chooses to use libraries like BOSL2 or NopSCADlib they will encounter
modules in those libraries that do not fit into the above framework.  As
previously noted, in BOSL2 every module that "draws a shape" also accepts
children---with very few exceptions.  It's probably a better dichotomy if
you say that there are modules that REQUIRE children and then modules that
do NOT require children.  I suggest that if you present a classification
of module types, make sure it is complete, in the sense that it covers
every possible kind of module and then indicate that the NATIVE modules all
fit into just these two classes, whereas modules defined by libraries or
that you define yourself may fit into this or these other classes.

I have no clue what you mean about preserving the state of special
variables on a stack.

An open brace actually does NOT create a new scope when used in isolation.
You can see this by doing

a=3;
{
a=2;
echo(a);
}

If a new scope was created, this would run without warnings, but it gives a
reassignment warning when a=2 is assigned.  There was talk in the past of
making isolated braces invalid, actually.

If the braces are used to pass children to a parent, then they create a new
scope.  Hence this works:

a=3;
assert(true)
{
a=2;
echo(a);
}

Now the stuff in braces forms children to the assert() module and it
creates a new scope.  When you open a new scope like this all previously
existing variables are preserved, and new variables---which may have the
same name and hence hide the old ones---can be created in the new scope.
The same thing happens with let().  This can make it appear that you can
redefine variables, like above where I "redefined" a, but it only works
because the "redefinition" is in a new scope.

On Sat, Aug 2, 2025 at 6:20 PM vulcan_--- via Discuss <
discuss@lists.openscad.org> wrote:

thanks Adrian, for the feedback and guidance.

i first want to check a few things with you :

from you n other comments my breadth of language is a bit jarring for the
reader .. ok

1.

object is now reserved for things made by the object() function ..
unless .. is that also a module pretending to be a function ??
2.

i will use shape as the generic term for anything drawn into the model
as lines or surfaces, and thus will not use “geometry” except when talking
about math shapes that are geometrical concepts
3.

drawn will now be the word for making lines and surfaces appear in the
model
4.

rendering will be the word for processing the shapes in the model into
a human visible form, be that preview, generating an image or exporting a
file
5.

is children() a placeholder for the objects that the operator module
will be applied to at run-time? OR is it a funky function? or is it more of
an object module ? or is it another of the funky operators let(), assert()
etc.?

Now the discussion for thread:

the term “call” or “calling“ is time honored tradition to use when one
chunk of code (program, subroutine whatever) makes a reference to another
chunk of code .. be called a function, subroutine or method soo .

if there is something really truly NOT correct about using the term
calling then i will change my approach

BUT

the appearance of the thing is that an openSCAD script can “call”
modules, be they user defined or built-in and can “call” functions in the
process of evaluating an expression with exactly the same meaning from when
FORTRAN allowed the definition of subroutines .. actually i write an
un-truth .. subroutines were available from the time the 8008 processor was
built with a “call <address>” microcode that pushed the registers onto the
stack, jumped to the <address> to continue processing until the “return”
microcode when the stack was popped to reload the registers and the program
counter reset to the instruction

so, most / many/ some people reading the scad docs and example code
(especially!) will see modules and functions being “called“ so i propose to
keep using that language to describe code calling code

That said; your comment raises a really valuable point .. the effect of
some modules is to create shapes that get placed into a hierarchy .. thus
creating parent-child relationships between shapes that have no connection
to their underlying math, nor when in the process of execution they got
created.

To return to the syntactical issue for a sec, most people reading code
that uses braces will see them as creating lexical scope .. which is also
true in scad, right? variables defined inside of a brace pair are local to
that scope.

IN ADDITION scad is preserving the state of special variables on the stack
to allow them to do .. well, something pretty nifty but that i don’t really
have my head around yet.

AND IN FURTHER ADDITION braces are creating another generation of children

first .. is this all true? pretty close? where am i still going wrong?

back to children and parents .. so i am now planning to revise my text on
object module versus operator module to say that they are variations on the
single underlying module thing in the code. But i still feel strongly that
the conceptual separation of operator versus object will help people coming
new to the language get their head’s around it.

That a module can BOTH draw shapes AND operate on child objects via a call
to children() is almost irrelevant to most users. There was no mention of
this in the docs before i got into them .. uhh .. at least not that i saw
.. i could have missed it. There have already been a few tiny but important
details that did get mention, but in places a bit hidden away.

But even so .. this ability can be covered as an exception to the general
usages of modules, specifically user-defined modules, as the vast majority
of these will be Either making objects or Operating on objects. A few folks
have said stuff about BOSL2 and they way they have extended scad .. which
is all to the good .. but it is hard to program anything really complex in
scad because the fundamentals of the language are quite difference .. but
use the same syntax as C, Java etc … by which i mean the same operators,
the concept of stored routines that you call by name, functions that return
values to stand in for complex calculations .. sure looks similar ..

i am trying to help two groups of readers

1.

expert scad coders that need a language reference
2.

people coming to scad from other programming traditions n tech

OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

Vulcan, Let me note that I'm involved in the BOSL2 project, which consumes a lot of my time and effort and I don't have time to deeply review your documentation effort for OpenSCAD. I know OpenSCAD well and almost never refer to its manual, so I'm not exactly the audience. I'm not sure why expert coders would need a language reference. I only need to occasionally look up how search() works or other things like that, mainly because the way search() works is ridiculous. I do have a bit of a concern that you seem to be trying to (re)write the OpenSCAD manual while having a somewhat shallow and incomplete understanding of OpenSCAD. I think you do not understand how modules are defined and how children work. It is absolutely incorrect to describe modules as "calling" children, in my opinion. The best word would be that children are "passed". Users can define modules in their code, they aren't just magical things provided by the language. A module defined by a user can call other modules in the normal sense of "calling". That looks like this: module foo(input) { other_module(3*input); } In this example, the module foo() has called the module other_module(). You would invoke foo by writing "foo(17);" in your code, perhaps. And we can see that foo() makes no use of children. If you have a module that uses children, perhaps bar(), then when you call it, you might write this: bar(24) child(); In this case, bar() is being run and given one child. I maintain that bar does not "call" the child in this construction. The most standard way to describe the relationship is that the child is PASSED to bar as a parameter, but it's a different kind of parameter than a variable. It's a parameter which is geometry, or I guess what you want to call "shape". (I'm not a great fan of "shape" because geometry can be several shapes...but I'm also used to calling it geometry. That's what we call it in the BOSL2 manual.) So the other way to invoke bar() with children is this: bar(24) { child1(); child2(); child3(); } Here I have passed three children to bar(). Again, in this code, no children have been "called". The children are parameters which are geometry (shape) instead of data and they are being passed into bar which can use them or ignore them as it chooses. Now within bar() I may want to use the children. The way to do that is to call the children() module. This is an ordinary module that invokes all of the children of the current module(). I guess in your language it "draws the shape" of the children. The bar() module can call children() never, or once, or as many times as it likes, just like with any other kind of parameter. It can also do children(0) which "draws the shape" of the first child, which I called child1() above. It MAY be a useful taxonomy for the native modules to split them apart into shape modules and operator modules. I don't know. But it's important to be aware that this doesn't apply to ALL modules, only the native ones currently in existence. But this is kind of like saying that in the C language functions can either return a computed value or they can print output. It's an incomplete taxonomy of what functions in C can do. Another thing to consider here is that a beginning user will be using the modules provided by native OpenSCAD. But as the user advances just a bit they will start writing their own modules which may or may not fit into the above framework. Writing your own modules is not some kind of advanced thing---it's a basic approach for creating readable code. And if the user chooses to use libraries like BOSL2 or NopSCADlib they will encounter modules in those libraries that do not fit into the above framework. As previously noted, in BOSL2 every module that "draws a shape" also accepts children---with very few exceptions. It's probably a better dichotomy if you say that there are modules that REQUIRE children and then modules that do NOT require children. I suggest that if you present a classification of module types, make sure it is complete, in the sense that it covers every possible kind of module and then indicate that the NATIVE modules all fit into just these two classes, whereas modules defined by libraries or that you define yourself may fit into this or these other classes. I have no clue what you mean about preserving the state of special variables on a stack. An open brace actually does NOT create a new scope when used in isolation. You can see this by doing a=3; { a=2; echo(a); } If a new scope was created, this would run without warnings, but it gives a reassignment warning when a=2 is assigned. There was talk in the past of making isolated braces invalid, actually. If the braces are used to pass children to a parent, then they create a new scope. Hence this works: a=3; assert(true) { a=2; echo(a); } Now the stuff in braces forms children to the assert() module and it creates a new scope. When you open a new scope like this all previously existing variables are preserved, and new variables---which may have the same name and hence hide the old ones---can be created in the new scope. The same thing happens with let(). This can make it appear that you can redefine variables, like above where I "redefined" a, but it only works because the "redefinition" is in a new scope. On Sat, Aug 2, 2025 at 6:20 PM vulcan_--- via Discuss < discuss@lists.openscad.org> wrote: > thanks Adrian, for the feedback and guidance. > > i first want to check a few things with you : > > from you n other comments my breadth of language is a bit jarring for the > reader .. ok > > 1. > > object is now reserved for things made by the object() function .. > unless .. is that also a module pretending to be a function ?? > 2. > > i will use shape as the generic term for anything drawn into the model > as lines or surfaces, and thus will not use “geometry” except when talking > about math shapes that are geometrical concepts > 3. > > drawn will now be the word for making lines and surfaces appear in the > model > 4. > > rendering will be the word for processing the shapes in the model into > a human visible form, be that preview, generating an image or exporting a > file > 5. > > is children() a placeholder for the objects that the operator module > will be applied to at run-time? OR is it a funky function? or is it more of > an object module ? or is it another of the funky operators let(), assert() > etc.? > > Now the discussion for thread: > > the term “call” or “calling“ is time honored tradition to use when one > chunk of code (program, subroutine whatever) makes a reference to another > chunk of code .. be called a function, subroutine or method soo . > > if there is something really truly NOT correct about using the term > calling then i will change my approach > > BUT > > the *appearance* of the thing is that an openSCAD script can “call” > modules, be they user defined or built-in and can “call” functions in the > process of evaluating an expression with exactly the same meaning from when > FORTRAN allowed the definition of subroutines .. actually i write an > un-truth .. subroutines were available from the time the 8008 processor was > built with a “call <address>” microcode that pushed the registers onto the > stack, jumped to the <address> to continue processing until the “return” > microcode when the stack was popped to reload the registers and the program > counter reset to the instruction > > so, most / many/ some people reading the scad docs and example code > (especially!) will see modules and functions being “called“ so i propose to > keep using that language to describe code calling code > > That said; your comment raises a really valuable point .. the *effect* of > some modules is to create shapes that get placed into a hierarchy .. thus > creating parent-child relationships between shapes that have no connection > to their underlying math, nor when in the process of execution they got > created. > > To return to the syntactical issue for a sec, most people reading code > that uses braces will see them as creating lexical scope .. which is also > true in scad, right? variables defined inside of a brace pair are local to > that scope. > > IN ADDITION scad is preserving the state of special variables on the stack > to allow them to do .. well, something pretty nifty but that i don’t really > have my head around yet. > > AND IN FURTHER ADDITION braces are creating another generation of children > > first .. is this all true? pretty close? where am i still going wrong? > > back to children and parents .. so i am now planning to revise my text on > object module versus operator module to say that they are variations on the > single underlying module thing in the code. But i still feel strongly that > the conceptual separation of operator versus object will help people coming > new to the language get their head’s around it. > > That a module can BOTH draw shapes AND operate on child objects via a call > to children() is almost irrelevant to most users. There was no mention of > this in the docs before i got into them .. uhh .. at least not that i saw > .. i could have missed it. There have already been a few tiny but important > details that did get mention, but in places a bit hidden away. > > But even so .. this ability can be covered as an exception to the general > usages of modules, specifically user-defined modules, as the vast majority > of these will be Either making objects or Operating on objects. A few folks > have said stuff about BOSL2 and they way they have extended scad .. which > is all to the good .. but it is hard to program anything really complex in > scad because the fundamentals of the language are quite difference .. but > use the same syntax as C, Java etc … by which i mean the same operators, > the concept of stored routines that you call by name, functions that return > values to stand in for complex calculations .. sure looks similar .. > > i am trying to help two groups of readers > > 1. > > expert scad coders that need a language reference > 2. > > people coming to scad from other programming traditions n tech > > > > > > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org >
JB
Jon Bondy
Sun, Aug 3, 2025 1:22 AM

I share this concern.  I welcome your helpful participation, but worry
that the result may require a lot of re-work.

On 8/2/2025 8:37 PM, Adrian Mariano via Discuss wrote:

I do have a bit of a concern that you seem to be trying to (re)write
the OpenSCAD manual while having a somewhat shallow and incomplete
understanding of OpenSCAD.

--
This email has been checked for viruses by AVG antivirus software.
www.avg.com

I share this concern.  I welcome your helpful participation, but worry that the result may require a lot of re-work. On 8/2/2025 8:37 PM, Adrian Mariano via Discuss wrote: > > I do have a bit of a concern that you seem to be trying to (re)write > the OpenSCAD manual while having a somewhat shallow and incomplete > understanding of OpenSCAD. > > -- This email has been checked for viruses by AVG antivirus software. www.avg.com
JB
Jordan Brown
Sun, Aug 3, 2025 6:10 PM

[ Sigh.  I hate being away from my desktop environment.  Sorry for the
duplicate. ]

On 8/2/2025 3:20 PM, vulcan_--- via Discuss wrote:

object is now reserved for things made by the object() function ..
unless .. is that also a module pretending to be a function ??

Modules are modules and functions are functions.  There is no such thing
as one pretending to be the other.

object() is a function, period.

rendering will be the word for processing the shapes in the model into
a human visible form, be that preview, generating an image or
exporting a file

No, absolutely not.  The word "render" is well-defined in OpenSCAD to
refer to the process of reducing a model to a mesh. It most specifically
does not refer to the process of previewing a model.  Yes, abstractly
that is a form of rendering, but it is not what the word means in OpenSCAD.

is children() a placeholder for the objects that the operator module
will be applied to at run-time? OR is it a funky function? or is it
more of an object module ? or is it another of the funky operators
let(), assert() etc.?

children() is a module that invokes the operations that were passed to
the current module as its children.

As previously discussed, "operator module" and "object module" are a
false dichotomy, perhaps useful as a simple mental distinction but not
useful for formally describing OpenSCAD modules.  OpenSCAD modules may
accept zero or more children.  They may add shapes of their own, or they
may not.  They always yield a shape, though that shape may be empty. 
children() does not neatly fall into either the "operator" or "object"
classification, because it does not accept children, and does not
produce shapes of its own; it invokes the children of the current module
instantiation.

There are only three "funky operators" - let, echo, and assert - and
they only apply in expression context, just as operators like + and -
only apply in expression context.

[ "calling" ]

The debate is over what to call the relationship between A and B in

A() B();

It is formally not correct to say that that line calls B.  Nor is it
truly correct to say that A calls B.  That line calls A, which might or
might not ... invoke ... the following statement that then calls B.

But how to say that in a way that is both technically correct and is
accessible to a newbie is difficult.

actually i write an un-truth .. subroutines were available from the
time the 8008 processor was built with a “call <address>” microcode

Long, long before that.  8008 is 1970s; FORTRAN is 1950s.  I don't know
what's before that, but something is.

That said; your comment raises a really valuable point .. the /effect/
of some modules is to create shapes that get placed into a hierarchy
.. thus creating parent-child relationships between shapes that have
no connection to their underlying math, nor when in the process of
execution they got created.

Actually, the resulting CSG tree is pretty closely tied to the execution
process.

To return to the syntactical issue for a sec, most people reading code
that uses braces will see them as creating lexical scope .. which is
also true in scad, right? variables defined inside of a brace pair are
local to that scope.

Not exactly.  It's really the parent module invocation that creates the
scope.  Braces by themselves do not create scopes (sigh).

It's a little hard to see this, but let() and for() demonstrate it; they
create a scope without needing braces to do it.

IN ADDITION scad is preserving the state of special variables on the
stack to allow them to do .. well, something pretty nifty but that i
don’t really have my head around yet.

$ variables are accessible to the scope that creates them and to all
scopes called by that scope.

AND IN FURTHER ADDITION braces are creating another generation of
children

No.  Braces do not themselves create children.  Braces group children. 
If you have only one child, braces are not required.

A() { B(); }

is exactly equivalent to

A() B();

That a module can BOTH draw shapes AND operate on child objects via a
call to children() is almost irrelevant to most users.

Increasingly untrue.  These days, pretty much as soon as somebody asks a
tricky question, the answer is "go look at BOSL2, it solves that
problem"... and for BOSL2, modules that create shapes and operate on
their children are almost universal.

There was no mention of this in the docs before i got into them .. uhh
.. at least not that i saw .. i could have missed it. There have
already been a few tiny but important details that did get mention,
but in places a bit hidden away.

The core set of modules doesn't include any that create shapes and
consume children.

That only arises from the implications of children(), that there is no
reason that you can't create shapes from a module that also calls
children().

but it is hard to program anything really complex in scad because the
fundamentals of the language are quite difference

I suppose that it depends on your definition of "hard", but I think
there are at least hundreds of thousands of lines of OpenSCAD programs
that would disagree.  (I mean, I can account for over over 10K in one
project alone, and BOSL2 is 77K...)

Is it different?  Sure.  And some aspects are really tricky, probably
trickier than other languages.  But you can do something moderately
complex without needing to explore the dark corners.

Writing documentation, on the other hand, is hard, because it needs to
both correctly describe those dark corners and be accessible to
beginners.  I think the answer to that is what's sometimes called
"progressive disclosure", where you present a simplified view, and then
introduce more advanced concepts as the user progresses.

That's pretty straightforward for tutorial matter, where you control the
intended order that the user reads the documentation. It's harder for
reference material, where you don't know in advance how deep the user
wants to go.  But even then you can take care to use language that is
simple but formally correct, and to introduce simpler aspects of a
particular topic before more advanced aspects.

Some documentation I read once - I dimly think it was the TeX manual -
specifically said in its introduction that it would lie to you, that it
would give you an incorrect but simplified and useful view of a topic,
and then would later correct it with more advanced concepts.  I think
that's a useful model.

i am trying to help two groups of readers

 expert scad coders that need a language reference
 people coming to scad from other programming traditions n tech

Mostly, group 1 doesn't look at the documentation because they already
have everything in their head.

But also there's group 3:  non-programmers.  They form a significant
fraction of the user base.

Many of the concepts in this discussion, especially those around the
"child" relationship, are easier to talk about if you talk about lambda
functions... but those are a fairly advanced programming concept that
you don't really need to get into as a beginner; you can use the
mechanisms without needing to dive into that level of detail.

[ Going dark for a couple of days, en route from Scotland to Iceland. ]

[ Sigh.  I hate being away from my desktop environment.  Sorry for the duplicate. ] On 8/2/2025 3:20 PM, vulcan_--- via Discuss wrote: > > object is now reserved for things made by the object() function .. > unless .. is that also a module pretending to be a function ?? > Modules are modules and functions are functions.  There is no such thing as one pretending to be the other. object() is a function, period. > rendering will be the word for processing the shapes in the model into > a human visible form, be that preview, generating an image or > exporting a file > No, absolutely not.  The word "render" is well-defined in OpenSCAD to refer to the process of reducing a model to a mesh. It most specifically does *not* refer to the process of previewing a model.  Yes, abstractly that is a form of rendering, but it is not what the word means in OpenSCAD. > is children() a placeholder for the objects that the operator module > will be applied to at run-time? OR is it a funky function? or is it > more of an object module ? or is it another of the funky operators > let(), assert() etc.? > children() is a module that invokes the operations that were passed to the current module as its children. As previously discussed, "operator module" and "object module" are a false dichotomy, perhaps useful as a simple mental distinction but not useful for formally describing OpenSCAD modules.  OpenSCAD modules may accept zero or more children.  They may add shapes of their own, or they may not.  They always yield a shape, though that shape may be empty.  children() does not neatly fall into either the "operator" or "object" classification, because it does not accept children, and does not produce shapes of its own; it invokes the children of the current module instantiation. There are only three "funky operators" - let, echo, and assert - and they only apply in expression context, just as operators like + and - only apply in expression context. > [ "calling" ] > The debate is over what to call the relationship between A and B in A() B(); It is formally *not* correct to say that that line calls B.  Nor is it truly correct to say that A calls B.  That line calls A, which might or might not ... invoke ... the following statement that then calls B. But how to say that in a way that is both technically correct and is accessible to a newbie is difficult. > actually i write an un-truth .. subroutines were available from the > time the 8008 processor was built with a “call <address>” microcode > Long, long before that.  8008 is 1970s; FORTRAN is 1950s.  I don't know what's before that, but something is. > That said; your comment raises a really valuable point .. the /effect/ > of some modules is to create shapes that get placed into a hierarchy > .. thus creating parent-child relationships between shapes that have > no connection to their underlying math, nor when in the process of > execution they got created. > Actually, the resulting CSG tree is pretty closely tied to the execution process. > To return to the syntactical issue for a sec, most people reading code > that uses braces will see them as creating lexical scope .. which is > also true in scad, right? variables defined inside of a brace pair are > local to that scope. > Not exactly.  It's really the parent module invocation that creates the scope.  Braces by themselves do *not* create scopes (sigh). It's a little hard to see this, but let() and for() demonstrate it; they create a scope without needing braces to do it. > IN ADDITION scad is preserving the state of special variables on the > stack to allow them to do .. well, something pretty nifty but that i > don’t really have my head around yet. > $ variables are accessible to the scope that creates them and to all scopes called by that scope. > AND IN FURTHER ADDITION braces are creating another generation of > children > No.  Braces do not themselves create children.  Braces group children.  If you have only one child, braces are not required. A() { B(); } is exactly equivalent to A() B(); > That a module can BOTH draw shapes AND operate on child objects via a > call to children() is almost irrelevant to most users. > Increasingly untrue.  These days, pretty much as soon as somebody asks a tricky question, the answer is "go look at BOSL2, it solves that problem"... and for BOSL2, modules that create shapes *and* operate on their children are almost universal. > There was no mention of this in the docs before i got into them .. uhh > .. at least not that i saw .. i could have missed it. There have > already been a few tiny but important details that did get mention, > but in places a bit hidden away. > The core set of modules doesn't include any that create shapes *and* consume children. That only arises from the implications of children(), that there is no reason that you can't create shapes from a module that also calls children(). > but it is hard to program anything really complex in scad because the > fundamentals of the language are quite difference > I suppose that it depends on your definition of "hard", but I think there are at least hundreds of thousands of lines of OpenSCAD programs that would disagree.  (I mean, I can account for over over 10K in one project alone, and BOSL2 is 77K...) Is it *different*?  Sure.  And some aspects are really tricky, probably trickier than other languages.  But you can do something moderately complex without needing to explore the dark corners. Writing documentation, on the other hand, is hard, because it needs to both correctly describe those dark corners *and* be accessible to beginners.  I think the answer to that is what's sometimes called "progressive disclosure", where you present a simplified view, and then introduce more advanced concepts as the user progresses. That's pretty straightforward for tutorial matter, where you control the intended order that the user reads the documentation. It's harder for reference material, where you don't know in advance how deep the user wants to go.  But even then you can take care to use language that is simple but formally correct, and to introduce simpler aspects of a particular topic before more advanced aspects. Some documentation I read once - I dimly think it was the TeX manual - specifically said in its introduction that it would lie to you, that it would give you an incorrect but simplified and useful view of a topic, and then would later correct it with more advanced concepts.  I think that's a useful model. > i am trying to help two groups of readers > > 1. > > expert scad coders that need a language reference > > 2. > > people coming to scad from other programming traditions n tech > Mostly, group 1 doesn't look at the documentation because they already have everything in their head. But also there's group 3:  non-programmers.  They form a significant fraction of the user base. Many of the concepts in this discussion, especially those around the "child" relationship, are easier to talk about if you talk about lambda functions... but those are a fairly advanced programming concept that you don't really need to get into as a beginner; you can use the mechanisms without needing to dive into that level of detail. [ Going dark for a couple of days, en route from Scotland to Iceland. ]
V
vulcan_@mac.com
Tue, Aug 5, 2025 9:39 PM

HI Jordan .. i know it will be a while before you see this, but i wanted to reply to one small issue you raised

No, absolutely not.  The word "render" is well-defined in OpenSCAD to
refer to the process of reducing a model to a mesh. It most specifically
does not refer to the process of previewing a model.  Yes, abstractly
that is a form of rendering, but it is not what the word means in OpenSCAD.

ah .. that scad assigns that specific meaning to “render” was not made clear to my until i read your message just now.

You know that my use of render, to process a model to create an image, is the standard use in the industry, yes?

In my experience the operation of making a polygonal version of the shapes in a model is “tessellation“

I did note that the terms, if you will, of “F5” and “F6” in the documentation seemed to carry more weight than just to indicate which function key to press. But after using them both i concluded that “F6” was a short form for “tessellation“ as its operation is to divide any face with more than 3 edges into triangles.

I have learned that the result of running an scad script is a mesh .. but, at least for primitives, drawn in n-gons .. so the term rendering does not seem to apply, to me. But i bow to the linguistic convention of the group.

er .. i hope that my readers understand that i am not being facetious saying this .. my career was based on my being able to establish good communications between my teams and those around us, and within the teams themselves, by creating and promoting language specific to each project and its corporate environment.

That was what i did in every job, so i am doing it here too

HI Jordan .. i know it will be a while before you see this, but i wanted to reply to one small issue you raised > No, absolutely not.  The word "render" is well-defined in OpenSCAD to \ > refer to the process of reducing a model to a mesh. It most specifically \ > does *not* refer to the process of previewing a model.  Yes, abstractly \ > that is a form of rendering, but it is not what the word means in OpenSCAD. ah .. that scad assigns that specific meaning to “render” was not made clear to my until i read your message just now. You know that my use of render, to process a model to create an image, is the standard use in the industry, yes? In my experience the operation of making a polygonal version of the shapes in a model is “tessellation“ I did note that the terms, if you will, of “F5” and “F6” in the documentation seemed to carry more weight than just to indicate which function key to press. But after using them both i concluded that “F6” was a short form for “tessellation“ as its operation is to divide any face with more than 3 edges into triangles. I have learned that the result of running an scad script is a mesh .. but, at least for primitives, drawn in n-gons .. so the term rendering does not seem to apply, to me. But i bow to the linguistic convention of the group. er .. i hope that my readers understand that i am not being facetious saying this .. my career was based on my being able to establish good communications between my teams and those around us, and within the teams themselves, by creating and promoting language specific to each project and its corporate environment. That was what i did in every job, so i am doing it here too
V
vulcan_@mac.com
Tue, Aug 5, 2025 9:50 PM

and .. this one

OpenSCAD modules may
accept zero or more children.  They may add shapes of their own, or they
may not.  They always yield a shape, though that shape may be empty. 

First, .. what is an “empty shape“ ?

on the face of it that makes little sense. If there is nothing displayed in the preview there was no mesh made, right?

I do get, now, that a module may create shape(s) itself, or be a parent to children that may create shapes. And that a module might perform only operations like color(), translate(), assert() and the like, thus defining what i have been calling an operator module, does not create any mesh, though its children might

so how can a module always yield a shape?

and .. this one > OpenSCAD modules may \ > accept zero or more children.  They may add shapes of their own, or they \ > may not.  They always yield a shape, though that shape may be empty.  First, .. what is an “empty shape“ ? on the face of it that makes little sense. If there is nothing displayed in the preview there was no mesh made, right? I do get, now, that a module may create shape(s) itself, or be a parent to children that may create shapes. And that a module might perform only operations like color(), translate(), assert() and the like, thus defining what i have been calling an operator module, does not create any mesh, though its children might so how can a module *always* yield a shape?
V
vulcan_@mac.com
Tue, Aug 5, 2025 10:05 PM

i hope to get to alignment on terminology with respect to the roles of functions and modules in a scad.

in this statement:

xx = do_something( 12 );

        ^ this is a call to a function, there are no children

do_operation() make_shape();

  ^ this and       ^  this are both calls to modules

 ^ this is the parent of ^ this child, by the syntax of it following the call to `do_operation()`

I am using the terms “call” and “calling“ to refer to the execution of a module during the execution of a script, which is industry standard as far as i know.

What was not clear to me was that a sequence of module calls in a single statement is the syntax for defining a nested parent-child shape that will be “rendered” as a mesh as a part of the model the script is drawing. But now it is and i am updating the docs to express my improved understanding

i hope to get to alignment on terminology with respect to the roles of functions and modules in a scad. in this statement: `xx = do_something( 12 );` ^ this is a call to a function, there are no children `do_operation() make_shape();` ^ this and ^ this are both calls to modules ^ this is the parent of ^ this child, by the syntax of it following the call to `do_operation()` I am using the terms “call” and “calling“ to refer to the execution of a module during the execution of a script, which is industry standard as far as i know. What was not clear to me was that a sequence of module calls in a single statement is the syntax for defining a nested parent-child shape that will be “rendered” as a mesh as a part of the model the script is drawing. But now it is and i am updating the docs to express my improved understanding
NH
nop head
Tue, Aug 5, 2025 10:05 PM

If you intersect two shapes that don't overlap or difference a shape that
completely overlaps the first operand, then you get an empty shape. It is
an empty geometry object.

All modules return a shape, but it may be empty.

On Tue, 5 Aug 2025, 22:51 vulcan_--- via Discuss, <
discuss@lists.openscad.org> wrote:

and .. this one

OpenSCAD modules may
accept zero or more children.  They may add shapes of their own, or they
may not.  They always yield a shape, though that shape may be empty.

First, .. what is an “empty shape“ ?

on the face of it that makes little sense. If there is nothing displayed
in the preview there was no mesh made, right?

I do get, now, that a module may create shape(s) itself, or be a parent to
children that may create shapes. And that a module might perform only
operations like color(), translate(), assert() and the like, thus defining
what i have been calling an operator module, does not create any mesh,
though its children might

so how can a module always yield a shape?


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

If you intersect two shapes that don't overlap or difference a shape that completely overlaps the first operand, then you get an empty shape. It is an empty geometry object. All modules return a shape, but it may be empty. On Tue, 5 Aug 2025, 22:51 vulcan_--- via Discuss, < discuss@lists.openscad.org> wrote: > and .. this one > > OpenSCAD modules may > accept zero or more children. They may add shapes of their own, or they > may not. They always yield a shape, though that shape may be empty. > > First, .. what is an “empty shape“ ? > > on the face of it that makes little sense. If there is nothing displayed > in the preview there was no mesh made, right? > > I do get, now, that a module may create shape(s) itself, or be a parent to > children that may create shapes. And that a module might perform only > operations like color(), translate(), assert() and the like, thus defining > what i have been calling an operator module, does not create any mesh, > though its children might > > so how can a module *always* yield a shape? > > > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org >
V
vulcan_@mac.com
Tue, Aug 5, 2025 10:10 PM

ah .. that leads me to ask, why bother? if there is no geometry created by a module, thus no change to any part of a mesh that might already exist in the model, why retain anything of the operation that effectively did nothing?

ah .. that leads me to ask, why bother? if there is no geometry created by a module, thus no change to any part of a mesh that might already exist in the model, why retain anything of the operation that effectively did nothing?
NH
nop head
Tue, Aug 5, 2025 10:14 PM

An empty geometry object has to exist because some CGS operations may
result in one.

In the case of  do_operation() make_shape();

do_operation() is instantiated, but it may or may not instantiate
make_shape();

On Tue, 5 Aug 2025 at 23:10, vulcan_--- via Discuss <
discuss@lists.openscad.org> wrote:

ah .. that leads me to ask, why bother? if there is no geometry created by
a module, thus no change to any part of a mesh that might already exist in
the model, why retain anything of the operation that effectively did
nothing?


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

An empty geometry object has to exist because some CGS operations may result in one. In the case of do_operation() make_shape(); do_operation() is instantiated, but it may or may not instantiate make_shape(); On Tue, 5 Aug 2025 at 23:10, vulcan_--- via Discuss < discuss@lists.openscad.org> wrote: > ah .. that leads me to ask, why bother? if there is no geometry created by > a module, thus no change to any part of a mesh that might already exist in > the model, why retain anything of the operation that effectively did > nothing? > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org >
V
vulcan_@mac.com
Tue, Aug 5, 2025 10:19 PM

thanks for patiently answering my incessant questions .. enlightenment is as hard a road for the teacher as the student.

i am grateful

thanks for patiently answering my incessant questions .. enlightenment is as hard a road for the teacher as the student. i am grateful
NH
nop head
Tue, Aug 5, 2025 10:36 PM

if() is a module that may or may not invoke its child. If the expressions
is false then the child is never called and may even have errors in it. An
empty geometry object has to be return because it might be part of say a
difference() or a union().

On Tue, 5 Aug 2025 at 23:19, vulcan_--- via Discuss <
discuss@lists.openscad.org> wrote:

thanks for patiently answering my incessant questions .. enlightenment is
as hard a road for the teacher as the student.

i am grateful


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

if() is a module that may or may not invoke its child. If the expressions is false then the child is never called and may even have errors in it. An empty geometry object has to be return because it might be part of say a difference() or a union(). On Tue, 5 Aug 2025 at 23:19, vulcan_--- via Discuss < discuss@lists.openscad.org> wrote: > thanks for patiently answering my incessant questions .. enlightenment is > as hard a road for the teacher as the student. > > i am grateful > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org >
JB
Jordan Brown
Wed, Aug 6, 2025 3:44 AM

ah .. that leads me to ask, why bother? if there is no geometry created by a module, thus no change to any part of a mesh that might already exist in the model, why retain anything of the operation that effectively did nothing?

This is why the invention of the zero was so important. Mostly :-) but only mostly.

Let’s talk about lists.

Suppose that we have a list [a,b]. Now take away the last element; what is the result? You might reasonably say “a”, and I’ve seen environments that did that, but it’s a nuisance because list operations like iteration and concatenations may not work well on a non-list. (Or may do something totally unexpected if “a” itself is a list.) The answer really needs to be [a], a list of one element.

Now take away the first element of that list. What do you have? You might say “nothing” or “null” or “undefined”, and I have seen environments that do that, but again it’s inconvenient because list operations will not work. You want the answer to be [], the empty list. You can hand it around and you can do all of the usual list-y operations to it, and they work sensibly.

Now let’s go back to OpenSCAD shapes.

Suppose that we have this module:

module empty () {
}

What does it produce?

If you say that it produces nothing at all, not even emptiness, that things should work as if it was not even there, then what does this yield?

difference () {
empty ();
cube(10);
}

I would hope that the answer is never “a cube”.

Perhaps more real-world, consider this module:

module maybe_sphere(f) {
if (f) sphere (10);
}

If that didn’t always produce a shape, perhaps an empty shape, it would be very hard to use. There would be lots of cases where the caller would have to somehow know whether it was going to produce something, and treat it specially if not.

It only gets worse when you start introducing other OpenSCAD semantics.

What does this print?

module how_many_children() {
echo ($children);
}
how_many_children() {
maybe_sphere(rands(0,2,1)[0] > 1);
}

If maybe_sphere() should effectively disappear when it generates nothing, then the answer should be either zero or one, but (for very useful reasons) OpenSCAD doesn’t evaluate the children until the module calls children(), so the answer is not knowable.

Net, for the same basic reasons that zero, empty lists, empty sets, and empty strings are valuable and even essential, empty shapes are valuable and even essential.

> ah .. that leads me to ask, why bother? if there is no geometry created by a module, thus no change to any part of a mesh that might already exist in the model, why retain anything of the operation that effectively did nothing? This is why the invention of the zero was so important. Mostly :-) but only mostly. Let’s talk about lists. Suppose that we have a list [a,b]. Now take away the last element; what is the result? You might reasonably say “a”, and I’ve seen environments that did that, but it’s a nuisance because list operations like iteration and concatenations may not work well on a non-list. (Or may do something totally unexpected if “a” itself is a list.) The answer really needs to be [a], a list of one element. Now take away the first element of that list. What do you have? You might say “nothing” or “null” or “undefined”, and I have seen environments that do that, but again it’s inconvenient because list operations will not work. You want the answer to be [], the empty list. You can hand it around and you can do all of the usual list-y operations to it, and they work sensibly. Now let’s go back to OpenSCAD shapes. Suppose that we have this module: module empty () { } What does it produce? If you say that it produces nothing at all, not even emptiness, that things should work as if it was not even there, then what does this yield? difference () { empty (); cube(10); } I would hope that the answer is never “a cube”. Perhaps more real-world, consider this module: module maybe_sphere(f) { if (f) sphere (10); } If that didn’t *always* produce a shape, perhaps an empty shape, it would be very hard to use. There would be lots of cases where the caller would have to somehow know whether it was going to produce something, and treat it specially if not. It only gets worse when you start introducing other OpenSCAD semantics. What does this print? module how_many_children() { echo ($children); } how_many_children() { maybe_sphere(rands(0,2,1)[0] > 1); } If maybe_sphere() should effectively disappear when it generates nothing, then the answer should be either zero or one, but (for very useful reasons) OpenSCAD doesn’t evaluate the children until the module calls children(), so the answer is not knowable. Net, for the same basic reasons that zero, empty lists, empty sets, and empty strings are valuable and even essential, empty shapes are valuable and even essential.
JB
Jordan Brown
Wed, Aug 6, 2025 4:42 AM

In my experience the operation of making a polygonal version of the shapes in a model is “tessellation“

This usage of “tessellation” does not seem to appear in https://en.m.wikipedia.org/wiki/Tessellation .

Tessellation is the process of fitting shapes into other shapes - often, covering an infinite plane with a pattern of shapes. It has nothing to do with things like transformations and Boolean operations, which are what the OpenSCAD rendering process does. If the OpenSCAD rendering process does tessellation, it’s an implementation detail subject to change at any time for any reason or no reason.

I agree that “rendering” in the broader industry often means generating an image, though I think it usually means generating a final image - I don’t think that CGI people call it “rendering” when they generate stick-figure visualizations; they mean the compute-intensive process of producing the final image.

But, expect for the “producing the final result” connotation, that’s not what it means here, and for better or worse the local definition is unlikely to change.

I did note that the terms, if you will, of “F5” and “F6” in the documentation seemed to carry more weight than just to indicate which function key to press.

You do know that they are short cuts for the Preview and Render menu items, right?
(I might have the exact words wrong, because I’m not in front of a computer, but it’s something like that.)

But after using them both i concluded that “F6” was a short form for “tessellation“ as its operation is to divide any face with more than 3 edges into triangles.

No, not at all. Again, if that happens it is an implementation detail subject to change at any time.

OpenSCAD rendering is the process of doing all of the operations required to yield a single (perhaps discontiguous) mesh. Concretely, given this script:

difference() {
cube(10);
translate ([5,5,5]) cube(10);
}

It is the process that turns those twenty-four edges and twelve faces into the resulting nine faces and fourteen edges. (If I’ve counted in my head correctly.)

It may, or may not, further divide those faces into triangles.

It may, in fact, do anything it feels like, as long as the result describes the correct closed shape.

(And, less commonly used but still entirely valid, given a 2D model it yields a set of polygons.)

I have learned that the result of running an scad script is a mesh

Maybe, maybe not. Sometimes it’s a mesh, sometimes it’s an image, sometimes it’s polygons, sometimes it’s text. It depends on the script and how it’s run.

If, and only if, you use the Render (F6) operation, or its CLI equivalent,  the result is a mesh. (NB: not the render() module; that does not affect whether the final result is a mesh.) (Or, for a 2D model, a set of polygons.)

> In my experience the operation of making a polygonal version of the shapes in a model is “tessellation“ This usage of “tessellation” does not seem to appear in https://en.m.wikipedia.org/wiki/Tessellation . Tessellation is the process of fitting shapes into other shapes - often, covering an infinite plane with a pattern of shapes. It has nothing to do with things like transformations and Boolean operations, which are what the OpenSCAD rendering process does. If the OpenSCAD rendering process does tessellation, it’s an implementation detail subject to change at any time for any reason or no reason. I agree that “rendering” in the broader industry often means generating an image, though I think it usually means generating a *final* image - I don’t think that CGI people call it “rendering” when they generate stick-figure visualizations; they mean the compute-intensive process of producing the final image. But, expect for the “producing the final result” connotation, that’s not what it means here, and for better or worse the local definition is unlikely to change. > I did note that the terms, if you will, of “F5” and “F6” in the documentation seemed to carry more weight than just to indicate which function key to press. > You do know that they are short cuts for the Preview and Render menu items, right? (I might have the exact words wrong, because I’m not in front of a computer, but it’s something like that.) > But after using them both i concluded that “F6” was a short form for “tessellation“ as its operation is to divide any face with more than 3 edges into triangles. > No, not at all. Again, if that happens it is an implementation detail subject to change at any time. OpenSCAD rendering is the process of doing all of the operations required to yield a single (perhaps discontiguous) mesh. Concretely, given this script: difference() { cube(10); translate ([5,5,5]) cube(10); } It is the process that turns those twenty-four edges and twelve faces into the resulting nine faces and fourteen edges. (If I’ve counted in my head correctly.) It may, or may not, further divide those faces into triangles. It may, in fact, do anything it feels like, as long as the result describes the correct closed shape. (And, less commonly used but still entirely valid, given a 2D model it yields a set of polygons.) > I have learned that the result of running an scad script is a mesh > Maybe, maybe not. Sometimes it’s a mesh, sometimes it’s an image, sometimes it’s polygons, sometimes it’s text. It depends on the script and how it’s run. If, and only if, you use the Render (F6) operation, or its CLI equivalent, the result is a mesh. (NB: not the render() module; that does not affect whether the final result is a mesh.) (Or, for a 2D model, a set of polygons.)
JB
Jordan Brown
Wed, Aug 6, 2025 5:00 AM



i hope to get to alignment on terminology with respect to the roles of functions and modules in a scad.

in this statement:

xx = do_something( 12 );

^ this is a call to a function, there are no children

do_operation() make_shape();

^ this and ^ this are both calls to modules

^ this is the parent of ^ this child, by the syntax of it following the call to do_operation()

Yes. Give or take the discuss of “call” below.

I am using the terms “call” and “calling“ to refer to the execution of a module during the execution of a script, which is industry standard as far as i know.

Yes, but there are important questions around what calls what, and when, and how that is described to the user.

For a beginning user, it is probably best to think of

rotate(45) cube(10);

as calling cube() to create a cube, and passing the result to rotate() to rotate it.

And you can use mental model for quite a while, even when you start to write modules that take children of their own.

But it’s false.

What actually happens is that it calls the rotate() module and passes the “cube(10)” statement to it, and rotate() evaluates that statement, rotates the result, and yields the rotated result.

But that’s a way more complex mental model than a beginner, or even an intermediate, really needs.

So the trick is in how to start out with the simpler mental model and eventually introduce the more complex and correct model, without totally confusing the user.

What was not clear to me was that a sequence of module calls in a single statement is the syntax for defining a nested parent-child shape that will be “rendered” as a mesh as a part of the model the script is drawing.

That seems like a pretty serious failure of the tutorial matter, since that’s the most fundamental building block of the entire language. (You did read the tutorial matter before the reference manual, right?)

 > i hope to get to alignment on terminology with respect to the roles of functions and modules in a scad. > > in this statement: > > xx = do_something( 12 ); > > ^ this is a call to a function, there are no children > > do_operation() make_shape(); > > ^ this and ^ this are both calls to modules > > ^ this is the parent of ^ this child, by the syntax of it following the call to do_operation() > Yes. Give or take the discuss of “call” below. > I am using the terms “call” and “calling“ to refer to the execution of a module during the execution of a script, which is industry standard as far as i know. > Yes, but there are important questions around what calls what, and when, and how that is described to the user. For a beginning user, it is probably best to think of rotate(45) cube(10); as calling cube() to create a cube, and passing the result to rotate() to rotate it. And you can use mental model for quite a while, even when you start to write modules that take children of their own. But it’s false. What actually happens is that it calls the rotate() module and passes the “cube(10)” statement to it, and rotate() evaluates that statement, rotates the result, and yields the rotated result. But that’s a way more complex mental model than a beginner, or even an intermediate, really needs. So the trick is in how to start out with the simpler mental model and eventually introduce the more complex and correct model, without totally confusing the user. > What was not clear to me was that a sequence of module calls in a single statement is the syntax for defining a nested parent-child shape that will be “rendered” as a mesh as a part of the model the script is drawing. > That seems like a pretty serious failure of the tutorial matter, since that’s the most fundamental building block of the entire language. (You did read the tutorial matter before the reference manual, right?)
P
pca006132
Wed, Aug 6, 2025 6:03 AM

After following the recent discussions and reading the current version of
the wiki, I have several major concerns here.

  1. One should not attempt to infer the API contract from the behavior.
    Implementation is subject to changes and may be incorrect. If you learn the
    API specification from the implementation behavior, you overfit. And you
    will miss subtle behaviors like what Jordan mentioned, which affect how
    special variable values are resolved.
  2. Terminologies are all messed up in the new version of the reference
    manual. The term "object" can refer to anything in
    https://en.m.wikibooks.org/wiki/OpenSCAD_User_Manual/User-Defined_Functions_and_Modules.
    In the old version of the language reference, it refers to geometries. The
    "named object" naming rule thing is just a rule about valid identifiers, it
    is not like we need a new name for it. And in
    https://en.m.wikibooks.org/wiki/OpenSCAD_User_Manual/General at the start,
    I have no idea what it means by "named operations". I don't think
    "manipulate" or "modify" are good words either: we never modify things
    in-place, we just get a new transformed version.
  3. I don't think the current version (or the old version) is an appropriate
    language reference manual. They are too verbose and not detailed enough.
    For example, for generating regular polygons using circle with $fn, what is
    the orientation of the polygon? When are child geometries evaluated, i.e.
    the thing Jordan mentioned above. What happen when we union 2D and 3D
    objects together? What is a valid expression? These are not answered. Also,
    for deprecation or experimental features, we should have a more uniform way
    of showing them, such as the style in cppreference.

While I appreciate Vulcan's hard work, I don't think the current rewrite
works.

Best,
John

On Wed, Aug 6, 2025 at 1:01 PM Jordan Brown via Discuss <
discuss@lists.openscad.org> wrote:



i hope to get to alignment on terminology with respect to the roles of
functions and modules in a scad.

in this statement:

xx = do_something( 12 );

^ this is a call to a function, there are no children

do_operation() make_shape();

^ this and ^ this are both calls to modules

^ this is the parent of ^ this child, by the syntax of it following the
call to do_operation()

Yes. Give or take the discuss of “call” below.

I am using the terms “call” and “calling“ to refer to the execution of a
module during the execution of a script, which is industry standard as far
as i know.

Yes, but there are important questions around what calls what, and when,
and how that is described to the user.

For a beginning user, it is probably best to think of

rotate(45) cube(10);

as calling cube() to create a cube, and passing the result to rotate() to
rotate it.

And you can use mental model for quite a while, even when you start to
write modules that take children of their own.

But it’s false.

What actually happens is that it calls the rotate() module and passes the
“cube(10)” statement to it, and rotate() evaluates that statement, rotates
the result, and yields the rotated result.

But that’s a way more complex mental model than a beginner, or even an
intermediate, really needs.

So the trick is in how to start out with the simpler mental model and
eventually introduce the more complex and correct model, without totally
confusing the user.

What was not clear to me was that a sequence of module calls in a single
statement is the syntax for defining a nested parent-child shape that will
be “rendered” as a mesh as a part of the model the script is drawing.

That seems like a pretty serious failure of the tutorial matter, since
that’s the most fundamental building block of the entire language. (You did
read the tutorial matter before the reference manual, right?)


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

After following the recent discussions and reading the current version of the wiki, I have several major concerns here. 1. One should not attempt to infer the API contract from the behavior. Implementation is subject to changes and may be incorrect. If you learn the API specification from the implementation behavior, you overfit. And you will miss subtle behaviors like what Jordan mentioned, which affect how special variable values are resolved. 2. Terminologies are all messed up in the new version of the reference manual. The term "object" can refer to anything in https://en.m.wikibooks.org/wiki/OpenSCAD_User_Manual/User-Defined_Functions_and_Modules. In the old version of the language reference, it refers to geometries. The "named object" naming rule thing is just a rule about valid identifiers, it is not like we need a new name for it. And in https://en.m.wikibooks.org/wiki/OpenSCAD_User_Manual/General at the start, I have no idea what it means by "named operations". I don't think "manipulate" or "modify" are good words either: we never modify things in-place, we just get a new transformed version. 3. I don't think the current version (or the old version) is an appropriate language reference manual. They are too verbose and not detailed enough. For example, for generating regular polygons using circle with $fn, what is the orientation of the polygon? When are child geometries evaluated, i.e. the thing Jordan mentioned above. What happen when we union 2D and 3D objects together? What is a valid expression? These are not answered. Also, for deprecation or experimental features, we should have a more uniform way of showing them, such as the style in cppreference. While I appreciate Vulcan's hard work, I don't think the current rewrite works. Best, John On Wed, Aug 6, 2025 at 1:01 PM Jordan Brown via Discuss < discuss@lists.openscad.org> wrote: >  > > i hope to get to alignment on terminology with respect to the roles of > functions and modules in a scad. > > in this statement: > > xx = do_something( 12 ); > > ^ this is a call to a function, there are no children > > do_operation() make_shape(); > > ^ this and ^ this are both calls to modules > > ^ this is the parent of ^ this child, by the syntax of it following the > call to do_operation() > > > Yes. Give or take the discuss of “call” below. > > I am using the terms “call” and “calling“ to refer to the execution of a > module during the execution of a script, which is industry standard as far > as i know. > > > Yes, but there are important questions around what calls what, and when, > and how that is described to the user. > > For a beginning user, it is probably best to think of > > rotate(45) cube(10); > > as calling cube() to create a cube, and passing the result to rotate() to > rotate it. > > And you can use mental model for quite a while, even when you start to > write modules that take children of their own. > > But it’s false. > > What actually happens is that it calls the rotate() module and passes the > “cube(10)” statement to it, and rotate() evaluates that statement, rotates > the result, and yields the rotated result. > > But that’s a way more complex mental model than a beginner, or even an > intermediate, really needs. > > So the trick is in how to start out with the simpler mental model and > eventually introduce the more complex and correct model, without totally > confusing the user. > > What was not clear to me was that a sequence of module calls in a single > statement is the syntax for defining a nested parent-child shape that will > be “rendered” as a mesh as a part of the model the script is drawing. > > > That seems like a pretty serious failure of the tutorial matter, since > that’s the most fundamental building block of the entire language. (You did > read the tutorial matter before the reference manual, right?) > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org >
V
vulcan_@mac.com
Wed, Aug 6, 2025 6:41 AM

Hi Jordan

you said this:

This usage of “tessellation” does not seem to appear in https://en.m.wikipedia.org/wiki/Tessellation .

correct, my usage of “tessellation“ comes from talking about rendering issues in long sequence animations for the movie industry with the folks developing / maintaining the render engines for Alias|wavefront Power Animator, Maya and the wavefront tool chain .. all of whom gleefully plucked the word from its correct use as a math term and applied it to
mean “Map all the NURBs in a model into their equivalent mesh so that we can make pictures with it”

The wiki page you cite is correct in another context. And it is even possible that the render gods of A|w were simplifying things in their explanations of the many things that could produce unwanted artifacts in a rendered image to me and so i may have misunderstood what they meant by “tessellation“ too.

—-

about “calling” a subroutine, with ref to your kind reply:

rotate(45) cube(10);

as calling cube() to create a cube, and passing the result to rotate() to rotate it.

if we could agree that the term “call a module” to mean:  ( using cube(10) as the example)

jump to the chunk of code labeled cube() passing its defined argument list with default values except size=45
execute that code and then return

in your example cube() is not in the parameter list of the call to rotate(), so i do not like to say it is “passed” to rotate()

My new understanding of the module’s syntax is that it includes a following child module, thus the definition of a statement’s syntax when a module is being called is (hacking BNF brutally) :

module <name>( <arg>* ) [ | child_module()* | {<statement>* } ];

meaning that the following child can be omitted, a call to another module, or a block of code within braces (using ‘|’ to separate alternatives). Textually this parallels how a procedural language builds a program’s structure in preparation for execution .. and no, the tutorials do not do enough to help a guy from that sort of background learn the very different approach of 1. a functional language and 2. scad’s use of a sequence of module calls and blocks in a statement to define an element of a model

and finally, no - of course i did not read the tutorials. I need to 3D print some small gears and google found me some FreeCAD extensions, websites, stand-alone programs, and several OpenSCAD libraries .. so i took a look at the ones that seemed to do what i needed .. one of the most accessible was an scad script that had been adapted (upgraded?) from the original version on Thingverse, which was in German. So what does any Real Programmer do? That is right!

One downloads the code to start hacking it to understand it, “improving it” as i go, translating to english and studying up on gear terminology and when the bits i touched broke .. being dissatisfied with the scad docs so that of course i had to  write a few dozen text and example scripts to test the details of syntax etc.

Finding BOSL2 too complex for what i was trying to do .. so finding stuff i could used in the relativity library .. but not really understanding some things its code was doing ..  more experimenting revealed flaws in the docs .. which as a Wikiverse contributor i could actually fix

well and truly a rabbit hole into which i jumped. I think you know how that happens, yes?

Hi Jordan you said this: > This usage of “tessellation” does not seem to appear in <https://en.m.wikipedia.org/wiki/Tessellation> . correct, my usage of “tessellation“ comes from talking about rendering issues in long sequence animations for the movie industry with the folks developing / maintaining the render engines for Alias|wavefront Power Animator, Maya and the wavefront tool chain .. all of whom gleefully plucked the word from its correct use as a math term and applied it to\ mean “Map all the NURBs in a model into their equivalent mesh so that we can make pictures with it” The wiki page you cite is correct in another context. And it is even possible that the render gods of A|w were simplifying things in their explanations of the many things that could produce unwanted artifacts in a rendered image to me and so i may have misunderstood what they meant by “tessellation“ too. —- about “calling” a subroutine, with ref to your kind reply: > rotate(45) cube(10); > > as calling cube() to create a cube, and passing the result to rotate() to rotate it. if we could agree that the term “call a module” to mean: ( using cube(10) as the example) > jump to the chunk of code labeled cube() passing its defined argument list with default values except size=45\ > execute that code and then return in your example cube() is not in the parameter list of the call to rotate(), so i do not like to say it is “passed” to rotate() My new understanding of the module’s syntax is that it includes a following child module, thus the definition of a statement’s syntax when a module is being called is (hacking BNF brutally) : > module <name>( <arg>\* ) \[ | child_module()\* | {<statement>\* } \]; meaning that the following child can be omitted, a call to another module, or a block of code within braces (using ‘|’ to separate alternatives). *Textually* this parallels how a procedural language builds a program’s structure in preparation for execution .. and no, the tutorials do not do enough to help a guy from that sort of background learn the very different approach of 1. a functional language and 2. scad’s use of a sequence of module calls and blocks in a statement to define an element of a model and finally, no - *of course* i did *not* read the tutorials. I need to 3D print some small gears and google found me some FreeCAD extensions, websites, stand-alone programs, and several OpenSCAD libraries .. so i took a look at the ones that seemed to do what i needed .. one of the most accessible was an scad script that had been adapted (upgraded?) from the original version on Thingverse, which was in German. So what does any Real Programmer do? That is right! One downloads the code to start hacking it to understand it, “improving it” as i go, translating to english and studying up on gear terminology and when the bits i touched broke .. being dissatisfied with the scad docs so that *of course* i had to write a few dozen text and example scripts to test the details of syntax etc. Finding BOSL2 too complex for what i was trying to do .. so finding stuff i could used in the relativity library .. but not really understanding some things its code was doing .. more experimenting revealed flaws in the docs .. which as a Wikiverse contributor i could actually fix well and truly a rabbit hole into which i jumped. I think you know how that happens, yes?
V
vulcan_@mac.com
Wed, Aug 6, 2025 7:51 AM

pca006132 wrote:

After following the recent discussions and reading the current version of
the wiki, I have several major concerns here.

you are giving me the feedback i crave PCA, thanks

  1. One should not attempt to infer the API contract from the behavior.

umm .. then how better to understand it? the docs and tutorials did not do enough so i started to experiment to see how things worked. I have dozens of test and example code snippets to back up what i write about how scad works ..

that said: feedback from you and others has already led me closer to the One True Way of SCAD and i continue to enshrine the revealed wisdom in updates to the docs

you overfit.

i am not at all clear what overfit means .. if you mean i try to understand scad in the context of my own experience but not knowing enough in the context of SCAD i get things wrong .. yep, that is why we write in a wiki, and have this forum - for you folks to educate me. I am happy to do the grunt work of docs updates .. i enjoy getting an explanation correct and helping others along the road to enlightenment.

special variable values are resolved.

Yeah, specials are still a fuzzy thing for me .. even after Jordan’s diligent attempt to educate me on how they work i am not at all clear on what they bring to the language that is any different from having global variables at the top level of scope

  1. Terminologies are all messed up in the new version of the reference manual. The term "object" can refer to anything in … "manipulate" or "modify" are good words either: we never modify things in-place, we just get a new transformed version.

I am in the process of fixing these terminology issues .. in a previous post i published the glossary i am now working with

  1. I don't think the current version (or the old version) is an appropriate
    language reference manual.

if you take a look at the new pages i am happiest with you will see that i am trying to answer the questions you raised. I too found the old docs imprecise and in a few places contradictory

for instance, i spent time to make this update to the page on 2D primitives

and i had done a complete rewrite of the page on operators in my sandbox to incorporate input i had from others, notably Jordan, and my observations of how they work.

While I appreciate Vulcan's hard work, I don't think the current rewrite
works.

how we move forward is up to the community - if you folks are willing to keep giving me feedback on what is broken / wrong / needs improving then i will keep working to make it all come good.

If not .. it is a wiki .. everyone is free to correct what they find to be wrong .. or even just revert it all back to early April when i started

Best,
John

Thanks John, for your input

pca006132 wrote: > After following the recent discussions and reading the current version of > the wiki, I have several major concerns here. you are giving me the feedback i crave PCA, thanks > 1. One should not attempt to infer the API contract from the behavior. umm .. then how better to understand it? the docs and tutorials did not do enough so i started to experiment to see how things worked. I have dozens of test and example code snippets to back up what i write about how scad works .. that said: feedback from you and others has already led me closer to the One True Way of SCAD and i continue to enshrine the revealed wisdom in updates to the docs > you overfit. i am not at all clear what overfit means .. if you mean i try to understand scad in the context of my own experience but not knowing enough in the context of SCAD i get things wrong .. yep, that is why we write in a wiki, and have this forum - for you folks to educate me. I am happy to do the grunt work of docs updates .. i enjoy getting an explanation correct and helping others along the road to enlightenment. > special variable values are resolved. Yeah, specials are still a fuzzy thing for me .. even after Jordan’s diligent attempt to educate me on how they work i am not at all clear on what they bring to the language that is any different from having global variables at the top level of scope > 1. Terminologies are all messed up in the new version of the reference manual. The term "object" can refer to anything in … "manipulate" or "modify" are good words either: we never modify things in-place, we just get a new transformed version. I am in the process of fixing these terminology issues .. in a previous post i [published the glossary i am now working with](https://en.wikibooks.org/wiki/User:VulcanWikiEdit/sandbox/SCADGlossary) > 1. I don't think the current version (or the old version) is an appropriate > language reference manual. if you take a look at the new pages i am happiest with you will see that i am trying to answer the questions you raised. I too found the old docs imprecise and in a few places contradictory for instance, i spent time to make this [update to the page on 2D primitives](https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Using_the_2D_Subsystem) and i had done a complete rewrite of [the page on operators in my sandbox](https://en.wikibooks.org/wiki/User:VulcanWikiEdit/sandbox/Operators_Discussion) to incorporate input i had from others, notably Jordan, and my observations of how they work. > While I appreciate Vulcan's hard work, I don't think the current rewrite > works. how we move forward is up to the community - if you folks are willing to keep giving me feedback on what is broken / wrong / needs improving then i will keep working to make it all come good. If not .. it is a wiki .. everyone is free to correct what they find to be wrong .. or even just revert it all back to early April when i started > Best, > John Thanks John, for your input
V
vulcan_@mac.com
Wed, Aug 6, 2025 7:56 AM

drat .. the links i pasted into my reply to john are not visible. I repeat them here

glossary https://en.wikibooks.org/wiki/User:VulcanWikiEdit/sandbox/SCADGlossary

updated page i am happy with ( and answers some of the issues John raised)

https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Using_the_2D_Subsystem

and a complete rewrite of the page on Operators ( + - * ?: etc) that is still in my sandbox

https://en.wikibooks.org/wiki/User:VulcanWikiEdit/sandbox/Operators_Discussion

drat .. the links i pasted into my reply to john are not visible. I repeat them here glossary https://en.wikibooks.org/wiki/User:VulcanWikiEdit/sandbox/SCADGlossary updated page i am happy with ( and answers some of the issues John raised) https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Using_the_2D_Subsystem and a complete rewrite of the page on Operators ( + - \* ?: etc) that is still in my sandbox https://en.wikibooks.org/wiki/User:VulcanWikiEdit/sandbox/Operators_Discussion
JB
Jordan Brown
Wed, Aug 6, 2025 11:02 AM

rotate(45) cube(10);

as calling cube() to create a cube, and passing the result to rotate() to rotate it.

if we could agree that the term “call a module” to mean: ( using cube(10) as the example)

jump to the chunk of code labeled cube() passing its defined argument list with default values except size=45
execute that code and then return

Sure.

in your example cube() is not in the parameter list of the call to rotate(), so i do not like to say it is “passed” to rotate()

Weeeeellllll…. It kind of is in the parameter list. There are two parameter lists. One is a conventional parameter list. The other is the child list, which in this case has a single entry and so does not need braces, but could have multiple entries surrounded by braces.

I’m happy with saying that cube() probably ends up being called. The questions are what calls it, and when.

The simple mental model says that it’s called by the top level, and the result passed to rotate(). But that’s not correct, or not exactly correct. What’s passed down to rotate() is the list of child statements, rotate() evaluates those statements, and that evaluation leads to cube() being called.

My new understanding of the module’s syntax is that it includes a following child module,

It’s best that when you’re being formal you distinguish between a module instantiation (or perhaps “call” or “invocation”) and a module definition. I believe that you’re referring to a module instantiation here.

thus the definition of a statement’s syntax when a module is being called is (hacking BNF brutally) :

module <name>( <arg>* ) [ | child_module()* | {<statement>* } ];

The keyword “module” indicates a module definition. It is roughly akin to “def” in Python or “function” in JavaScript.

The syntax of the body of a module is very similar to the syntax of a statement. (I think it might be identical, but don’t want to go check the parser right now.).

I think you’re trying to describe a module instantiation, so let’s drop “module”:

<name>( <arg>* ) [ | child_module()* | {<statement>* } ];

I assume that you are using brackets to indicate grouping for the | alternatives, rather than to indicate optionality.

A semicolon is not used after a brace-enclosed list, and the * on child_module() includes the case of zero so you don’t need the empty case.

Also, “<arg>” doesn’t describe argument list syntax correctly, so let’s just push the details down into a separate and not-defined-here level.  Net, next draft:
<name>( <args> ) [ child_module()
; | {<statement>* } ]

But that’s not quite right, because the last child module installation can have a brace-enclosed list.  I think you could syntactically describe it as

<name>( <args>) child_module()* [ ; | {<statement>* } ]

But that’s not really the best representation, because it does not represent the nesting.

Best is probably a recursive definition, something like:

module_instantiation:

<name>(<args>);

| <name>(<args>) <module_instantiation>

| <name>(<args>) { <statement>* }

But for the formally correct definition, refer to the parser, src/core/parser.y.

> rotate(45) cube(10); > > as calling cube() to create a cube, and passing the result to rotate() to rotate it. > > if we could agree that the term “call a module” to mean: ( using cube(10) as the example) > > jump to the chunk of code labeled cube() passing its defined argument list with default values except size=45 > execute that code and then return > Sure. > in your example cube() is not in the parameter list of the call to rotate(), so i do not like to say it is “passed” to rotate() > Weeeeellllll…. It kind of *is* in the parameter list. There are *two* parameter lists. One is a conventional parameter list. The other is the child list, which in this case has a single entry and so does not need braces, but could have multiple entries surrounded by braces. I’m happy with saying that cube() probably ends up being called. The questions are what calls it, and when. The simple mental model says that it’s called by the top level, and the result passed to rotate(). But that’s not correct, or not exactly correct. What’s passed down to rotate() is the list of child statements, rotate() evaluates those statements, and that evaluation leads to cube() being called. > My new understanding of the module’s syntax is that it includes a following child module, > It’s best that when you’re being formal you distinguish between a module instantiation (or perhaps “call” or “invocation”) and a module definition. I believe that you’re referring to a module instantiation here. > thus the definition of a statement’s syntax when a module is being called is (hacking BNF brutally) : > > module <name>( <arg>* ) [ | child_module()* | {<statement>* } ]; > The keyword “module” indicates a module *definition*. It is roughly akin to “def” in Python or “function” in JavaScript. The syntax of the body of a module is very similar to the syntax of a statement. (I think it might be identical, but don’t want to go check the parser right now.). I think you’re trying to describe a module instantiation, so let’s drop “module”: <name>( <arg>* ) [ | child_module()* | {<statement>* } ]; I assume that you are using brackets to indicate grouping for the | alternatives, rather than to indicate optionality. A semicolon is not used after a brace-enclosed list, and the * on child_module() includes the case of zero so you don’t need the empty case. Also, “<arg>*” doesn’t describe argument list syntax correctly, so let’s just push the details down into a separate and not-defined-here level. Net, next draft: <name>( <args> ) [ child_module()* ; | {<statement>* } ] But that’s not quite right, because the last child module installation can have a brace-enclosed list. I think you could syntactically describe it as <name>( <args>) child_module()* [ ; | {<statement>* } ] But that’s not really the best representation, because it does not represent the nesting. Best is probably a recursive definition, something like: module_instantiation: <name>(<args>); | <name>(<args>) <module_instantiation> | <name>(<args>) { <statement>* } But for the formally correct definition, refer to the parser, src/core/parser.y.
MH
Matthieu Hendriks
Wed, Aug 6, 2025 11:09 AM

The subject is still "is color an actual operator???"

I'm losing focus on this  thread :)

Jordan Brown via Discuss schreef op 2025-08-06 13:02:

rotate(45) cube(10);

as calling cube() to create a cube, and passing the result to rotate()
to rotate it.

if we could agree that the term "call a module" to mean: ( using
cube(10) as the example)

jump to the chunk of code labeled cube() passing its defined argument
list with default values except size=45
execute that code and then return

Sure.

in your example cube() is not in the parameter list of the call to
rotate(), so i do not like to say it is "passed" to rotate()

Weeeeellllll.... It kind of is in the parameter list. There are
two parameter lists. One is a conventional parameter list. The other
is the child list, which in this case has a single entry and so does not
need braces, but could have multiple entries surrounded by braces.

I'm happy with saying that cube() probably ends up being called. The
questions are what calls it, and when.

The simple mental model says that it's called by the top level, and the
result passed to rotate(). But that's not correct, or not exactly
correct. What's passed down to rotate() is the list of child statements,
rotate() evaluates those statements, and that evaluation leads to cube()
being called.

My new understanding of the module's syntax is that it includes a
following child module,

It's best that when you're being formal you distinguish between a
module instantiation (or perhaps "call" or "invocation") and a module
definition. I believe that you're referring to a module instantiation
here.

thus the definition of a statement's syntax when a module is being
called is (hacking BNF brutally) :

module <name>( <arg>* ) [ | child_module()* | {<statement>* } ];

The keyword "module" indicates a module definition. It is roughly
akin to "def" in Python or "function" in JavaScript.

The syntax of the body of a module is very similar to the syntax of a
statement. (I think it might be identical, but don't want to go check
the parser right now.).

I think you're trying to describe a module instantiation, so let's drop
"module":

<name>( <arg>* ) [ | child_module()* | {<statement>* } ];

I assume that you are using brackets to indicate grouping for the |
alternatives, rather than to indicate optionality.

A semicolon is not used after a brace-enclosed list, and the * on
child_module() includes the case of zero so you don't need the empty
case.

Also, "<arg>*" doesn't describe argument list syntax correctly, so let's
just push the details down into a separate and not-defined-here level.
Net, next draft:

<name>( <args> ) [ child_module()* ; | {<statement>* } ]

But that's not quite right, because the last child module installation
can have a brace-enclosed list.  I think you could syntactically
describe it as

<name>( <args>) child_module()* [ ; | {<statement>* } ]

But that's not really the best representation, because it does not
represent the nesting.

Best is probably a recursive definition, something like:

module_instantiation:

 <name>(<args>);

 | <name>(<args>) <module_instantiation>

 | <name>(<args>) { <statement>* }

But for the formally correct definition, refer to the parser,
src/core/parser.y.


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

The subject is still "is color an actual operator???" I'm losing focus on this thread :) Jordan Brown via Discuss schreef op 2025-08-06 13:02: > rotate(45) cube(10); > > as calling cube() to create a cube, and passing the result to rotate() > to rotate it. > > if we could agree that the term "call a module" to mean: ( using > cube(10) as the example) > > jump to the chunk of code labeled cube() passing its defined argument > list with default values except size=45 > execute that code and then return Sure. > in your example cube() is not in the parameter list of the call to > rotate(), so i do not like to say it is "passed" to rotate() Weeeeellllll.... It kind of *is* in the parameter list. There are *two* parameter lists. One is a conventional parameter list. The other is the child list, which in this case has a single entry and so does not need braces, but could have multiple entries surrounded by braces. I'm happy with saying that cube() probably ends up being called. The questions are what calls it, and when. The simple mental model says that it's called by the top level, and the result passed to rotate(). But that's not correct, or not exactly correct. What's passed down to rotate() is the list of child statements, rotate() evaluates those statements, and that evaluation leads to cube() being called. > My new understanding of the module's syntax is that it includes a > following child module, It's best that when you're being formal you distinguish between a module instantiation (or perhaps "call" or "invocation") and a module definition. I believe that you're referring to a module instantiation here. > thus the definition of a statement's syntax when a module is being > called is (hacking BNF brutally) : > >> module <name>( <arg>* ) [ | child_module()* | {<statement>* } ]; The keyword "module" indicates a module *definition*. It is roughly akin to "def" in Python or "function" in JavaScript. The syntax of the body of a module is very similar to the syntax of a statement. (I think it might be identical, but don't want to go check the parser right now.). I think you're trying to describe a module instantiation, so let's drop "module": <name>( <arg>* ) [ | child_module()* | {<statement>* } ]; I assume that you are using brackets to indicate grouping for the | alternatives, rather than to indicate optionality. A semicolon is not used after a brace-enclosed list, and the * on child_module() includes the case of zero so you don't need the empty case. Also, "<arg>*" doesn't describe argument list syntax correctly, so let's just push the details down into a separate and not-defined-here level. Net, next draft: <name>( <args> ) [ child_module()* ; | {<statement>* } ] But that's not quite right, because the last child module installation can have a brace-enclosed list. I think you could syntactically describe it as <name>( <args>) child_module()* [ ; | {<statement>* } ] But that's not really the best representation, because it does not represent the nesting. Best is probably a recursive definition, something like: module_instantiation: <name>(<args>); | <name>(<args>) <module_instantiation> | <name>(<args>) { <statement>* } But for the formally correct definition, refer to the parser, src/core/parser.y. _______________________________________________ OpenSCAD mailing list To unsubscribe send an email to discuss-leave@lists.openscad.org
NH
nop head
Wed, Aug 6, 2025 11:18 AM

colour is simply a module. In fact I think all named items that are allowed
in a statement are modules. There is no such thing as operator modules.
They are just modules.

On Wed, 6 Aug 2025, 12:09 Matthieu Hendriks via Discuss, <
discuss@lists.openscad.org> wrote:

The subject is still "is color an actual operator???"

I'm losing focus on this  thread :)

Jordan Brown via Discuss schreef op 2025-08-06 13:02:

rotate(45) cube(10);

as calling cube() to create a cube, and passing the result to rotate() to
rotate it.

if we could agree that the term "call a module" to mean: ( using cube(10)
as the example)

jump to the chunk of code labeled cube() passing its defined argument list
with default values except size=45
execute that code and then return

Sure.

in your example cube() is not in the parameter list of the call to
rotate(), so i do not like to say it is "passed" to rotate()

Weeeeellllll.... It kind of is in the parameter list. There are two
parameter lists. One is a conventional parameter list. The other is the
child list, which in this case has a single entry and so does not need
braces, but could have multiple entries surrounded by braces.

I'm happy with saying that cube() probably ends up being called. The
questions are what calls it, and when.

The simple mental model says that it's called by the top level, and the
result passed to rotate(). But that's not correct, or not exactly correct.
What's passed down to rotate() is the list of child statements, rotate()
evaluates those statements, and that evaluation leads to cube() being
called.

My new understanding of the module's syntax is that it includes a
following child module,

It's best that when you're being formal you distinguish between a module
instantiation (or perhaps "call" or "invocation") and a module definition.
I believe that you're referring to a module instantiation here.

thus the definition of a statement's syntax when a module is being called
is (hacking BNF brutally) :

module <name>( <arg>* ) [ | child_module()* | {<statement>* } ];

The keyword "module" indicates a module definition. It is roughly akin
to "def" in Python or "function" in JavaScript.

The syntax of the body of a module is very similar to the syntax of a
statement. (I think it might be identical, but don't want to go check the
parser right now.).

I think you're trying to describe a module instantiation, so let's drop
"module":

<name>( <arg>* ) [ | child_module()* | {<statement>* } ];

I assume that you are using brackets to indicate grouping for the |
alternatives, rather than to indicate optionality.

A semicolon is not used after a brace-enclosed list, and the * on
child_module() includes the case of zero so you don't need the empty case.

Also, "<arg>*" doesn't describe argument list syntax correctly, so let's
just push the details down into a separate and not-defined-here level.
Net, next draft:

<name>( <args> ) [ child_module()* ; | {<statement>* } ]

But that's not quite right, because the last child module installation can
have a brace-enclosed list.  I think you could syntactically describe it as

<name>( <args>) child_module()* [ ; | {<statement>* } ]

But that's not really the best representation, because it does not
represent the nesting.

Best is probably a recursive definition, something like:

module_instantiation:

 <name>(<args>);

 | <name>(<args>) <module_instantiation>

 | <name>(<args>) { <statement>* }

But for the formally correct definition, refer to the parser,
src/core/parser.y.


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

colour is simply a module. In fact I think all named items that are allowed in a statement are modules. There is no such thing as operator modules. They are just modules. On Wed, 6 Aug 2025, 12:09 Matthieu Hendriks via Discuss, < discuss@lists.openscad.org> wrote: > The subject is still "is color an actual operator???" > > > I'm losing focus on this thread :) > > > > Jordan Brown via Discuss schreef op 2025-08-06 13:02: > > > > > rotate(45) cube(10); > > as calling cube() to create a cube, and passing the result to rotate() to > rotate it. > > if we could agree that the term "call a module" to mean: ( using cube(10) > as the example) > > jump to the chunk of code labeled cube() passing its defined argument list > with default values except size=45 > execute that code and then return > > > Sure. > > in your example cube() is not in the parameter list of the call to > rotate(), so i do not like to say it is "passed" to rotate() > > > Weeeeellllll.... It kind of *is* in the parameter list. There are *two* > parameter lists. One is a conventional parameter list. The other is the > child list, which in this case has a single entry and so does not need > braces, but could have multiple entries surrounded by braces. > > I'm happy with saying that cube() probably ends up being called. The > questions are what calls it, and when. > > The simple mental model says that it's called by the top level, and the > result passed to rotate(). But that's not correct, or not exactly correct. > What's passed down to rotate() is the list of child statements, rotate() > evaluates those statements, and that evaluation leads to cube() being > called. > > My new understanding of the module's syntax is that it includes a > following child module, > > > It's best that when you're being formal you distinguish between a module > instantiation (or perhaps "call" or "invocation") and a module definition. > I believe that you're referring to a module instantiation here. > > thus the definition of a statement's syntax when a module is being called > is (hacking BNF brutally) : > > module <name>( <arg>* ) [ | child_module()* | {<statement>* } ]; > > > The keyword "module" indicates a module *definition*. It is roughly akin > to "def" in Python or "function" in JavaScript. > > The syntax of the body of a module is very similar to the syntax of a > statement. (I think it might be identical, but don't want to go check the > parser right now.). > > I think you're trying to describe a module instantiation, so let's drop > "module": > > <name>( <arg>* ) [ | child_module()* | {<statement>* } ]; > > I assume that you are using brackets to indicate grouping for the | > alternatives, rather than to indicate optionality. > > A semicolon is not used after a brace-enclosed list, and the * on > child_module() includes the case of zero so you don't need the empty case. > > Also, "<arg>*" doesn't describe argument list syntax correctly, so let's > just push the details down into a separate and not-defined-here level. > Net, next draft: > > <name>( <args> ) [ child_module()* ; | {<statement>* } ] > > But that's not quite right, because the last child module installation can > have a brace-enclosed list. I think you could syntactically describe it as > > <name>( <args>) child_module()* [ ; | {<statement>* } ] > > But that's not really the best representation, because it does not > represent the nesting. > > Best is probably a recursive definition, something like: > > module_instantiation: > > <name>(<args>); > > | <name>(<args>) <module_instantiation> > > | <name>(<args>) { <statement>* } > > But for the formally correct definition, refer to the parser, > src/core/parser.y. > > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org > > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org >
P
pca006132
Wed, Aug 6, 2025 2:15 PM

 umm .. then how better to understand it? the docs and tutorials did

not do enough so i started to experiment to see how things worked. I
have dozens of test and example code snippets to back up what i write
about how scad works ..

Yes, you should experiment, but that only tells you about the behavior
of the current implementation, not the API contract. You have to think
about what is the truly important thing, and ignore everything that are
not crucial. If you include things that are not crucial, this is
overspecification. The real specification probably only exists in the
devs' mind, if that exists, so deciding what to include requires a bit
of personal judgement and requires thinking like the devs. Here are some
examples (note that these are just my opinion, I am not the core dev and
I don't have the final say over the spec):

  • In the 2D subsystem page, "Although they are infinitely thin, they
    are rendered with a 1-unit thickness.". This is an example where the
    documentation overspecifies (and this is preview, not the F6
    render). Why? Because this doesn't really affect anything. This
    thickness choice is arbitrary. The reason it has thickness is
    probably due to how preview rendering works. Note that I am not
    opposed to mentioning this in the reference manual, but I am
    opposing to mentioning it two more times when talking about square
    and circle. (I think it is there for a long time, I'm just looking
    for random examples from the wiki)
  • Your confusion over how render works is an example of what I meant
    by overfit. The API contract is simple: The output of the render
    module is a mesh. Trying to understand why the implementation
    chooses quad over triangles in some cases but not the other is
    futile because it is complex and can be changed later. Writing it
    down in documentation will confuse people and make future updates
    harder (people will complain it is a breaking change).
    To quote Jordan's comment: "OpenSCAD makes no particular promises
    about the details of its rendering. It does not promise that
    everything will be reduced to triangles, and it does not promise
    that it won’t, and whether or not a particular case is reduced to
    triangles can depend on subtle factors.  It would be entirely with
    the specification (such as it is) for it to randomly do one or the
    other. (We don’t like that answer for testability reasons, but it
    would be legal.)".
  • The starting point of the circle module is an important detail in
    the API documentation, because it can be used to draw regular polygons.

 I am in the process of fixing these terminology issues .. in a

previous post i published the glossary i am now working with
https://en.wikibooks.org/wiki/User:VulcanWikiEdit/sandbox/SCADGlossary

It is good that you are fixing this. My recommendation is to avoid terms
with similar meaning unless you have a really, really convincing reason
to use both of them frequently and you can clearly show the difference
between them. "Shape" and "geometry" doesn't pass this test for me, at
least I have no idea why you want to have them both. For "drawn", do you
want to use it only when describing GUI or use it in the language
reference manual? I don't think you need this word. And I really want to
get rid of the term "action". Why is "statement" not good enough?

 if you take a look at the new pages i am happiest with you will see

that i am trying to answer the questions you raised. I too found the old
docs imprecise and in a few places contradictory

I have quite a few comments about style. IMO a reference manual is not
for beginners, and it should be written in a way that helps people
scanning and finding what they need, i.e. consistent style and concise.

First, people reading the reference manual probably don't care much
about the default behavior, so things like "By default this module draws
a unit circle centered on the origin [0,0] as a pentagon with its
starting point on the X-axis at X=1. Its lines have no thickness but the
shape is drawn as a 1 unit high, filled plane." should not be put at the
top of the documentation for the circle module. The first description
should be about the general behavior, written in a concise manner. The
old one "Creates a circle at the origin." is good enough for me, or
maybe you can say "Creates a regular polygon that approximates a circle
at the origin".

Second, the way you document the parameters is hard to understand. Again
for the circle module example, I wouldn't understand its signature if I
had no experience with openscad. The old documentation is not great
either in this case. I would rather want something like

circle(radius)
circle(r=radius)
circle(d=diameter)

radius: circle radius
diameter: circle diameter

And you talk about $fa, $fs, $fn at the end about quality of the
approximation and where the first point is placed, not as parameters.
You only give examples at the end, not interleave examples like the old
circle module documentation.

Third, we should have a more uniform way of writing
deprecated/experimental things. Instead of natural language like "Object
data structures have been introduced to the language recently. [Note:
Requires version 2025.07.11].", a simple highlight with "Since
2025.07.11:" or "Development snapshot only:" will be good. We should
probably put this in the section heading or at the top of the section if
that section is about something new (or deprecated..).

Fourth, we should have things like a grammar for expression and
statements, instead of natural language description such as "A vector or
list is a sequence of zero or more OpenSCAD values. Vectors are
collections of numeric or boolean values, variables, vectors, strings or
any combination thereof. They can also be expressions that evaluate to
one of these. Vectors handle the role of arrays found in many imperative
languages. The information here also applies to lists and tables that
use vectors for their data. A vector has square brackets, [] enclosing
zero or more items (elements or members), separated by commas. A vector
can contain vectors, which can contain vectors, etc.". This should be
left in the example. Note that the current documentation is also
imprecise: Vector (as a value) elements cannot be unevaluated
expressions, they must be values. You can have expressions in the
constructor of a vector, i.e., the square bracket form. And for things
like matrix, we should at least say whether it is column- or row-major,
i.e., whether the inner vector is a row or a column. This is never
described explicitly in the documentation.

These are what I meant by "too verbose and not detailed enough". I hope
I made my points clear. I will try to write something when I have time
as an example of the style that I want in the reference manual, but I am
running out of time now.

Best,
John

> umm .. then how better to understand it? the docs and tutorials did not do enough so i started to experiment to see how things worked. I have dozens of test and example code snippets to back up what i write about how scad works .. Yes, you should experiment, but that only tells you about the behavior of the current implementation, not the API contract. You have to think about what is the truly important thing, and ignore everything that are not crucial. If you include things that are not crucial, this is overspecification. The real specification probably only exists in the devs' mind, if that exists, so deciding what to include requires a bit of personal judgement and requires thinking like the devs. Here are some examples (note that these are just my opinion, I am not the core dev and I don't have the final say over the spec): * In the 2D subsystem page, "Although they are infinitely thin, they are rendered with a 1-unit thickness.". This is an example where the documentation overspecifies (and this is preview, not the F6 render). Why? Because this doesn't really affect anything. This thickness choice is arbitrary. The reason it has thickness is probably due to how preview rendering works. Note that I am not opposed to mentioning this in the reference manual, but I am opposing to mentioning it two more times when talking about square and circle. (I think it is there for a long time, I'm just looking for random examples from the wiki) * Your confusion over how render works is an example of what I meant by overfit. The API contract is simple: The output of the render module is a mesh. Trying to understand why the implementation chooses quad over triangles in some cases but not the other is futile because it is complex and can be changed later. Writing it down in documentation will confuse people and make future updates harder (people will complain it is a breaking change). To quote Jordan's comment: "OpenSCAD makes no particular promises about the details of its rendering. It does not promise that everything will be reduced to triangles, and it does not promise that it won’t, and whether or not a particular case is reduced to triangles can depend on subtle factors.  It would be entirely with the specification (such as it is) for it to randomly do one or the other. (We don’t like that answer for testability reasons, but it would be legal.)". * The starting point of the circle module is an important detail in the API documentation, because it can be used to draw regular polygons. > I am in the process of fixing these terminology issues .. in a previous post i published the glossary i am now working with <https://en.wikibooks.org/wiki/User:VulcanWikiEdit/sandbox/SCADGlossary> It is good that you are fixing this. My recommendation is to avoid terms with similar meaning unless you have a really, really convincing reason to use both of them frequently and you can clearly show the difference between them. "Shape" and "geometry" doesn't pass this test for me, at least I have no idea why you want to have them both. For "drawn", do you want to use it only when describing GUI or use it in the language reference manual? I don't think you need this word. And I really want to get rid of the term "action". Why is "statement" not good enough? > if you take a look at the new pages i am happiest with you will see that i am trying to answer the questions you raised. I too found the old docs imprecise and in a few places contradictory I have quite a few comments about style. IMO a reference manual is not for beginners, and it should be written in a way that helps people scanning and finding what they need, i.e. consistent style and concise. First, people reading the reference manual probably don't care much about the default behavior, so things like "By default this module draws a unit circle centered on the origin [0,0] as a pentagon with its starting point on the X-axis at X=1. Its lines have no thickness but the shape is drawn as a 1 unit high, filled plane." should not be put at the top of the documentation for the circle module. The first description should be about the general behavior, written in a concise manner. The old one "Creates a circle at the origin." is good enough for me, or maybe you can say "Creates a regular polygon that approximates a circle at the origin". Second, the way you document the parameters is hard to understand. Again for the circle module example, I wouldn't understand its signature if I had no experience with openscad. The old documentation is not great either in this case. I would rather want something like circle(radius) circle(r=radius) circle(d=diameter) radius: circle radius diameter: circle diameter And you talk about $fa, $fs, $fn at the end about quality of the approximation and where the first point is placed, not as parameters. You only give examples at the end, not interleave examples like the old circle module documentation. Third, we should have a more uniform way of writing deprecated/experimental things. Instead of natural language like "Object data structures have been introduced to the language recently. [Note: Requires version 2025.07.11].", a simple highlight with "Since 2025.07.11:" or "Development snapshot only:" will be good. We should probably put this in the section heading or at the top of the section if that section is about something new (or deprecated..). Fourth, we should have things like a grammar for expression and statements, instead of natural language description such as "A vector or list is a sequence of zero or more OpenSCAD values. Vectors are collections of numeric or boolean values, variables, vectors, strings or any combination thereof. They can also be expressions that evaluate to one of these. Vectors handle the role of arrays found in many imperative languages. The information here also applies to lists and tables that use vectors for their data. A vector has square brackets, [] enclosing zero or more items (elements or members), separated by commas. A vector can contain vectors, which can contain vectors, etc.". This should be left in the example. Note that the current documentation is also imprecise: Vector (as a value) elements cannot be unevaluated expressions, they must be values. You can have expressions in the constructor of a vector, i.e., the square bracket form. And for things like matrix, we should at least say whether it is column- or row-major, i.e., whether the inner vector is a row or a column. This is never described explicitly in the documentation. These are what I meant by "too verbose and not detailed enough". I hope I made my points clear. I will try to write something when I have time as an example of the style that I want in the reference manual, but I am running out of time now. Best, John
V
vulcan_@mac.com
Wed, Aug 6, 2025 9:37 PM

pca006132 wrote:

yeah .. i am still a bit shaky on rendering .. but i am getting there

  • Your confusion over how render works is an example of what I meant
    by overfit. The API contract is simple: The output of the render
    module is a mesh. Trying to understand why the implementation
    chooses quad over triangles in some cases but not the other is
    futile because it is complex and can be changed later. Writing it
    down in documentation will confuse people and make future updates
    harder (people will complain it is a breaking change).

i get all that .. i have been using docs updates as a way to clarify my thoughts on rendering ..
it is working slowly .. there will be a few more revisions to the rendering page till it is right.

  • The starting point of the circle module is an important detail in
    the API documentation, because it can be used to draw regular polygons.

. "Shape" and "geometry" doesn't pass this test for me, at
least I have no idea why you want to have them both.

For "drawn", do you
want to use it only when describing GUI

I need a word for everywhere that a module .. does whatever it is that results in a mesh being created.
Jordan tells me the word in use in the community is “render” .. that is a problem for me as my
background in 3D modelling and animation that word was only used for when images were being
generated from a mesh or model.

i settled on “draw” to mean “make or add to a mesh being created by an scad script running”

I don't think you need this word. And I really want to
get rid of the term "action".

action is waaayy too general a word for “doing something”

Why is "statement" not good enough?

“statement“ has a particular lexical and syntactic meaning in the context of coding
in a programming language .. i use in the way i describe in
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/General#Program_Structure

First, people reading the reference manual probably don't care much
about the default behavior, so things like "By default this module draws
a unit circle centered on the origin [0,0]

i have to disagree with you on this. IMHO a clear, complete, and accurate statement
of a built-in function or modules default behavior is a good starting point for a
newcomer to OpenSCAD.
I start with that because when i was just starting out with it was a nice confirmation
of what i was seeing in my experiments .. and from there i write about the parameters
in a concise list .. and then for the params that have some complexity i add additional
sections to cover that .. complexity

The first description
should be about the general behavior, written in a concise manner. The
old one "Creates a circle at the origin." is good enough for me, or
maybe you can say "Creates a regular polygon that approximates a circle
at the origin".

But that .. is too cringe for me. Circle creates a circle .. not a polygon .. it is drawn
as a polygon, but that is an approximation of its shape. The polygon’s size
is determined by it being inscribed inside the circle of the given diameter.

Second, the way you document the parameters is hard to understand.

i agree .. i have experimented with a few templates for param lists .. no final
answer yet … but my current favorite is in the docs for linear_extrude()

https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/3D_Modelling#linear_extrude()_Operator_Module

You only give examples at the end, not interleave examples like the old
circle module documentation.

actually i strongly prefer to interleave examples .. the places you are seeing them
bunched up at the end of a section or page are mostly legacy pages that are still
in progress in being reafactored

Third, we should have a more uniform way of writing
deprecated/experimental things.

to this end i have created templates specific to our needs .. see them on
my sandbox page
https://en.wikibooks.org/wiki/User:VulcanWikiEdit/sandbox#templates

Fourth, we should have things like a grammar for expression and
statements,

well this would be a can of worms to open.
I prefer natural language expressions and descriptions over symbolic
syntax specs like BNF .. as long as the wording is clear and concise i feel
words are better.

But i am willing to hear a discussion on this point .. it is an important one.
I do make the warning that in my working career the ONLY time that a
team could agree on a standard for documentation was when i was in the
position of being able to unilaterally dictating it.

These are what I meant by "too verbose and not detailed enough". I hope
I made my points clear.

I would say so John, and thanks again for the feedback

Best,
John

Guten Abend
Jeff

pca006132 wrote: yeah .. i am still a bit shaky on rendering .. but i am getting there > * Your confusion over how render works is an example of what I meant > by overfit. The API contract is simple: The output of the render > module is a mesh. Trying to understand why the implementation > chooses quad over triangles in some cases but not the other is > futile because it is complex and can be changed later. Writing it > down in documentation will confuse people and make future updates > harder (people will complain it is a breaking change). > i get all that .. i have been using docs updates as a way to clarify my thoughts on rendering .. \ it is working slowly .. there will be a few more revisions to the rendering page till it is right. > * The starting point of the circle module is an important detail in > the API documentation, because it can be used to draw regular polygons. > > . "Shape" and "geometry" doesn't pass this test for me, at > least I have no idea why you want to have them both. this is my new glossary : https://en.wikibooks.org/wiki/User:VulcanWikiEdit/sandbox/SCADGlossary > For "drawn", do you > want to use it only when describing GUI I need a word for everywhere that a module .. does whatever it is that results in a mesh being created.\ Jordan tells me the word in use in the community is “render” .. that is a problem for me as my\ background in 3D modelling and animation that word was only used for when images were being\ generated *from* a mesh or model. i settled on “draw” to mean “make or add to a mesh being created by an scad script running” > I don't think you need this word. And I really want to > get rid of the term "action". action is waaayy too general a word for “doing something” > Why is "statement" not good enough? “statement“ has a particular lexical and syntactic meaning in the context of coding\ in a programming language .. i use in the way i describe in \ https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/General#Program_Structure > > > > First, people reading the reference manual probably don't care much > about the default behavior, so things like "By default this module draws > a unit circle centered on the origin \[0,0\] i have to disagree with you on this. IMHO a clear, complete, and accurate statement\ of a built-in function or modules default behavior is a good starting point for a\ newcomer to OpenSCAD. \ I start with that because when i was just starting out with it was a nice confirmation\ of what i was seeing in my experiments .. and from there i write about the parameters\ in a concise list .. and then for the params that have some complexity i add additional\ sections to cover that .. complexity > The first description > should be about the general behavior, written in a concise manner. The > old one "Creates a circle at the origin." is good enough for me, or > maybe you can say "Creates a regular polygon that approximates a circle > at the origin". But that .. is too cringe for me. Circle creates a circle .. not a polygon .. it is drawn\ as a polygon, but that is an approximation of its *shape*. The polygon’s size\ is determined by it being inscribed inside the circle of the given diameter. > Second, the way you document the parameters is hard to understand. i agree .. i have experimented with a few templates for param lists .. no final\ answer yet … but my current favorite is in the docs for linear_extrude() https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/3D_Modelling#linear_extrude()_Operator_Module > > You only give examples at the end, not interleave examples like the old > circle module documentation. actually i strongly prefer to interleave examples .. the places you are seeing them\ bunched up at the end of a section or page are mostly legacy pages that are still\ in progress in being reafactored > Third, we should have a more uniform way of writing > deprecated/experimental things. to this end i have created templates specific to our needs .. see them on \ my sandbox page \ https://en.wikibooks.org/wiki/User:VulcanWikiEdit/sandbox#templates > Fourth, we should have things like a grammar for expression and > statements, well this would be a can of worms to open.\ I prefer natural language expressions and descriptions over symbolic \ syntax specs like BNF .. as long as the wording is clear and concise i feel\ words are better. But i am willing to hear a discussion on this point .. it is an important one.\ I do make the warning that in my working career the ONLY time that a\ team could agree on a standard for documentation was when i was in the\ position of being able to unilaterally dictating it. > These are what I meant by "too verbose and not detailed enough". I hope > I made my points clear. I would say so John, and thanks again for the feedback > Best, > John Guten Abend \ Jeff
V
vulcan_@mac.com
Wed, Aug 6, 2025 9:54 PM

speaking only of the built-in modules .. the modules that draw shapes .. circle, sphere etc. only create shapes in the model and cannot do anything with child modules that follow them in a statement .. if there are any

I have been calling these Object Modules, copying that terminology from one or two places in the docs, but now we have actual objects so my attempt to build a consensus crashes and burns :)

and .. built-ins for modifying or moving those objects .. translate, color etc .. these are modules that ONLY operate on their children, can’t draw shapes and are not useful if they end a statement.

There was as place in the docs that referred to these as operating on the other type of module .. thus object modules and operator modules became a “thing” for me and i wrote them up that way .. it seemed a useful distinction .. for the built-in modules.

Not so much for user-defined modules .. folks have been telling me about the cool and complicated things being done in BOSL2 and NopSCADlib .. modules that both draw shapes and do operations on their children.

if we can come up with a better terminology i am all ears

thanks for your input Noppy

speaking only of the built-in modules .. the modules that draw shapes .. circle, sphere etc. only create shapes in the model and cannot do anything with child modules that follow them in a statement .. if there are any I have been calling these Object Modules, copying that terminology from one or two places in the docs, but now we have actual objects so my attempt to build a consensus crashes and burns :) and .. built-ins for modifying or moving those objects .. translate, color etc .. these are modules that ONLY operate on their children, can’t draw shapes and are not useful if they end a statement. There was as place in the docs that referred to these as operating on the other type of module .. thus object modules and operator modules became a “thing” for me and i wrote them up that way .. it seemed a useful distinction .. for the built-in modules. Not so much for user-defined modules .. folks have been telling me about the cool and complicated things being done in BOSL2 and NopSCADlib .. modules that both draw shapes and do operations on their children. if we can come up with a better terminology i am all ears thanks for your input Noppy
JB
Jon Bondy
Wed, Aug 6, 2025 10:00 PM

I just read this:


I need a word for everywhere that a module .. does whatever it is that
results in a mesh being created.
Jordan tells me the word in use in the community is “render” .. that is
a problem for me as my
background in 3D modelling and animation that word was only used for
when images were being
generated /from/ a mesh or model.

i settled on “draw” to mean “make or add to a mesh being created by an
scad script running”


I can't speak for anyone else, but I thought that the documentation was
OK (not great, but OK), and now we're entertaining changing how
everything is described, because we are not using the same terms as
elsewhere on the web.  This is not a compelling argument, at least to me.

I wish that, before ANY of these changes were even CONTEMPLATED, the
community (not someone inexperienced with OpenSCAD) came up with a list
of issues that needed to be resolved, and then we resolved them.  I do
not believe that a wholesale change to the documentation was required or
desired.  Pieces?  Sure.  Dealing with the new term "object"?  Sure.

I, for one, find what Vulcan is doing to be terrifying.  And I do not
have the patience to read all of the new documentation, over and over
again, trying to figure out what else has been broken.

I don't doubt that Vulcan's intentions are good, but I wonder if there
really is a problem that needs solving.  I also wonder whether the
community would be better off with an experienced OpenSCAD programmer
making the changes.

I understand that the documentation should be accessible to an OpenSCAD
newbie, but I am not sure that these changes will produce the best product.

If I'm way off base, I apologize.

Jon

On 8/6/2025 5:37 PM, vulcan_--- via Discuss wrote:

pca006132 wrote:

yeah .. i am still a bit shaky on rendering .. but i am getting there

  *

     Your confusion over how render works is an example of what I
     meant by overfit. The API contract is simple: The output of
     the render module is a mesh. Trying to understand why the
     implementation chooses quad over triangles in some cases but
     not the other is futile because it is complex and can be
     changed later. Writing it down in documentation will confuse
     people and make future updates harder (people will complain it
     is a breaking change).

i get all that .. i have been using docs updates as a way to clarify
my thoughts on rendering ..
it is working slowly .. there will be a few more revisions to the
rendering page till it is right.

  *

     The starting point of the circle module is an important detail
     in the API documentation, because it can be used to draw
     regular polygons.

 . "Shape" and "geometry" doesn't pass this test for me, at least I
 have no idea why you want to have them both.

this is my new glossary :
https://en.wikibooks.org/wiki/User:VulcanWikiEdit/sandbox/SCADGlossary

 For "drawn", do you want to use it only when describing GUI

I need a word for everywhere that a module .. does whatever it is that
results in a mesh being created.
Jordan tells me the word in use in the community is “render” .. that
is a problem for me as my
background in 3D modelling and animation that word was only used for
when images were being
generated /from/ a mesh or model.

i settled on “draw” to mean “make or add to a mesh being created by an
scad script running”

 I don't think you need this word. And I really want to get rid of
 the term "action".

action is waaayy too general a word for “doing something”

 Why is "statement" not good enough?

“statement“ has a particular lexical and syntactic meaning in the
context of coding
in a programming language .. i use in the way i describe in
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/General#Program_Structure

 First, people reading the reference manual probably don't care
 much about the default behavior, so things like "By default this
 module draws a unit circle centered on the origin [0,0]

i have to disagree with you on this. IMHO a clear, complete, and
accurate statement
of a built-in function or modules default behavior is a good starting
point for a
newcomer to OpenSCAD.
I start with that because when i was just starting out with it was a
nice confirmation
of what i was seeing in my experiments .. and from there i write about
the parameters
in a concise list .. and then for the params that have some complexity
i add additional
sections to cover that .. complexity

 The first description should be about the general behavior,
 written in a concise manner. The old one "Creates a circle at the
 origin." is good enough for me, or maybe you can say "Creates a
 regular polygon that approximates a circle at the origin".

But that .. is too cringe for me. Circle creates a circle .. not a
polygon .. it is drawn
as a polygon, but that is an approximation of its /shape/. The
polygon’s size
is determined by it being inscribed inside the circle of the given
diameter.

 Second, the way you document the parameters is hard to understand.

i agree .. i have experimented with a few templates for param lists ..
no final
answer yet … but my current favorite is in the docs for linear_extrude()

https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/3D_Modelling#linear_extrude()_Operator_Module

 You only give examples at the end, not interleave examples like
 the old circle module documentation.

actually i strongly prefer to interleave examples .. the places you
are seeing them
bunched up at the end of a section or page are mostly legacy pages
that are still
in progress in being reafactored

 Third, we should have a more uniform way of writing
 deprecated/experimental things.

to this end i have created templates specific to our needs .. see them on
my sandbox page
https://en.wikibooks.org/wiki/User:VulcanWikiEdit/sandbox#templates

 Fourth, we should have things like a grammar for expression and
 statements,

well this would be a can of worms to open.
I prefer natural language expressions and descriptions over symbolic
syntax specs like BNF .. as long as the wording is clear and concise i
feel
words are better.

But i am willing to hear a discussion on this point .. it is an
important one.
I do make the warning that in my working career the ONLY time that a
team could agree on a standard for documentation was when i was in the
position of being able to unilaterally dictating it.

 These are what I meant by "too verbose and not detailed enough". I
 hope I made my points clear.

I would say so John, and thanks again for the feedback

 Best, John

Guten Abend
Jeff


OpenSCAD mailing list
To unsubscribe send an email todiscuss-leave@lists.openscad.org

--
This email has been checked for viruses by AVG antivirus software.
www.avg.com

I just read this: --- I need a word for everywhere that a module .. does whatever it is that results in a mesh being created. Jordan tells me the word in use in the community is “render” .. that is a problem for me as my background in 3D modelling and animation that word was only used for when images were being generated /from/ a mesh or model. i settled on “draw” to mean “make or add to a mesh being created by an scad script running” --- I can't speak for anyone else, but I thought that the documentation was OK (not great, but OK), and now we're entertaining changing how everything is described, because we are not using the same terms as elsewhere on the web.  This is not a compelling argument, at least to me. I wish that, before ANY of these changes were even CONTEMPLATED, the community (not someone inexperienced with OpenSCAD) came up with a list of issues that needed to be resolved, and then we resolved them.  I do not believe that a wholesale change to the documentation was required or desired.  Pieces?  Sure.  Dealing with the new term "object"?  Sure. I, for one, find what Vulcan is doing to be terrifying.  And I do not have the patience to read all of the new documentation, over and over again, trying to figure out what else has been broken. I don't doubt that Vulcan's intentions are good, but I wonder if there really is a problem that needs solving.  I also wonder whether the community would be better off with an experienced OpenSCAD programmer making the changes. I understand that the documentation should be accessible to an OpenSCAD newbie, but I am not sure that these changes will produce the best product. If I'm way off base, I apologize. Jon On 8/6/2025 5:37 PM, vulcan_--- via Discuss wrote: > > pca006132 wrote: > > yeah .. i am still a bit shaky on rendering .. but i am getting there > > * > > Your confusion over how render works is an example of what I > meant by overfit. The API contract is simple: The output of > the render module is a mesh. Trying to understand why the > implementation chooses quad over triangles in some cases but > not the other is futile because it is complex and can be > changed later. Writing it down in documentation will confuse > people and make future updates harder (people will complain it > is a breaking change). > > i get all that .. i have been using docs updates as a way to clarify > my thoughts on rendering .. > it is working slowly .. there will be a few more revisions to the > rendering page till it is right. > > > * > > The starting point of the circle module is an important detail > in the API documentation, because it can be used to draw > regular polygons. > > . "Shape" and "geometry" doesn't pass this test for me, at least I > have no idea why you want to have them both. > > this is my new glossary : > https://en.wikibooks.org/wiki/User:VulcanWikiEdit/sandbox/SCADGlossary > > For "drawn", do you want to use it only when describing GUI > > I need a word for everywhere that a module .. does whatever it is that > results in a mesh being created. > Jordan tells me the word in use in the community is “render” .. that > is a problem for me as my > background in 3D modelling and animation that word was only used for > when images were being > generated /from/ a mesh or model. > > i settled on “draw” to mean “make or add to a mesh being created by an > scad script running” > > I don't think you need this word. And I really want to get rid of > the term "action". > > action is waaayy too general a word for “doing something” > > Why is "statement" not good enough? > > “statement“ has a particular lexical and syntactic meaning in the > context of coding > in a programming language .. i use in the way i describe in > https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/General#Program_Structure > > > First, people reading the reference manual probably don't care > much about the default behavior, so things like "By default this > module draws a unit circle centered on the origin [0,0] > > i have to disagree with you on this. IMHO a clear, complete, and > accurate statement > of a built-in function or modules default behavior is a good starting > point for a > newcomer to OpenSCAD. > I start with that because when i was just starting out with it was a > nice confirmation > of what i was seeing in my experiments .. and from there i write about > the parameters > in a concise list .. and then for the params that have some complexity > i add additional > sections to cover that .. complexity > > The first description should be about the general behavior, > written in a concise manner. The old one "Creates a circle at the > origin." is good enough for me, or maybe you can say "Creates a > regular polygon that approximates a circle at the origin". > > But that .. is too cringe for me. Circle creates a circle .. not a > polygon .. it is drawn > as a polygon, but that is an approximation of its /shape/. The > polygon’s size > is determined by it being inscribed inside the circle of the given > diameter. > > Second, the way you document the parameters is hard to understand. > > i agree .. i have experimented with a few templates for param lists .. > no final > answer yet … but my current favorite is in the docs for linear_extrude() > > https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/3D_Modelling#linear_extrude()_Operator_Module > > You only give examples at the end, not interleave examples like > the old circle module documentation. > > actually i strongly prefer to interleave examples .. the places you > are seeing them > bunched up at the end of a section or page are mostly legacy pages > that are still > in progress in being reafactored > > Third, we should have a more uniform way of writing > deprecated/experimental things. > > to this end i have created templates specific to our needs .. see them on > my sandbox page > https://en.wikibooks.org/wiki/User:VulcanWikiEdit/sandbox#templates > > Fourth, we should have things like a grammar for expression and > statements, > > well this would be a can of worms to open. > I prefer natural language expressions and descriptions over symbolic > syntax specs like BNF .. as long as the wording is clear and concise i > feel > words are better. > > But i am willing to hear a discussion on this point .. it is an > important one. > I do make the warning that in my working career the ONLY time that a > team could agree on a standard for documentation was when i was in the > position of being able to unilaterally dictating it. > > These are what I meant by "too verbose and not detailed enough". I > hope I made my points clear. > > I would say so John, and thanks again for the feedback > > Best, John > > Guten Abend > Jeff > > > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email todiscuss-leave@lists.openscad.org -- This email has been checked for viruses by AVG antivirus software. www.avg.com
TA
Todd Allen
Wed, Aug 6, 2025 11:20 PM

vulcan_ wrote:

But that .. is too cringe for me. Circle creates a circle .. not a polygon
.. it is drawn
as a polygon, but that is an approximation of its shape. The polygon’s size
is determined by it being inscribed inside the circle of the given diameter.

It NEVER makes a circle.  It isn't just drawn as a polygon.  It makes a
polygon with the number of sides determined by the value of special
variables such as $fn or $fs and $fa.

On Wed, Aug 6, 2025 at 4:37 PM vulcan_--- via Discuss <
discuss@lists.openscad.org> wrote:

pca006132 wrote:

yeah .. i am still a bit shaky on rendering .. but i am getting there

-

Your confusion over how render works is an example of what I meant by
overfit. The API contract is simple: The output of the render module is a
mesh. Trying to understand why the implementation chooses quad over
triangles in some cases but not the other is futile because it is complex
and can be changed later. Writing it down in documentation will confuse
people and make future updates harder (people will complain it is a
breaking change).

i get all that .. i have been using docs updates as a way to clarify my
thoughts on rendering ..
it is working slowly .. there will be a few more revisions to the
rendering page till it is right.

-

The starting point of the circle module is an important detail in the
API documentation, because it can be used to draw regular polygons.

. "Shape" and "geometry" doesn't pass this test for me, at least I have no
idea why you want to have them both.

this is my new glossary :
https://en.wikibooks.org/wiki/User:VulcanWikiEdit/sandbox/SCADGlossary

For "drawn", do you want to use it only when describing GUI

I need a word for everywhere that a module .. does whatever it is that
results in a mesh being created.
Jordan tells me the word in use in the community is “render” .. that is a
problem for me as my
background in 3D modelling and animation that word was only used for when
images were being
generated from a mesh or model.

i settled on “draw” to mean “make or add to a mesh being created by an
scad script running”

I don't think you need this word. And I really want to get rid of the term
"action".

action is waaayy too general a word for “doing something”

Why is "statement" not good enough?

“statement“ has a particular lexical and syntactic meaning in the context
of coding
in a programming language .. i use in the way i describe in

https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/General#Program_Structure

First, people reading the reference manual probably don't care much about
the default behavior, so things like "By default this module draws a unit
circle centered on the origin [0,0]

i have to disagree with you on this. IMHO a clear, complete, and accurate
statement
of a built-in function or modules default behavior is a good starting
point for a
newcomer to OpenSCAD.
I start with that because when i was just starting out with it was a nice
confirmation
of what i was seeing in my experiments .. and from there i write about the
parameters
in a concise list .. and then for the params that have some complexity i
add additional
sections to cover that .. complexity

The first description should be about the general behavior, written in a
concise manner. The old one "Creates a circle at the origin." is good
enough for me, or maybe you can say "Creates a regular polygon that
approximates a circle at the origin".

But that .. is too cringe for me. Circle creates a circle .. not a polygon
.. it is drawn
as a polygon, but that is an approximation of its shape. The polygon’s
size
is determined by it being inscribed inside the circle of the given
diameter.

Second, the way you document the parameters is hard to understand.

i agree .. i have experimented with a few templates for param lists .. no
final
answer yet … but my current favorite is in the docs for linear_extrude()

https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/3D_Modelling#linear_extrude()_Operator_Module

You only give examples at the end, not interleave examples like the old
circle module documentation.

actually i strongly prefer to interleave examples .. the places you are
seeing them
bunched up at the end of a section or page are mostly legacy pages that
are still
in progress in being reafactored

Third, we should have a more uniform way of writing
deprecated/experimental things.

to this end i have created templates specific to our needs .. see them on
my sandbox page
https://en.wikibooks.org/wiki/User:VulcanWikiEdit/sandbox#templates

Fourth, we should have things like a grammar for expression and
statements,

well this would be a can of worms to open.
I prefer natural language expressions and descriptions over symbolic
syntax specs like BNF .. as long as the wording is clear and concise i feel
words are better.

But i am willing to hear a discussion on this point .. it is an important
one.
I do make the warning that in my working career the ONLY time that a
team could agree on a standard for documentation was when i was in the
position of being able to unilaterally dictating it.

These are what I meant by "too verbose and not detailed enough". I hope I
made my points clear.

I would say so John, and thanks again for the feedback

Best, John

Guten Abend
Jeff


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

vulcan_ wrote: But that .. is too cringe for me. Circle creates a circle .. not a polygon .. it is drawn as a polygon, but that is an approximation of its shape. The polygon’s size is determined by it being inscribed inside the circle of the given diameter. It NEVER makes a circle. It isn't just drawn as a polygon. It makes a polygon with the number of sides determined by the value of special variables such as $fn or $fs and $fa. On Wed, Aug 6, 2025 at 4:37 PM vulcan_--- via Discuss < discuss@lists.openscad.org> wrote: > pca006132 wrote: > > yeah .. i am still a bit shaky on rendering .. but i am getting there > > > - > > Your confusion over how render works is an example of what I meant by > overfit. The API contract is simple: The output of the render module is a > mesh. Trying to understand why the implementation chooses quad over > triangles in some cases but not the other is futile because it is complex > and can be changed later. Writing it down in documentation will confuse > people and make future updates harder (people will complain it is a > breaking change). > > i get all that .. i have been using docs updates as a way to clarify my > thoughts on rendering .. > it is working slowly .. there will be a few more revisions to the > rendering page till it is right. > > > > - > > The starting point of the circle module is an important detail in the > API documentation, because it can be used to draw regular polygons. > > . "Shape" and "geometry" doesn't pass this test for me, at least I have no > idea why you want to have them both. > > this is my new glossary : > https://en.wikibooks.org/wiki/User:VulcanWikiEdit/sandbox/SCADGlossary > > For "drawn", do you want to use it only when describing GUI > > I need a word for everywhere that a module .. does whatever it is that > results in a mesh being created. > Jordan tells me the word in use in the community is “render” .. that is a > problem for me as my > background in 3D modelling and animation that word was only used for when > images were being > generated *from* a mesh or model. > > i settled on “draw” to mean “make or add to a mesh being created by an > scad script running” > > I don't think you need this word. And I really want to get rid of the term > "action". > > action is waaayy too general a word for “doing something” > > Why is "statement" not good enough? > > “statement“ has a particular lexical and syntactic meaning in the context > of coding > in a programming language .. i use in the way i describe in > > https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/General#Program_Structure > > > First, people reading the reference manual probably don't care much about > the default behavior, so things like "By default this module draws a unit > circle centered on the origin [0,0] > > i have to disagree with you on this. IMHO a clear, complete, and accurate > statement > of a built-in function or modules default behavior is a good starting > point for a > newcomer to OpenSCAD. > I start with that because when i was just starting out with it was a nice > confirmation > of what i was seeing in my experiments .. and from there i write about the > parameters > in a concise list .. and then for the params that have some complexity i > add additional > sections to cover that .. complexity > > The first description should be about the general behavior, written in a > concise manner. The old one "Creates a circle at the origin." is good > enough for me, or maybe you can say "Creates a regular polygon that > approximates a circle at the origin". > > But that .. is too cringe for me. Circle creates a circle .. not a polygon > .. it is drawn > as a polygon, but that is an approximation of its *shape*. The polygon’s > size > is determined by it being inscribed inside the circle of the given > diameter. > > Second, the way you document the parameters is hard to understand. > > i agree .. i have experimented with a few templates for param lists .. no > final > answer yet … but my current favorite is in the docs for linear_extrude() > > > https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/3D_Modelling#linear_extrude()_Operator_Module > > You only give examples at the end, not interleave examples like the old > circle module documentation. > > actually i strongly prefer to interleave examples .. the places you are > seeing them > bunched up at the end of a section or page are mostly legacy pages that > are still > in progress in being reafactored > > Third, we should have a more uniform way of writing > deprecated/experimental things. > > to this end i have created templates specific to our needs .. see them on > my sandbox page > https://en.wikibooks.org/wiki/User:VulcanWikiEdit/sandbox#templates > > Fourth, we should have things like a grammar for expression and > statements, > > well this would be a can of worms to open. > I prefer natural language expressions and descriptions over symbolic > syntax specs like BNF .. as long as the wording is clear and concise i feel > words are better. > > But i am willing to hear a discussion on this point .. it is an important > one. > I do make the warning that in my working career the ONLY time that a > team could agree on a standard for documentation was when i was in the > position of being able to unilaterally dictating it. > > These are what I meant by "too verbose and not detailed enough". I hope I > made my points clear. > > I would say so John, and thanks again for the feedback > > Best, John > > Guten Abend > Jeff > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org >
P
pca006132
Thu, Aug 7, 2025 12:29 AM

. "Shape" and "geometry" doesn't pass this test for me, at least I have no
idea why you want to have them both.

this is my new glossary :
https://en.wikibooks.org/wiki/User:VulcanWikiEdit/sandbox/SCADGlossary

This doesn't answer my question. When would you mention the word "geometry"?

For "drawn", do you want to use it only when describing GUI

I need a word for everywhere that a module .. does whatever it is that
results in a mesh being created.

circle() "creates" a regular polygon that approximates a circle. Isn't that
good enough? Why draw? Btw, we never add to a mesh, we only create new
meshes.

Why is "statement" not good enough?

“statement“ has a particular lexical and syntactic meaning in the context
of coding
in a programming language .. i use in the way i describe in

https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/General#Program_Structure

Well, I still don't get why "statement" is not good enough and the word
"action" is needed. I know programming languages well, I am doing a PhD
with it, and we define what a statement means all the time.

The first code block about <perform named action>; just confuse me further.
This is not a grammar description, nor an example, and it doesn't tell me
anything. The description about "invokes one or more modules to instantiate
a shape
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/General#Constructing_Solid_Geometry
that appears in the preview panel
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/The_OpenSCAD_User_Interface"
is just wrong because we can do it without the GUI. Similarly in the second
code block <Named variable> = <expression>; is also confusing: does that
imply we have unnamed variables?
The sentence "Normally a statement does just one thing, and for assignment
expressions that is enough." is also confusing: Statements doing only one
thing is just a special form, why bother? And assignment is a statement,
not an expression.

I don't want to continue on-and-on, there are too many issues that I can
point out here. I would suggest you to just start with a BNF form and
describe each construct, don't interleave them and try to write a good
prose.

First, people reading the reference manual probably don't care much about
the default behavior, so things like "By default this module draws a unit
circle centered on the origin [0,0]

i have to disagree with you on this. IMHO a clear, complete, and accurate
statement
of a built-in function or modules default behavior is a good starting
point for a
newcomer to OpenSCAD.
I start with that because when i was just starting out with it was a nice
confirmation
of what i was seeing in my experiments .. and from there i write about the
parameters
in a concise list .. and then for the params that have some complexity i
add additional
sections to cover that .. complexity

https://diataxis.fr/reference/ is, in my opinion, a good resource about
writing technical documentation. It says that "Reference material describes
the machinery. It should be austere. One hardly reads reference
material; one consults it.".
And I should probably clarify, by experts I mean people mature enough to
read the docs. A reference manual written in a clear, concise, predictable
style can only help people understand things.

The first description should be about the general behavior, written in a
concise manner. The old one "Creates a circle at the origin." is good
enough for me, or maybe you can say "Creates a regular polygon that
approximates a circle at the origin".

But that .. is too cringe for me. Circle creates a circle .. not a polygon
.. it is drawn
as a polygon, but that is an approximation of its shape. The polygon’s
size
is determined by it being inscribed inside the circle of the given
diameter.

Who cares if the reference manual is stating the obvious? You come to the
reference manual to find things you care, not to read a prose, and
typically not to look for the simple default behaviour. Also, the
description being obvious is a good thing, not a bad thing.

You only give examples at the end, not interleave examples like the old
circle module documentation.

actually i strongly prefer to interleave examples .. the places you are
seeing them
bunched up at the end of a section or page are mostly legacy pages that
are still
in progress in being reafactored

As mentioned above, one consults the reference manual. If you interleave
examples with description of the API, it makes it long, and people will
need more time to find the thing they need.

Third, we should have a more uniform way of writing
deprecated/experimental things.

to this end i have created templates specific to our needs .. see them on
my sandbox page
https://en.wikibooks.org/wiki/User:VulcanWikiEdit/sandbox#templates

Fourth, we should have things like a grammar for expression and
statements,

well this would be a can of worms to open.
I prefer natural language expressions and descriptions over symbolic
syntax specs like BNF .. as long as the wording is clear and concise i feel
words are better.

But i am willing to hear a discussion on this point .. it is an important
one.
I do make the warning that in my working career the ONLY time that a
team could agree on a standard for documentation was when i was in the
position of being able to unilaterally dictating it.

I am not saying we should not have natural language description. Again, it
is from a point of a quick search over the reference manual. If you have
the expertise in reading things like BNF, BNF is just the most concise way
to convey the information. You can supplement it with natural language
later. And as mentioned above, the current way is absolutely not clear, at
least to me.

Best,
John

> > . "Shape" and "geometry" doesn't pass this test for me, at least I have no > idea why you want to have them both. > > this is my new glossary : > https://en.wikibooks.org/wiki/User:VulcanWikiEdit/sandbox/SCADGlossary > This doesn't answer my question. When would you mention the word "geometry"? > For "drawn", do you want to use it only when describing GUI > > I need a word for everywhere that a module .. does whatever it is that > results in a mesh being created. > circle() "creates" a regular polygon that approximates a circle. Isn't that good enough? Why draw? Btw, we never add to a mesh, we only create new meshes. > Why is "statement" not good enough? > > “statement“ has a particular lexical and syntactic meaning in the context > of coding > in a programming language .. i use in the way i describe in > > https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/General#Program_Structure > Well, I still don't get why "statement" is not good enough and the word "action" is needed. I know programming languages well, I am doing a PhD with it, and we define what a statement means all the time. The first code block about <perform named action>; just confuse me further. This is not a grammar description, nor an example, and it doesn't tell me anything. The description about "invokes one or more modules to instantiate a shape <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/General#Constructing_Solid_Geometry> that appears in the preview panel <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/The_OpenSCAD_User_Interface>" is just wrong because we can do it without the GUI. Similarly in the second code block <Named variable> = <expression>; is also confusing: does that imply we have unnamed variables? The sentence "Normally a statement does just one thing, and for assignment expressions that is enough." is also confusing: Statements doing only one thing is just a special form, why bother? And assignment is a statement, not an expression. I don't want to continue on-and-on, there are too many issues that I can point out here. I would suggest you to just start with a BNF form and describe each construct, don't interleave them and try to write a good prose. > First, people reading the reference manual probably don't care much about > the default behavior, so things like "By default this module draws a unit > circle centered on the origin [0,0] > > i have to disagree with you on this. IMHO a clear, complete, and accurate > statement > of a built-in function or modules default behavior is a good starting > point for a > newcomer to OpenSCAD. > I start with that because when i was just starting out with it was a nice > confirmation > of what i was seeing in my experiments .. and from there i write about the > parameters > in a concise list .. and then for the params that have some complexity i > add additional > sections to cover that .. complexity > https://diataxis.fr/reference/ is, in my opinion, a good resource about writing technical documentation. It says that "Reference material describes the machinery. It should be *austere*. One hardly *reads* reference material; one *consults* it.". And I should probably clarify, by experts I mean people mature enough to read the docs. A reference manual written in a clear, concise, predictable style can only help people understand things. > The first description should be about the general behavior, written in a > concise manner. The old one "Creates a circle at the origin." is good > enough for me, or maybe you can say "Creates a regular polygon that > approximates a circle at the origin". > > But that .. is too cringe for me. Circle creates a circle .. not a polygon > .. it is drawn > as a polygon, but that is an approximation of its *shape*. The polygon’s > size > is determined by it being inscribed inside the circle of the given > diameter. > Who cares if the reference manual is stating the obvious? You come to the reference manual to find things you care, not to read a prose, and typically not to look for the simple default behaviour. Also, the description being obvious is a good thing, not a bad thing. > You only give examples at the end, not interleave examples like the old > circle module documentation. > > actually i strongly prefer to interleave examples .. the places you are > seeing them > bunched up at the end of a section or page are mostly legacy pages that > are still > in progress in being reafactored > As mentioned above, one consults the reference manual. If you interleave examples with description of the API, it makes it long, and people will need more time to find the thing they need. > Third, we should have a more uniform way of writing > deprecated/experimental things. > > to this end i have created templates specific to our needs .. see them on > my sandbox page > https://en.wikibooks.org/wiki/User:VulcanWikiEdit/sandbox#templates > > Fourth, we should have things like a grammar for expression and > statements, > > well this would be a can of worms to open. > I prefer natural language expressions and descriptions over symbolic > syntax specs like BNF .. as long as the wording is clear and concise i feel > words are better. > > But i am willing to hear a discussion on this point .. it is an important > one. > I do make the warning that in my working career the ONLY time that a > team could agree on a standard for documentation was when i was in the > position of being able to unilaterally dictating it. > I am not saying we should not have natural language description. Again, it is from a point of a quick search over the reference manual. If you have the expertise in reading things like BNF, BNF is just the most concise way to convey the information. You can supplement it with natural language later. And as mentioned above, the current way is absolutely not clear, at least to me. Best, John
P
pca006132
Thu, Aug 7, 2025 12:49 AM

I can't speak for anyone else, but I thought that the documentation was OK
(not great, but OK), and now we're entertaining changing how everything is
described, because we are not using the same terms as elsewhere on the
web.  This is not a compelling argument, at least to me.

Well I don't think that is the motivation for the overall change. That is
only my complaint about the new documentation.

I wish that, before ANY of these changes were even CONTEMPLATED, the
community (not someone inexperienced with OpenSCAD) came up with a list of
issues that needed to be resolved, and then we resolved them. l

I, for one, find what Vulcan is doing to be terrifying.  And I do not have

the patience to read all of the new documentation, over and over again,
trying to figure out what else has been broken.

Same here. I don't know what problem the current rewrite it solving. And I
think it makes something worse, i.e., searching for information in the
reference.

Best,
John

> > I can't speak for anyone else, but I thought that the documentation was OK > (not great, but OK), and now we're entertaining changing how everything is > described, because we are not using the same terms as elsewhere on the > web. This is not a compelling argument, at least to me. > Well I don't think that is the motivation for the overall change. That is only my complaint about the new documentation. > I wish that, before ANY of these changes were even CONTEMPLATED, the > community (not someone inexperienced with OpenSCAD) came up with a list of > issues that needed to be resolved, and then we resolved them. l > I, for one, find what Vulcan is doing to be terrifying. And I do not have > the patience to read all of the new documentation, over and over again, > trying to figure out what else has been broken. > Same here. I don't know what problem the current rewrite it solving. And I think it makes something worse, i.e., searching for information in the reference. Best, John
JB
Jordan Brown
Fri, Aug 8, 2025 7:48 AM

On 8/6/2025 4:20 PM, Todd Allen via Discuss wrote:

[ circle() ] NEVER makes a circle.  It isn't just drawn as a polygon. 
It makes a polygon with the number of sides determined by the value of
special variables such as $fn or $fs and $fa.

That's absolutely true, but we have an active discussion going on about
whether we should ensure that the documentation allows for a future
where (absent $fn) it does create a true circle.

On 8/6/2025 4:20 PM, Todd Allen via Discuss wrote: > [ circle() ] NEVER makes a circle.  It isn't just drawn as a polygon.  > It makes a polygon with the number of sides determined by the value of > special variables such as $fn or $fs and $fa. That's absolutely true, but we have an active discussion going on about whether we should ensure that the documentation allows for a future where (absent $fn) it *does* create a true circle.
JB
Jordan Brown
Fri, Aug 8, 2025 8:06 AM

[ Sigh yet again... what e-mail address I use is largely automatically
handled on my desktop, but not on this laptop. ]

Mattheiu is right; this needs a subject change.

On 8/6/2025 12:51 AM, vulcan_--- via Discuss wrote:

 1.

     One should not attempt to infer the API contract from the
     behavior.

umm .. then how better to understand it?

Reread the documentation.  Repeat repeat repeat.  Then ask and/or
inspect the sources.  Behavior is good only for very targeted questions,
and even then should be tempered by the others.

i am not at all clear what overfit means ..

He means that you may assume that the behavior that you see is the only
possible behavior.  (For instance, you may assume that some particular
triangularization (or lack thereof) is the promised answer, and it isn't.)

Yeah, specials are still a fuzzy thing for me .. even after Jordan’s
diligent attempt to educate me on how they work i am not at all clear
on what they bring to the language that is any different from having
global variables at the top level of scope

They aren't necessarily at the top level.  Try running this...

normal = "top";
$special = "top";

module foo() {
echo(normal=normal, $special=$special);
}

module bar() {
$special = "bar";
normal = "bar";
foo();
}

foo();
foo($special="top per-call");
bar();
echo(normal=normal, $special=$special);

Normal variables are scoped based on the program's static structure, so
"normal" is visible from the top, from foo(), and from bar() until the
definition of the new "normal" on bar's second line.  Nothing ever
refers to bar's definition of "normal".

Special variables ($ variables) are scoped based on the call stack.  The
initial setting ("top") is visible at the top level, and in anything
called from the top level - which means the top-level call to foo(), and
the call to bar() until bar's first line, where a new $special is
created ("bar").  That new $special is visible to bar() and to
everything that bar() calls - notably, its call to foo().  The second
call to foo() sets $special in the call, and that setting applies to
that call to foo() and everything that it calls (which is nothing).

Another way to put it:

For a normal variable, to find the assignment, start at the reference to
the variable, then look at that scope.  If it's defined there, you're
done.  Move to the next higher scope (one fewer level of braces).  If
it's defined there, you're done. Continue until you reach the top scope.

For a special variable, look at the current scope.  If it's defined
there, you're done.  Move to the place that called this module; look at
the scope there.  If it's defined there, you're done.  Continue until
you reach the top scope.

It's actually a little more complicated than that, in in both cases that
a reference in an assignment needs to look at earlier assignments in
that scope.

[ Sigh yet again... what e-mail address I use is largely automatically handled on my desktop, but not on this laptop. ] Mattheiu is right; this needs a subject change. On 8/6/2025 12:51 AM, vulcan_--- via Discuss wrote: > > 1. > > One should not attempt to infer the API contract from the > behavior. > > umm .. then how better to understand it? > Reread the documentation.  Repeat repeat repeat.  Then ask and/or inspect the sources.  Behavior is good only for very targeted questions, and even then should be tempered by the others. > i am not at all clear what overfit means .. > He means that you may assume that the behavior that you see is the only possible behavior.  (For instance, you may assume that some particular triangularization (or lack thereof) is the promised answer, and it isn't.) > Yeah, specials are still a fuzzy thing for me .. even after Jordan’s > diligent attempt to educate me on how they work i am not at all clear > on what they bring to the language that is any different from having > global variables at the top level of scope > They *aren't* necessarily at the top level.  Try running this... normal = "top"; $special = "top"; module foo() { echo(normal=normal, $special=$special); } module bar() { $special = "bar"; normal = "bar"; foo(); } foo(); foo($special="top per-call"); bar(); echo(normal=normal, $special=$special); Normal variables are scoped based on the program's static structure, so "normal" is visible from the top, from foo(), and from bar() until the definition of the new "normal" on bar's second line.  Nothing ever refers to bar's definition of "normal". Special variables ($ variables) are scoped based on the call stack.  The initial setting ("top") is visible at the top level, and in anything called from the top level - which means the top-level call to foo(), and the call to bar() until bar's first line, where a new $special is created ("bar").  That new $special is visible to bar() and to everything that bar() calls - notably, its call to foo().  The second call to foo() sets $special in the call, and that setting applies to that call to foo() and everything that it calls (which is nothing). Another way to put it: For a normal variable, to find the assignment, start at the reference to the variable, then look at that scope.  If it's defined there, you're done.  Move to the next higher scope (one fewer level of braces).  If it's defined there, you're done. Continue until you reach the top scope. For a special variable, look at the current scope.  If it's defined there, you're done.  Move to the place that called this module; look at the scope there.  If it's defined there, you're done.  Continue until you reach the top scope. It's actually a little more complicated than that, in in both cases that a reference in an assignment needs to look at earlier assignments in that scope.
JB
Jordan Brown
Fri, Aug 8, 2025 8:07 AM

[ Sigh ]

Prose descriptions are good for when you're trying to understand the
overall structure of the thing, and when you're trying to write and
understand simple cases.

BNF or something similarly concise and specific is essential when you're
trying to actually understand the syntax and how the pieces fit
together.  There is no way, for instance, that a prose description is
going to reasonably explain the parsing surrounding the let(), echo(),
and assert() operators.

[ Sigh ] Prose descriptions are good for when you're trying to understand the overall structure of the thing, and when you're trying to write and understand simple cases. BNF or something similarly concise and specific is essential when you're trying to actually *understand* the syntax and how the pieces fit together.  There is no way, for instance, that a prose description is going to reasonably explain the parsing surrounding the let(), echo(), and assert() operators.
JB
Jordan Brown
Fri, Aug 8, 2025 8:08 AM

[ I'll spend the effort to fix up this laptop configuration, again,
sorry for the duplicates. ]

Two Dimensional Modelling

0% developed  as of November 17, 2009
https://en.wikibooks.org/wiki/Help:Development_stages2D Primitives
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/2D_Primitives

All 2D primitives can be transformed with 3D transformations.

Really bad place to start.  Yes, you can transform them with 3D
transforms, but if you do then the results can be weird.  It should be
discouraged; you should almost always work with 2D transforms when
working with a 2D subassembly.

Also, maybe we should talk about the primitives before we talk about
what you can do with them.

 They are usually used as part of a 3D extrusion.

Yeah, eventually.  But again this doesn't seem appropriate for a "2D
primitives" section.  Maybe for an overview section above that.

 Although they are infinitely thin, they are rendered with a 1-unit
thickness.

Again, maybe in an overview section.

Note: Trying to subtract with|difference()|from 3D object will lead
to unexpected results in final rendering.

The real rule is "don't mix 2D objects with 3D objects and 3D
operations".  It isn't necessary or appropriate to say very much about
what will happen if you do.  Some cases will yield errors, while others
will do something weird.  We don't want the documentation to nail down
any particular behavior, because there are reasons that we might want to
change the behavior in these cases.

Ref, e.g., OEP 7 "Mixed Dimension Geometry Support"
https://github.com/openscad/openscad/wiki/OEP7%3A-Mixed-Dimension-Geometry-Support.

 Square Object Module

By default this module draws a unit square in the first quadrant,
(+X,+Y), starting at the origin [0,0]. Its four lines have no
thickness but the shape is drawn as a 1 unit high, filled plane.

The second sentence should probably just go away:

  • The first part "its four lines have no thickness" is both misleading
    • the lines have no independent existence - and incorrect; when
      rendered they do have thickness.
  • The second half (drawn as 1 unit high) restates something already
    said in above.

The module's arguments may be written in the order|<size>,
center=<bool>|without being named, but the names may be used as shown
in the examples:

There needs to be (but probably isn't) enough documentation convention
that this need not be said.

Parameters

size
has two forms:/single value/or/vector/
single - non-negative float, length of all four sides

Should use the word "number" rather than the word "float". OpenSCAD does
not have distinct floating point and integer types; it has only numbers.

center
boolean, default false, to set the shape's position in the X-Y plane

CenterWhen|false|, as it is by default, the shape will be drawn from
its first point at (0,0) in the First Quadrant, (+X,+Y). With center
set to|true|the shape is drawn centered on the origin.

These two paragraphs should be merged.

 Circle Object Module

By default this module draws a unit circle centered on the origin
[0,0] as a pentagon with its starting point on the X-axis at X=1. Its
lines have no thickness but the shape is drawn as a 1 unit high,
filled plane.

The part of the first sentence starting "as a pentagon ..." should go
away.  It's true, but it really belongs as part of the description of
$fa/$fs.

Again, the second sentence should just go away.

Somewhere it should say "Circles are approximated as regular polygons;
see <reference to $fa/$fs/$fn> for the details of the polygons generated."

The argument|radius|may be given without being named, but
the|r|and|d|arguments must be named.

There is no "radius" argument.  There are r and d.

Again, we should have a documentation convention so that we don't have
to repeat positional/named rules, but the behavior here is that r can be
supplied as the first argument, but d must be named.

(Technically, if you say "circle(undef, 10)" the 10 is the second  it
creates a 10-unit-diameter circle.  I would say that the fact that this
works is a minor bug.)

$fa
Special Variable
$fs
Special Variable
$fn
Special Variable

Theses should be described only to the extent of pointing at the general
description of $fa/$fs/$fn.

The default circle displays as a pentagram as that is the minimum
number of fragments used to approximate a curved shape calculated from
the default values for $fs and $fa. To have it draw as a smooth shape
increase the $fn value, the minimum number of fragments to draw, to 20
or more (best $fn < 128).

This is just bad.  First, everything here should be covered in the
description of $fa/$fs/$fn.  Second, using $fn to control the resolution
of a circle is generally the wrong answer; you are better off setting
$fa and $fs.  Finally, specific advice on $fn values is a bad idea,
because the "looks smooth" value varies dramatically with size.  A
20-gon is okay for a medium-small circle; a 72-gon is not good enough
for a 100-unit circle.

An alternative method to draw a very smooth circle scale is to scale
down a very large circle.

scale( 0.001 ) circle(200);

This should just go away; it confuses the issue.

Another way to solve the lack of a built-in module for regular
polygons is to write a custom one:module regular_polygon()
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/example_module_regular_polygon()

I wouldn't include this.  Using polygon() is harder than using circle(),
and anybody who's capable of using it should have little trouble
simulating circle().

convexity
Integer, default=1 - complex edge geometry may require a higher
value value to preview correctly.

Should include a link to a general discussion of convexity. Probably
should not even mention the default; that should be covered in the
general discussion.

Points ParameterA list of X-Y coordinates in this form:

[[1, 1], [1, 4], [3, 4], [3, 1], [1, 1]]

which defines four points and makes it explicit that the last one is
the same as the first.

Including the first point twice is not strictly necessary as this:

[[1, 1], [1, 4], [3, 4], [3, 1]]

gives the same result.

This seems like it should be simplified.  In the absence of a paths
parameter, the last point always connects to the first, because polygons
are always closed.

Paths Parameter

This optional parameter is a nested vector of paths.

A "path" is a list of index values that reference points in
the|points|vector. It can explicitly describe a closed loop by its
last index being the same as its first, as in:

[1, 2, 3, 4, 1]

but this is equivalent to:

[1, 2, 3, 4]

Again, this seems like unnecessary complexity; the last point always
connects to the first.

Notice that the points vector is simple list,

No, it's a list of lists.

 while each path is a separate vector.

Yes... points and paths are the same order. They are both lists of lists.

 This means that paths, that are lists of references to points, have
to "know" which points it needs to include.

While it's true that paths need to "know" the indexes they connect, I
don't see how that follows from the previous sentences.

 This can be an issue if the polygon is assembled from a number of
shapes at run time as the order of adding shapes affects their point's
index values.

It's true that this is something that you must handle, but I don't think
that a reference manual needs to discuss it.

 .Convexity

Formatting error:  this title is merged with the previous paragraph.
(But should be deleted, see below.)

Shapes with a lot of detail in their edges may need the convexity
parameter increased to preview correctly. See Convexity

Already discussed, should be deleted.

Example With Multiple Holes

[Note:Requires version2015.03] (for use of|concat()|)

https://en.wikibooks.org/wiki/File:OpenSCAD_romboid_with_holes.jpg

We are using "a" for the point lists and "b" for their paths:

a0 = [[0,0],[100,0],[130,50],[30,50]];    // outer boundary
b0 = [1,0,3,2];
a1 = [[20,20],[40,20],[30,30]];            // hole 1
b1 = [4,5,6];
a2 = [[50,20],[60,20],[40,30]];            // hole 2
b2 = [7,8,9];
a3 = [[65,10],[80,10],[80,40],[65,40]];    // hole 3
b3 = [10,11,12,13];
a4 = [[98,10],[115,40],[85,40],[85,10]];  // hole 4
b4 = [14,15,16,17];
a  = concat( a0,a1,a2,a3,a4 ); // merge all points into "a"
b  = [b0,b1,b2,b3,b4]; // place all paths into a vector
polygon(a,b);
//alternate
polygon(a,[b0,b1,b2,b3,b4]);

The "alternate" at the end of the example seems unnecessary - of course
you can use either a particular expression or a variable that has been
set to that expression.

2D to 3D by Extrusion

A polygon may be the basis for an extrusion, just as any of the 2D
primitives can. Thisexample script
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/example_module_2D_to_3D_extrusionmay
be used to draw the shape in this image:

Yes, a polygon can be used as the basis for extrusion, just as any of
the 2D primitives can.  That means that you do not need a specific
example of that case.

 Import a 2D Shape From a DXF

[Deprecated:import_dxf() will be removed in a future release. Use
Useimport() Object Module
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/The_OpenSCAD_Language#importinstead.
instead*]*

As a deprecated feature, this should be pushed to the bottom.

Read a DXF file and create a 2D shape.

Example

linear_extrude(height = 5, center = true)
import_dxf(file = "example009.dxf", layer = "plate");

Example with Import()

linear_extrude(height = 5, center = true)
import(file = "example009.dxf", layer = "plate");

The second should perhaps be titled "Replacement example with
import()".  Note also that since OpenSCAD is case sensitive the word
"import" should not be capitalized.

Text is a big enough topic that it should probably have its own page,
with just a brief mention and cross-reference here.

I see that it has its own page and is transcluded here.  It should not
be transcluded, because that makes it harder to just read everything.

Text in OpenSCAD

Being able to use text objects as a part of a model is valuable in a
lot of design solutions.

Delete this sentence.  This is reference material, not sales material. 
The user already knows whether or not it's valuable to them.

The fontsavailable to use in a script
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Text#Fonts_in_OpenSCADare
from the system that OpenSCAD is running in with the addition of those
explicitly added by the script itself.

And OpenSCAD includes several.  (And this duplicates a more extensive
discussion below.)

 text() Object Module

The|text()|object module draws a single string of text as a 2D
geometric object, using fonts installed on the local system or
provided as separate font file.

provided as +a+ separate font file

The shape starts at the origin and is drawn along the positive X axis.

By default, ...

(because halign and valign change things)

text
String. A single line ofany character allowed
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Characters_Strings#Characters.*Limitation:*non-printable
ASCII characters like newline and tab rendered as placeholders

Delete the second sentence.  If it's a string, it's allowed.  As for
being a single line and treatment of non-printable characters, need to
phrase that as a current restriction, not as a permanent behavior - it
would be good if we could eventually provide more support there, and we
wouldn't want to be prevented from adding that support by compatibility
concerns.  Ref https://github.com/openscad/openscad/issues/5018 for the
desire for multi-line text.

font
aformatted string
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Text#Parameterswith
default font of "Liberation Sans:style=Regular"

"formatted string" is a poor phrase there.  Better would be something
like "String.  A font specification with ...".

Also I see that this is a link over to a separate Text page.  A separate
Text page is good, as discussed above, but it shouldn't be duplicated here.

size
non-negative decimal, default=10. The generated text has a height
above the baseline of approximately this value, varying for
different fonts but typically being slightly smaller.

The "decimal" part should be "number".  (It isn't even sensible to talk
about a base.)

I don't feel the need for the "non-negative" part.  (It should probably
also be non-zero.)  Unless we have a special meaning for a negative
size, we should be able to let people figure out for themselves that if
they make a silly request they will get a silly answer.

Current behavior is ... interesting... though when you think about it
unsurprising:  the text is mirrored in X and Y, leading to it being
effectively rotated 180 degrees.  Unless we really want to keep that
behavior, we should probably make it be an error instead.  Until and
unless we decide that we want to keep that behavior, we should not
document it.

There needs to be a footnote about size.  Because of an arithmetic error
in the implementation (issue #4304
https://github.com/openscad/openscad/issues/4304), the "size"
parameter does not correspond to a typical font size specification.  It
is a coincidence that the arithmetic error approximately cancels out the
usual ratio between the specified font size and the size of a capital
letter, making "size" approximately specify the size of a capital letter
in a typical Western font.  However, since the result is useful, and
the error has been in place since the beginning, we really can't fix
it.  Maybe at some point we can introduce an alternative parameter that
specifies a more conventional font size, eg PR#4306
https://github.com/openscad/openscad/pull/4306.

spacing
float, default=1. Multiplicative factor that increases or
decreases spacing between characters.

"float" should be "number".

language
String. The language of the text (e.g., "en", "ar", "ch"). Default
is "en".
script
String, default="latin". The script of the text (e.g. "latin",
"arabic", "hani").

Somebody needs to figure out what these actually do.

$fn
higher values generate smoother curves (refer toSpecial Variables
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Other_Language_Features#special_variables)

This should refer to $fa, $fs, and $fn... and really you shouldn't be
using $fn here.

   Font & Style Parameter

The "name" of a font is a string starting with its|logical font
name|and|variation|,

I don't see variation as a separate part of the specification.

Also, use of the "typewriter" font here is inappropriate; neither of
these is a language keyword or language component.  Either use plain
text or perhaps italics.

 optionally followed by a colon (":") separated list of font
specifications like a|style|selection, and a set of zero or
more|features|.

We should include a list of the name=value specifications supported, or
refer to external (fontconfig?) documentation.

Again, "features" is not a keyword and should not be in typewriter font.

The common variations in a font family are|sans|and|serif|though many
others will be seen in the list of fonts available. Each font
variation can be drawn with a/style/to support textual emphasis.

I think those are part of the font name, and that there they are usually
capitalized.  I'm a bit torn on whether they should be in typewriter font.

The default, upright appearance is usually called "Regular" with
"Bold", "Italic", and "Bold Italic" being the other three styles
commonly included in a font. In general the styles offered by a font
may only be known by using the platform's font configuration tools or
theOpenSCAD font list dialog
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Text#Fonts_in_Openscad.

This should explicitly tie to the "style=" parameter.

The fontfeatures property is appended to the|font name|after the

"fontfeatures" should be in typewriter font because it is a keyword.

"font name" should not be in typewriter font because it is not a keyword.

optional style parameter. Its value is a semi-colon separated list of
feature codes, each prefixed by a plus, "+", to indicate that it is
being added,

Should end with a colon, not a comma.

font = "Linux Libertine G:style=Regular:fontfeatures=+smcp;+onum");

Size Parameter

Text size is normally given in points, and a point is 1/72 of an inch
high. The formula to convert thesizevalue to "points" is|pt =
size/3.937|, so asizeargument of 3.05 is about 12 points.

This is incorrect, because OpenSCAD is unitless.  "size" specifies some
dimension of the font, in OpenSCAD units.  See the discussion above
about exactly what dimension it measures. (OpenSCAD units are
typically interpreted as millimeters, but that's up to the user and
the consuming program; it is not part of OpenSCAD's definitions.)

There should be no reference to "points" except perhaps to disclaim
that anything is measured in points.

Note: Character size the distance from ascent to descent, not from
ascent to baseline.

Ref the arithmetic error mentioned above and the long discussion in
issue #4304, this is incorrect.  "size" should have measured
approximately the font ascent plus descent, but instead measures (even
more approximately) the font ascent.

One of these four names must be given as a string to the|valign|parameter.

Since the valign parameter itself is optional, the word "must" seems
inappropriate.  Perhaps "The valign parameter may be set to one of these
four words".

top
The text is aligned so the top of the tallest character in your
text is at the given Y coordinate.

There is no "given Y coordinate".  The top of the tallest character in
your text is at the X axis, Y=0.

center
The text is aligned with the center of the bounding box at the
given Y coordinate.

Again, at Y=0.

baseline
The text is aligned with the font baseline at the given Y coordinate.

Again, at Y=0.

bottom
The text is aligned so the bottom of the lowest-reaching character
in your text is at the given Y coordinate.

Again, at Y=0.

Note: only the "baseline" vertical alignment option will ensure
correct alignment of texts that use mix of fonts and sizes.

This overlaps a lot with the last sentence of the definition of
"baseline" and should probably be merged with it.

One of these three names must be given as a string to
the|halign|parameter.

Again, the word "must" seems inappropriate.

left
The text is aligned with the left side of the bounding box at the
given X coordinate.
center
The text is aligned with the center of the bounding box at the
given X coordinate.
right
The text is aligned with the right of the bounding box at the
given X coordinate.

None of these are correct.  The alignment is based on spacing, not on
the bounding box.  For most letters, "left" will position the ink
slightly to the right of X=0.  (For a size=10 M in Liberation Sans, it's
about 1.1 units right of X=0.)  I'd need to do more research to figure
out the exactly correct wording.

And for all of them, there is no "given [XY] coordinate". Positioning is
relative to the origin.

Spacing Parameter

Characters in a text element have the size dictated by their glyph in
the font being used. As such their size in X and Y is fixed. Each
glyph also has fixed|advance|values (it is a vector [a,b],
seetextmetrics
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Text#textmetrics)
for the offset to the origin of the next character. The position of
each following character is the|advance.x|value multiplied by
the|space|value. Obviously letters in the string can be stretched out
when the factor is greater than 1, and can be made to overlap
when|space|is a fraction closer to zero, but interestingly, using a
negative value spaces each letter in the opposite of
the|direction|parameter.

This is more or less correct, but what it doesn't say is that "spacing"
is almost completely useless for a proportionally spaced font, for two
reasons.  Ref https://github.com/openscad/openscad/issues/3859 .

  • It does not take ligatures into account; it spaces a ligature as a
    single glyph, yielding text that looks like "d i ffi c u l t".
  • Because it's a multiplier on the advance value, and because the
    advance value is larger for a wide glyph than it is for a narrow
    glyph, spacing between narrow glyphs and wide glyphs is radically
    different.  "IIIMMM" demonstrates this problem.

The "spacing" parameter should probably be downplayed, and should
probably be deprecated.

   Text Examples

Simulating Formatted Text

Needs to define what it means by "formatted".

When text needs to be drawn as if it was formatted it is possible to
use translate() to space lines of text vertically. Fonts that descend
below the baseline need to be spaced apart vertically by
about|1.4size|to not overlap. Some word processing programs use a
more generous spacing of|1.6
size|for "single spacing" and double
spacing can use|3.2*size|.

fontmetrics() can supply more correct values for the particular font.

But really this is advice, not reference material.

 Fonts in OpenSCAD

The fonts available for use in a script are thosed:

  • registered in the local system
  • included in the OpenSCAD installation
  • imported at run-time by a program

A call to fontmetrics() using only default settings shows the
installation's standard font and settings:

Any reference to fontmetrics() needs a "requires release XXX" note,
which at the moment is still "requires development snapshot".  But
really this should be at most a reference to the fontmetrics() section.

{
nominal = {
ascent = 12.5733;
descent = -2.9433;
};
max = {
ascent = 13.6109; descent = -4.2114;
};
interline = 15.9709;
font = {
family = "Liberation Sans";
style = "Regular";
};
}

Wherever this ends up, the indentation needs work.  It should match the
indentation style used in the examples.

None of the platforms OpenSCAD is available on include the Liberation
font family so having it as part of the app's installation, and making
it the default font, avoids problems of font availability.

"None" is an awfully broad statement about a moving target.  It would be
better to say "To avoid problems of font availability, OpenSCAD includes
the Liberation font family as part of its installation, and has
Liberation Sans as the default font.".

Note: It was previously noted in the docs that fonts may be added to
the installation by drag-and-drop of a font file into the editor
window, but as of version 2025 Snapshot this isnotthe case

That isn't what it said.  It said:

You can drag a font in the font list, into the editor window to use
in the text() statement.

I can't readily check a 2025 build at the moment, but as of Oct 2024 the
it does exactly as described:  dragging a font from the OpenSCAD font
list into the editor window drops its name in the editor window.  If
that is no longer the case, it's a bug.

In general, don't say things like this.  If the documentation said X,
and you find that X is not true, then one of the following is true:

  • You didn't understand, and X is indeed true.  (And maybe the
    documentation needs to be clearer.)
  • X is false, and it's a bug.  (The bug should be fixed, not the
    documentation.)
  • X is false, and has always been false, and it was always a
    documentation error.  (And the documentation needs to be fixed.)
  • Indeed, X used to be true and is no longer true, and it's an
    intentional change, and nobody updated the documentation.  This is a
    very rare case, because it often means a compatibility problem or
    feature regression.

Regardless, the right answer is to file an issue to get the actual answer.

In the following sample code a True Type Font, Andika, has been added
to the system fonts using its Font Management service.

We shouldn't talk about adding fonts to the system.  That's not our problem.

But also, that's not what the sample does.  It adds a font to
OpenSCAD
, and has nothing to do with the platform font mechanisms.

Supported font file formats areTrueType
https://en.wikipedia.org/wiki/TrueTypefonts (.ttf) andOpenType
https://en.wikipedia.org/wiki/OpenTypefonts (
.otf). Once a file is
registered to the project the details of the fonts in it may be seen
in the font list dialog (see image) so that the logical font names,
variations, and their available styles are available for use in the
project.

This says "see image", but doesn't indicate which image.

And:  OpenSCAD doesn't have the notion of "projects" or "registered to
the project".

 3D Text by Extrusion

This is true of all 2D objects and so does not need to be mentioned. 
Delete.

position
a vector [X,Y], the origin of the first glyph, thus the lower-left
corner of the drawn text.

No, it's not the origin of the first glyph, or at least that's a
confusing phrase to use.  A glyph is usually positioned slightly to the
right of the origin, and if it's a descender then it's below the origin,
and some characters (e.g. quotes) are well above the origin.  A more
correct statement would be that it's the lower left corner of the
bounding box of the text.

If one is going to talk about the origin of a glyph, it should be the
point on the baseline to at the left edge of the advance... which this
isn't.

size
a vector [a,b], the size of the generated text.

Should be [x,y].  [a,b] doesn't tell you what "a" and "b" mean.

ascent
positive float, the amount that the text extends above the baseline.

Use the word "number" rather than "float".

It's not always positive; for a glyph entirely below the baseline (like
underscore in Liberation Sans) it's negative.  (I'm not sure that's
truly the right definition, but it's the current behavior.)

descent
negative float, the amount that the text extends below the baseline.

Not always negative; for a glyph that is entirely above the baseline
(like apostrophe in Liberation Sans) it's positive. Again, I'm not sure
that's the right definition, but it's the current behavior.

offset
a vector default [0, 0], the lower-left corner of the box
containing the text, including inter-glyph spacing before the
first glyph.

There is no default; this is a value that's returned to you.

This is not the correct definition (and it wasn't correct in the
original that I wrote).  It's the position of the origin of the text,
after adjusting for halign and valign.  For normal LTR text, the X
coordinate is the X coordinate at the left edge of the first glyph's
advance, and the Y component is the Y coordinate of the baseline.

advance
a vector default [153.09, 0], amount of space to leave to any
following text.

There is no default (and certainly not that one!).

The original definition ("the "other end" of the text, the point at
which additional text should be positioned.") wasn't great, but was more
correct.  I would say "The point at which additional text should be
positioned, relative to the text's origin as reported by 'offset'.".

This example displays the text metrics for the default font used by
OpenSCAD:

"text metrics for ... font" is a non sequitur.  Text metrics measure a
particular string.  (And "used by OpenSCAD" is unnecessary; the entire
document is in that context.)

And it's incorrect; the default font is Liberation Sans and this example
uses Liberation Serif.

Better would be:

This example displays the text metrics for "Hello, World!" for
Liberation Serif with size=20:

https://en.wikibooks.org/wiki/File:OpenSCAD_textmetrics.pngUsing
textmetrics() to draw a box around text

s="Hello, World!";
size=20;
font="Liberation Serif";

translate([0,0,1])
text("Hello, World!",size=size,font=font);

Should use "s" instead of repeating the string.  (And this is in my
original, sigh.)

displays (formatted for readability):

The original "yields" is better, because it might or might not be displayed.

ECHO:{
position=[0.7936,-4.2752];
size=[149.306,23.552];
ascent=19.2768;
descent=-4.2752;
offset=[0,0];
advance=[153.09,0];
}

The indentation should match the examples, with the close brace at the
left margin.

   fontmetrics()

size
Decimal, optional. The size of the font, as described above
for|text()|.

Replace "decimal" with "number".

0% developed  as of November 17, 2009
https://en.wikibooks.org/wiki/Help:Development_stages3D to 2D
Projection
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/3D_to_2D_Projection

Using the|projection()|function, you can create 2d drawings from 3d
models,

So far so good.

 and export them to the dxf format.

This part should be deleted.  There are any number of things you might
do with a 2D projection of a 3D object.  Exporting to DXF is only one.

 It works by projecting a 3D model to the (x,y) plane, with z at 0.
If|cut=true|, only points with z=0 are considered (effectively cutting
the object), with|cut=false|(/the default/), points above and below
the plane are considered as well (creating a proper projection).

Example: Consider example002.scad, that comes with OpenSCAD.

https://en.wikibooks.org/wiki/File:Openscad_projection_example_2x.png

Then you can do a 'cut' projection, which gives you the 'slice' of the
x-y plane with z=0.

Doing the non-default case as the first example seems wrong; I would
swap the two examples.

Another Example

You can also use projection to get a 'side view' of an object.

This example seems unnecessary for a reference manual.  It's a
straightforward combination of the features described.

Links:

Seems inappropriate for a reference manual.  Also, doesn't seem more
complicated at all.

0% developed  as of November 17, 2009
https://en.wikibooks.org/wiki/Help:Development_stages2D to 3D
Extrusion
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/2D_to_3D_Extrusion

Extrusion https://en.wikipedia.org/wiki/Extrusionis the process of
creating an object with a fixed cross-sectional profile. OpenSCAD
provides two commands

"Commands" isn't the right word.  "Modules" is more correct, but
"operations" is probably best.

Both extrusion methods work on a (possibly disjointed) 2D shape
normally drawn in the relevant plane (see below).

The old description of the behavior of extrusion for 2D objects that
have been moved off the Z=0 plane is an example of something that should
never have been documented.  It's not a particularly useful behavior,
and we might eventually want a different behavior.  At most, it should
have said "don't do that".

It should probably say "drawn on the Z=0 plane".

This child object is first projected onto the X-Y plane along the Z
axis to create the starting face of the extrusion.

Delete.  We shouldn't document that behavior.

The start face is duplicated at the Z position given by the height
parameter to create the extrusion's end face. The extrusion is then
formed by creating a surface that joins each point along the edges of
the two faces.

That's a seriously incomplete description, because it's only true with
all of the parameters at their defaults.

Or, in other words, the 2D shape may be ... a 2D shape.

Delete the whole sentence.

The 2D shape may have a Z value that moves it out of the X-Y plane,
and it may even be rotated out of parallel with it. As stated above,
the extrusion's starting face is the projection of the 2D shape onto
the X-Y plane, which, if it is rotated, will have the effect of
fore-shortening it normal to the axis of the rotation.

Delete.

Using a 3D object as the extrusion's child will cause a compile time
error.

Factually incorrect.  It's not a compile-time error; it's a run-time error.

Also, we just said that the child must be a 2D shape.  Exact behavior
when that requirement is violated need not be (and probably should not
be) specified.

Delete.

Including a 3D object in a composition of 2D objects (formed using
boolean combinations on them) will be detected, the 3D object(s) will
be deleted from it and the remaining 2D objects will be the basis for
projecting their shape onto the X-Y plane.

We need not (and generally should not) specify the behavior in error
conditions.  Delete.

 Parameters For Linear Extrusion

There are no required parameters. The default operation is to extrude
the child by 100 units vertically from the X-Y Plane, centered on the
[0,0] origin.

"centered" is at best meaningless (because it's extruded wherever the
child is, without respect to the origin) and at worst incorrect (because
the default is to extrude into +Z, not to center in Z). Delete that last
phrase.

  1. height
    a non-negative integer, default 100, giving the length of the
    extrusion

Doesn't have to be an integer.

I don't know how strong a pattern we have for specifying parameters, but
they shouldn't be numbered.  (Except maybe if they are usable as
positional parameters - which don't match these numbers.)

  1. v - twist axis vector
    a vector of 3 signed decimal values, default [0,0,1], used as an
    eigen vector specifying the axis of rotation for the
    twist.[Note:Requires versionDevelopment snapshot]

I can't say that I truly understand eigenvectors, but I don't think this
is one.  The "signed" part is unnecessary, because all numbers are
signed, and the "decimal" part is meaningless because abstract numbers
have no base.

"v" is a vector of three numbers that controls the vector along which
the extrusion is done.

It has an interesting interaction with "height".  If both are specified,
height is used as the length of the extrusion, along the direction that
v points, and v's magnitude is ignored.  If only v is specified, it is
used to control both the direction and length of the extrusion.

Saying that it's the axis of rotation for twist is sort of right, but
maybe needs more explanation.  Normally when you think of an axis of
rotation, you're rotating along the plane perpendicular to that axis. 
Here, though, it is perhaps more correct to say that it controls the
origin of the rotation.  At each slice, the 2D shape is rotated around
Z, with the origin being the XY position of the extrusion vector.

  1. center
    a boolean, default false, that, when true, causes the resulting
    solid to be vertically centered at the X-Y plane.

"at the Z=0 plane" would be a bit more obvious.

  1. convexity
    a non-negative integer, default 1, giving a measure of the
    complexity of the generated surface. See the Section on Convexity
    later on this page.

Should include a link... which should not be pointing at this page, no
matter which page we're talking about.

  1. twist
    a signed decimal,

a number

  180 degrees is a half twist, 360 is all the way around, and so on.

Unnecessary, delete.

  1. scale
    either : a non-negative, decimal value,

a non-negative number

 minimum 0.0,

Implied by "non-negative", delete.

  that specifies the factor by which the end face should be scaled
 up, or down, in size from that of the start face.

All scaling is either up or down.  Just "should be scaled".

 or : an [x,y] vector that scales the extrusion in the X and Y
 directions separately.

Delete the colon.

  1. slices
    a non-negative integer for the number of rows of polygons that the
    extr.

Needs help.

h
a named parameter, synonym to height

Just list it in the same block as height.

$fn $fs $fa
Special Parameters - given as named parameters.

They have standard special-variable semantics, which means they can be
specified in the context or in the call.  They should be mentioned, but
perhaps not as parameters per se.  I believe they only affect twisted
extrusions, so maybe they should be mentioned there.

   Center

This parameter affects only affects the vertical position or the
extrusion. Its X-Y position is always that of the projection that sets
its starting face.

"or" should be "of".

This is a nice comment, but doesn't say what the parameter does.

"When true, the extrusion is centered vertically around Z=0." seems
adequate to me, without any further comment, but a subsequent comment
about not affecting X and Y would be OK.

   Scale

This is multiplicative factor that affects the size of extrusion's end
face. As such 1.0 means no change, a value greater than one expands
the end face, and a value between 0.001 and less than 1 shrinks it.

"As such" is unnecessary.

I don't know where 0.001 came from.  I would say "a value less than 1
shrinks it".

 A value of 0.0 causes the end face to degenerate to a point, turning
the extrusion into a pyramid, cone, or complex pointy shape according
to what the starting shape is.

I'd say this is unnecessary.

Using the vector form sets the scale factor in the X and Y directions
separately

   Twist

Twist is applied, by default, as a rotation about the Z Axis.

As discussed above, twist is always around Z.  What v controls is the
origin of that rotation.

When the start face is at the origin a twist creates a spiral out of
any corners in the child shape. If the start face is translated away
from the origin the twist creates a spring shape.

I don't know if it's truly useful to try to describe the various shapes
that can result from twisting.

One thing that might be worth explicitly mentioning is that you can't
practically use linear_extrude to generate threads.  You can come
temptingly close, but they won't be shaped right.  (It is actually
possible to get right, but requires an unobvious base shape.)

A positive twist rotates clockwise, negative twist the opposite.

Huh.  I basically never use twist, so I never noticed that it's
backwards from rotate.  That seems very wrong... and it's way too late
to fix it.  It might be worth mentioning this difference.

   Twist Axis Vector

The second parameter is an [x,y,z] eigen vector that specifies the
axis of rotation of the applied twist.

Suggest referring to it by name instead of by position.

 The ratios of the three dimensional values to their respective
coordinate axes specify the tilt away from the default axis, [0,0,1],
the Z-Axis. For instance, v=[cos(45),0,1] tilts the extrusion at 45
degrees to the X axis.

It's actually a skew rather than a tilt.

The start and end faces are always normal to the Z-axis, even when the
twist axis is tilted. The extruded and twisted surfaces are thus
distorted from what might be expected in an extruded shape. The more
expected result may be achieved by applying a rotation to then twisted
extrusion on the Z Axis to tilt it into the desired position.

It's best not to make assumptions about what the user expects. Describe
the operation, and describe it carefully.  Do not describe how to do
things that are straightforward combinations of operations.


Note that the documentation does not discuss which happens first:  twist
or scale.  I don't believe it matters when using the same scaling for X
and Y, but matters a great deal with using different scaling on the two
axes.  It twists and then scales, which can mean (for instance) that a
shape that started out rectangular turns into a parallelogram.  There's
an argument that this is not the useful behavior, and that
scale-and-then-twist is more useful since it retains the general shape
throughout the extrusion.  I've started a discussion a few times about
maybe changing this, but I don't think it ever came to a conclusion.  It
might be best not to document this without that conclusion.

   $fn, $fa, $fs Special Parameters

The special variables must be given as named parameters and are
applied to the extrusion, overriding the global setting. When the same
special variables are set on the base shape its values override their
use as parameters on the extrusion.

None of this is really accurate.

The special variables have standard special-variable behavior, which
means that you can specify them in the context or in the particular
call, and they apply to that context (including a specific call) and
everything that that is called from that context.  There is no "global
setting" that is special.

What matters for the linear_extrude (and in particular for twisted
extrusions) is the setting that it sees.

If the child 2D shape also uses these variables, what matters for it
is what it sees... which, absent an inner setting, will be the same as
what linear_extrude sees.

Thus, either:

linear_extrude(height=10, twist=20, $fn=100) circle(10);

or

$fn=100; linear_extrude(height=10, twist=20) circle(10);

will yield a high-resolution twist of a high-resolution circle.

On the other hand, either

linear_extrude(height=10, twist=20, $fn=100) circle(10, $fn=3);

or

$fn=100; linear_extrude(height=10, twist=20) circle(10, $fn=3);

will yield a high-resolution twist of a low-resolution circle - a triangle.

   Extrusion From Imported DXF

Does not need to be discussed.  You can linear_extrude any 2D shape, and
an import of a DXF yields a 2D shape.

     A Unit Circle with No Twist

I don't think all of these examples are necessary.

Generate an extrusion from a circle 2 units along the X Axis from the
origin,

unit circle

centered vertically on the X-Y plane, with no twist. The extrusion
appears to have a pentagonal cross-section because the extrusion's
child is a 2D circle with the default value for $fn.

It doesn't appear to have a pentagonal cross-section.  It does have
a pentagonal cross-section.

The same circle, but made into a spiral by 500 degrees of
counter-clockwise twist.

If you look carefully, this example demonstrates why you can't make
threads.  As you twist it more, it becomes thinner and thinner in Z. 
The problem is that the cross-section of a thread is a strange shape.

     Mesh Refinement

The slices parameter defines the number of intermediate points along
the Z axis of the extrusion.

I am not sure of the exactly right way to describe this, because of
fence post errors.

"slices" controls the number of 3D "chunks" that make up the extrusion. 
The total number of instances of the original 2D object is slices+1.

Its default increases with the value of twist.

It's some function of that and $fa/$fs/$fn.  I don't know what the
function is or exactly how to describe it.

Additional the segments parameter

Addition -> Additionally

Segments need to be a multiple of the polygon's fragments to have an
effect (6 or 9.. for a circle($fn=3), 8,12.. for a square() ).

I don't know what the actual behavior is, but that's not it.  For more
complex shapes (I experimented with a right triangle) intermediate
values do have an effect.

Thespecial variables
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Other_Language_Features$fn,
$fs and $fa can also be used to improve the output. If slices is not
defined, its value is taken from the defined $fn value.

Again, I don't know what the behavior is, but that's not it. Increasing
$fn does increase the number of slices, but it isn't simply used as the
number of slices.

$fa/$fs/$fn seem to control both slices and segments.

   Using with imported SVG

Does not need to be separately discussed.

 rotate_extrude() Operator Module

Rotational extrusion spins a 2D shape around the Z-axis to form a
solid which has rotational symmetry. One way to think of this
operation is to imagine a Potter's wheel placed on the X-Y plane with
its axis of rotation pointing up towards +Z. Then place the to-be-made
object on this virtual Potter's wheel (possibly extending down below
the X-Y plane towards -Z). The to-be-made object is the cross-section
of the object on the X-Y plane (keeping only the right half, X >= 0).
That is the 2D shape that will be fed to rotate_extrude() as the child
in order to generate this solid. Note that the object started on the
X-Y plane but is tilted up (rotated +90 degrees about the X-axis) to
extrude.

I'm not sure that this is the best possible explanation.

Since a 2D shape is rendered by OpenSCAD on the X-Y plane, an
alternative way to think of this operation is as follows: spins a 2D
shape around the Y-axis to form a solid. The resultant solid is placed
so that its axis of rotation lies along the Z-axis.

That's the way that I always think of it, though I mentally rotate it to
vertical before spinning it.

Just like the linear_extrude, the extrusion is always performed on the
projection of the 2D polygon to the XY plane.

Again, we should not document this behavior.

Transformations like rotate, translate, etc. applied to the 2D polygon
before extrusion modify the projection of the 2D polygon to the XY
plane and therefore also modify the appearance of the final 3D object.

  • A translation in Z of the 2D polygon has no effect on the result
    (as also the projection is not affected).
  • A translation in X increases the diameter of the final object.
  • A translation in Y results in a shift of the final object in Z
    direction.
  • A rotation about the X or Y axis distorts the cross section of the
    final object, as also the projection to the XY plane is distorted.

This is perhaps good stuff, if the part about projecting is removed.

Don't get confused, as OpenSCAD displays 2D polygons with a certain
height in the Z direction, so the 2D object (with its height) appears
to have a bigger projection to the XY plane. But for the projection to
the XY plane and also for the later extrusion only the base polygon
without height is used.

Once you get rid of the part about projecting this goes away too.

You cannot use rotate_extrude to produce a helix or screw thread.
Doing this properly can be difficult, so it's best to find a thread
library to make them for you.

This kind of comment can be valuable, but I'm not sure it belongs in a
reference manual.  If it is in a reference manual, it should be in a
clear and separate section (of the description of the particular
feature) marked "Application Notes" or something like that, to make it
clear that it's not part of the description of the feature.

If the shape spans the X axis a warning appears in the console windows
and the rotate_extrude() is ignored.

Don't talk about what window something appears in, because not everybody
uses the OpenSCAD GUI.

Don't talk about what happens "after" the error.

Just say that it's an error, period.

(And, BTW, this particular one is something that I think should not be
an error; I think that the result should be as if you split the 2D shape
in half, rotationally extruded both, and unioned them.  That is, take
the shape, sweep it 360 degrees, and anything it sweeps through (whether
once or twice) is part of the result.)

 If the 2D shape touches the Y axis, i.e. at x=0, itmustbe a line
that touches, not a point, as a point results in a zero thickness 3D
object, which is invalid and results in a CGAL error.

This may have been addressed with Manifold.

 *convexity* : If the extrusion fails for a non-trival 2D shape,
 try setting the convexity parameter (the default is not 10, but 10
 is a "good" value to try). See explanation further down.

Just point at the general discussion of convexity.  (Which should not be
on this page.)

And the extrusion does not "fail".  In fact, the artifacts may be quite
subtle.

 *start*[Note:Requires versionDevelopment snapshot] : Defaults to 0
 if*angle*is specified, and 180 if not. Specifies the starting
 angle of the extrusion, counter-clockwise from the positive X axis.

start was part of an effort to align rotational extrusion behavior with
the behavior of other round things.  I don't remember all of the
details, but there are few reasons why it isn't equivalent to rotating
the result.

 *$fa* : minimum angle (in degrees) of each fragment.
 *$fs* : minimum circumferential length of each fragment.
 *$fn* :*fixed*number of fragments in 360 degrees. Values of 3 or
 more override $fa and $fs

     $fa, $fs and $fn must be named parameters.click here for more
     details,
     <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Other_Language_Features>.

Do not describe these in detail here.  Refer to a general description of
them elsewhere.

Do not ever, ever, say "click here".  Any text that would not make sense
when printed is wrong.

   Rotate Extrude on Imported DXF

Delete.

Increasing the number of fragments composing the 2D shape improves the
quality of the mesh, but takes longer to render.

Unnecessary.

rotate_extrude(convexity = 10)
translate([2, 0, 0])
circle(r = 1, $fn = 100);

This example is unnecessary; this is a description of rotate_extrude,
not circle()

The number of fragments used by the extrusion can also be increased.

rotate_extrude(convexity = 10, $fn = 100)
translate([2, 0, 0])
circle(r = 1, $fn = 100);

Use $fs and $fa here.  In fact, supply them at the top level. And this
case doesn't require specifying convexity (though I'm not sure why
not).  Also, for circles this small high resolution is not practical;
make them bigger to make the example more real. Thus:

$fa = 1;
$fs = 1;
rotate_extrude()
     translate([20, 0, 0])
         circle(r = 10);

That's really the best practice.  You almost never want to use $fn if
your intent is to create a circle.

(Minor exception that is itself something of a bug:  if you're trying to
force the number of sides to be a multiple of 4.  But that shouldn't be
discussed here.)

Using the parameter angle (with OpenSCAD versions 2016.xx), a hook can
be modeled .

https://en.wikibooks.org/wiki/File:Hook.pngOpenSCAD - a hook

eps = 0.01;
translate([eps, 60, 0])
rotate_extrude(angle=270, convexity=10)
translate([40, 0]) circle(10);
rotate_extrude(angle=90, convexity=10)
translate([20, 0]) circle(10);
translate([20, eps, 0])
rotate([90, 0, 0]) cylinder(r=10, h=80+eps);

Delete.

     Extruding a Polygon

Delete.

   Description of extrude parameters

Why are we repeating these here?  Don't, especially because there is
little commonality between linear_extrude and rotate_extrude.

 0% developed  as of November 17, 2009
 <https://en.wikibooks.org/wiki/Help:Development_stages>DXF
 Extrusion
 <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/DXF_Extrusion>

Delete.

This should get more content.  At the current state of things it can
probably all go on the 2D page, but if it gets much more complex it
might want its own page with a brief summary and reference here.

[ I'll spend the effort to fix up this laptop configuration, again, sorry for the duplicates. ] > Two Dimensional Modelling > > > 0% developed  as of November 17, 2009 > <https://en.wikibooks.org/wiki/Help:Development_stages>2D Primitives > <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/2D_Primitives> > > All 2D primitives can be transformed with 3D transformations. > Really bad place to start.  Yes, you can transform them with 3D transforms, but if you do then the results can be weird.  It should be discouraged; you should almost always work with 2D transforms when working with a 2D subassembly. Also, maybe we should talk about the primitives before we talk about what you can do with them. >  They are usually used as part of a 3D extrusion. > Yeah, eventually.  But again this doesn't seem appropriate for a "2D primitives" section.  Maybe for an overview section *above* that. >  Although they are infinitely thin, they are rendered with a 1-unit > thickness. > Again, maybe in an overview section. > *Note*: Trying to subtract with|difference()|from 3D object will lead > to unexpected results in final rendering. > The real rule is "don't mix 2D objects with 3D objects and 3D operations".  It isn't necessary or appropriate to say very much about what will happen if you do.  Some cases will yield errors, while others will do something weird.  We don't want the documentation to nail down any particular behavior, because there are reasons that we might want to change the behavior in these cases. Ref, e.g., OEP 7 "Mixed Dimension Geometry Support" <https://github.com/openscad/openscad/wiki/OEP7%3A-Mixed-Dimension-Geometry-Support>. > Square Object Module > > By default this module draws a unit square in the first quadrant, > (+X,+Y), starting at the origin [0,0]. Its four lines have no > thickness but the shape is drawn as a 1 unit high, filled plane. > The second sentence should probably just go away: * The first part "its four lines have no thickness" is both misleading - the lines have no independent existence - and incorrect; when rendered they *do* have thickness. * The second half (drawn as 1 unit high) restates something already said in above. > The module's arguments may be written in the order|<size>, > center=<bool>|without being named, but the names may be used as shown > in the examples: > There needs to be (but probably isn't) enough documentation convention that this need not be said. > *Parameters* > > size > has two forms:/single value/or/vector/ > single - non-negative float, length of all four sides > Should use the word "number" rather than the word "float". OpenSCAD does not have distinct floating point and integer types; it has only numbers. > center > boolean, default false, to set the shape's position in the X-Y plane > > *Center*When|false|, as it is by default, the shape will be drawn from > its first point at (0,0) in the First Quadrant, (+X,+Y). With center > set to|true|the shape is drawn centered on the origin. > These two paragraphs should be merged. > Circle Object Module > > By default this module draws a unit circle centered on the origin > [0,0] as a pentagon with its starting point on the X-axis at X=1. Its > lines have no thickness but the shape is drawn as a 1 unit high, > filled plane. > The part of the first sentence starting "as a pentagon ..." should go away.  It's true, but it really belongs as part of the description of $fa/$fs. Again, the second sentence should just go away. Somewhere it should say "Circles are approximated as regular polygons; see <reference to $fa/$fs/$fn> for the details of the polygons generated." > The argument|radius|may be given without being named, but > the|r|and|d|arguments must be named. > There is no "radius" argument.  There are r and d. Again, we should have a documentation convention so that we don't have to repeat positional/named rules, but the behavior here is that r can be supplied as the first argument, but d must be named. (Technically, if you say "circle(undef, 10)" the 10 is the second  it creates a 10-unit-diameter circle.  I would say that the fact that this works is a minor bug.) > $fa > Special Variable > $fs > Special Variable > $fn > Special Variable > Theses should be described only to the extent of pointing at the general description of $fa/$fs/$fn. > The default circle displays as a pentagram as that is the minimum > number of fragments used to approximate a curved shape calculated from > the default values for $fs and $fa. To have it draw as a smooth shape > increase the $fn value, the minimum number of fragments to draw, to 20 > or more (best $fn < 128). > This is just bad.  First, everything here should be covered in the description of $fa/$fs/$fn.  Second, using $fn to control the resolution of a circle is generally the wrong answer; you are better off setting $fa and $fs.  Finally, specific advice on $fn values is a bad idea, because the "looks smooth" value varies dramatically with size.  A 20-gon is okay for a medium-small circle; a 72-gon is not good enough for a 100-unit circle. > An alternative method to draw a very smooth circle scale is to scale > down a very large circle. > > scale( 0.001 ) circle(200); This should just go away; it confuses the issue. > Another way to solve the lack of a built-in module for regular > polygons is to write a custom one:module regular_polygon() > <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/example_module_regular_polygon()> > I wouldn't include this.  Using polygon() is harder than using circle(), and anybody who's capable of using it should have little trouble simulating circle(). > convexity > Integer, default=1 - complex edge geometry may require a higher > value value to preview correctly. > Should include a link to a general discussion of convexity. Probably should not even mention the default; that should be covered in the general discussion. > *Points Parameter*A list of X-Y coordinates in this form: > > [[1, 1], [1, 4], [3, 4], [3, 1], [1, 1]] > > which defines four points and makes it explicit that the last one is > the same as the first. > > Including the first point twice is not strictly necessary as this: > > [[1, 1], [1, 4], [3, 4], [3, 1]] > > gives the same result. > This seems like it should be simplified.  In the absence of a paths parameter, the last point always connects to the first, because polygons are always closed. > *Paths Parameter* > > This optional parameter is a nested vector of paths. > > A "path" is a list of index values that reference points in > the|points|vector. It can explicitly describe a closed loop by its > last index being the same as its first, as in: > > [1, 2, 3, 4, 1] > > but this is equivalent to: > > [1, 2, 3, 4] Again, this seems like unnecessary complexity; the last point always connects to the first. > Notice that the points vector is simple list, > No, it's a list of lists. >  while each path is a separate vector. > Yes... points and paths are the same order. They are both lists of lists. >  This means that paths, that are lists of references to points, have > to "know" which points it needs to include. > While it's true that paths need to "know" the indexes they connect, I don't see how that follows from the previous sentences. >  This can be an issue if the polygon is assembled from a number of > shapes at run time as the order of adding shapes affects their point's > index values. > It's true that this is something that you must handle, but I don't think that a reference manual needs to discuss it. >  .*Convexity* > Formatting error:  this title is merged with the previous paragraph. (But should be deleted, see below.) > Shapes with a lot of detail in their edges may need the convexity > parameter increased to preview correctly. See Convexity > Already discussed, should be deleted. > *Example With Multiple Holes* > > [Note:Requires version2015.03] (for use of|concat()|) > > <https://en.wikibooks.org/wiki/File:OpenSCAD_romboid_with_holes.jpg> > > We are using "a" for the point lists and "b" for their paths: > > a0 = [[0,0],[100,0],[130,50],[30,50]]; // outer boundary > b0 = [1,0,3,2]; > a1 = [[20,20],[40,20],[30,30]]; // hole 1 > b1 = [4,5,6]; > a2 = [[50,20],[60,20],[40,30]]; // hole 2 > b2 = [7,8,9]; > a3 = [[65,10],[80,10],[80,40],[65,40]]; // hole 3 > b3 = [10,11,12,13]; > a4 = [[98,10],[115,40],[85,40],[85,10]]; // hole 4 > b4 = [14,15,16,17]; > a = concat( a0,a1,a2,a3,a4 ); // merge all points into "a" > b = [b0,b1,b2,b3,b4]; // place all paths into a vector > polygon(a,b); > //alternate > polygon(a,[b0,b1,b2,b3,b4]); The "alternate" at the end of the example seems unnecessary - of course you can use either a particular expression or a variable that has been set to that expression. > *2D to 3D by Extrusion* > > A polygon may be the basis for an extrusion, just as any of the 2D > primitives can. Thisexample script > <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/example_module_2D_to_3D_extrusion>may > be used to draw the shape in this image: > Yes, a polygon can be used as the basis for extrusion, just as any of the 2D primitives can.  That means that you do *not* need a specific example of that case. > Import a 2D Shape From a DXF > > [Deprecated:import_dxf() will be removed in a future release. Use > Useimport() Object Module > <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/The_OpenSCAD_Language#import>instead. > instead*]* > As a deprecated feature, this should be pushed to the bottom. > Read a DXF file and create a 2D shape. > > *Example* > > linear_extrude(height = 5, center = true) > import_dxf(file = "example009.dxf", layer = "plate"); > > *Example with Import()* > > linear_extrude(height = 5, center = true) > import(file = "example009.dxf", layer = "plate"); The second should perhaps be titled "Replacement example with import()".  Note also that since OpenSCAD is case sensitive the word "import" should not be capitalized. > 0% developed  as of November 17, 2009 > <https://en.wikibooks.org/wiki/Help:Development_stages>Text > <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Text> > Text is a big enough topic that it should probably have its own page, with just a brief mention and cross-reference here. I see that it *has* its own page and is transcluded here.  It should not be transcluded, because that makes it harder to just read everything. > > Text in OpenSCAD > > Being able to use text objects as a part of a model is valuable in a > lot of design solutions. > Delete this sentence.  This is reference material, not sales material.  The user already knows whether or not it's valuable to them. > The fontsavailable to use in a script > <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Text#Fonts_in_OpenSCAD>are > from the system that OpenSCAD is running in with the addition of those > explicitly added by the script itself. > And OpenSCAD includes several.  (And this duplicates a more extensive discussion below.) > text() Object Module > > The|text()|object module draws a single string of text as a 2D > geometric object, using fonts installed on the local system or > provided as separate font file. > provided as +a+ separate font file > The shape starts at the origin and is drawn along the positive X axis. > By default, ... (because halign and valign change things) > text > String. A single line ofany character allowed > <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Characters_Strings#Characters>.*Limitation:*non-printable > ASCII characters like newline and tab rendered as placeholders > Delete the second sentence.  If it's a string, it's allowed.  As for being a single line and treatment of non-printable characters, need to phrase that as a current restriction, not as a permanent behavior - it would be good if we could eventually provide more support there, and we wouldn't want to be prevented from adding that support by compatibility concerns.  Ref https://github.com/openscad/openscad/issues/5018 for the desire for multi-line text. > font > aformatted string > <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Text#Parameters>with > default font of "Liberation Sans:style=Regular" > "formatted string" is a poor phrase there.  Better would be something like "String.  A font specification with ...". Also I see that this is a link over to a separate Text page.  A separate Text page is good, as discussed above, but it shouldn't be duplicated here. > size > non-negative decimal, default=10. The generated text has a height > above the baseline of approximately this value, varying for > different fonts but typically being slightly smaller. > The "decimal" part should be "number".  (It isn't even sensible to talk about a base.) I don't feel the need for the "non-negative" part.  (It should probably also be non-zero.)  Unless we have a special meaning for a negative size, we should be able to let people figure out for themselves that if they make a silly request they will get a silly answer. Current behavior is ... interesting... though when you think about it unsurprising:  the text is mirrored in X and Y, leading to it being effectively rotated 180 degrees.  Unless we really want to keep that behavior, we should probably make it be an error instead.  Until and unless we decide that we want to keep that behavior, we should *not* document it. There needs to be a footnote about size.  Because of an arithmetic error in the implementation (issue #4304 <https://github.com/openscad/openscad/issues/4304>), the "size" parameter does not correspond to a typical font size specification.  It is a coincidence that the arithmetic error approximately cancels out the usual ratio between the specified font size and the size of a capital letter, making "size" approximately specify the size of a capital letter in a typical Western font.  However, since the result *is* useful, and the error has been in place since the beginning, we really can't fix it.  Maybe at some point we can introduce an alternative parameter that specifies a more conventional font size, eg PR#4306 <https://github.com/openscad/openscad/pull/4306>. > spacing > float, default=1. Multiplicative factor that increases or > decreases spacing between characters. > "float" should be "number". > language > String. The language of the text (e.g., "en", "ar", "ch"). Default > is "en". > script > String, default="latin". The script of the text (e.g. "latin", > "arabic", "hani"). > Somebody needs to figure out what these actually do. > $fn > higher values generate smoother curves (refer toSpecial Variables > <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Other_Language_Features#special_variables>) > This should refer to $fa, $fs, and $fn... and really you shouldn't be using $fn here. > Font & Style Parameter > > The "name" of a font is a string starting with its|logical font > name|and|variation|, > I don't see variation as a separate part of the specification. Also, use of the "typewriter" font here is inappropriate; neither of these is a language keyword or language component.  Either use plain text or perhaps italics. >  optionally followed by a colon (":") separated list of font > specifications like a|style|selection, and a set of zero or > more|features|. > We should include a list of the name=value specifications supported, or refer to external (fontconfig?) documentation. Again, "features" is not a keyword and should not be in typewriter font. > The common variations in a font family are|sans|and|serif|though many > others will be seen in the list of fonts available. Each font > variation can be drawn with a/style/to support textual emphasis. > I think those are part of the font name, and that there they are usually capitalized.  I'm a bit torn on whether they should be in typewriter font. > The default, upright appearance is usually called "Regular" with > "Bold", "Italic", and "Bold Italic" being the other three styles > commonly included in a font. In general the styles offered by a font > may only be known by using the platform's font configuration tools or > theOpenSCAD font list dialog > <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Text#Fonts_in_Openscad>. > This should explicitly tie to the "style=" parameter. > The fontfeatures property is appended to the|font name|after the > "fontfeatures" should be in typewriter font because it is a keyword. "font name" should not be in typewriter font because it is *not* a keyword. > optional style parameter. Its value is a semi-colon separated list of > feature codes, each prefixed by a plus, "+", to indicate that it is > being added, > Should end with a colon, not a comma. > font = "Linux Libertine G:style=Regular:fontfeatures=+smcp;+onum"); > > *Size Parameter* > > Text size is normally given in points, and a point is 1/72 of an inch > high. The formula to convert the*size*value to "points" is|pt = > size/3.937|, so a*size*argument of 3.05 is about 12 points. > This is incorrect, because OpenSCAD is unitless.  "size" specifies some dimension of the font, in OpenSCAD units.  See the discussion above about exactly what dimension it measures. (OpenSCAD units are *typically* interpreted as millimeters, but that's up to the user and the consuming program; it is not part of OpenSCAD's definitions.) There should be no reference to "points" except perhaps to *disclaim* that anything is measured in points. > *Note*: Character size the distance from ascent to descent, not from > ascent to baseline. > Ref the arithmetic error mentioned above and the long discussion in issue #4304, this is incorrect.  "size" *should have* measured approximately the font ascent plus descent, but instead measures (even more approximately) the font ascent. > One of these four names must be given as a string to the|valign|parameter. > Since the valign parameter itself is optional, the word "must" seems inappropriate.  Perhaps "The valign parameter may be set to one of these four words". > top > The text is aligned so the top of the tallest character in your > text is at the given Y coordinate. > There is no "given Y coordinate".  The top of the tallest character in your text is at the X axis, Y=0. > center > The text is aligned with the center of the bounding box at the > given Y coordinate. > Again, at Y=0. > baseline > The text is aligned with the font baseline at the given Y coordinate. > Again, at Y=0. > > bottom > The text is aligned so the bottom of the lowest-reaching character > in your text is at the given Y coordinate. > Again, at Y=0. > *Note*: only the "baseline" vertical alignment option will ensure > correct alignment of texts that use mix of fonts and sizes. > This overlaps a lot with the last sentence of the definition of "baseline" and should probably be merged with it. > One of these three names must be given as a string to > the|halign|parameter. > Again, the word "must" seems inappropriate. > left > The text is aligned with the left side of the bounding box at the > given X coordinate. > center > The text is aligned with the center of the bounding box at the > given X coordinate. > right > The text is aligned with the right of the bounding box at the > given X coordinate. > None of these are correct.  The alignment is based on spacing, not on the bounding box.  For most letters, "left" will position the ink slightly to the right of X=0.  (For a size=10 M in Liberation Sans, it's about 1.1 units right of X=0.)  I'd need to do more research to figure out the exactly correct wording. And for all of them, there is no "given [XY] coordinate". Positioning is relative to the origin. > *Spacing Parameter* > > Characters in a text element have the size dictated by their glyph in > the font being used. As such their size in X and Y is fixed. Each > glyph also has fixed|advance|values (it is a vector [a,b], > seetextmetrics > <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Text#textmetrics>) > for the offset to the origin of the next character. The position of > each following character is the|advance.x|value multiplied by > the|space|value. Obviously letters in the string can be stretched out > when the factor is greater than 1, and can be made to overlap > when|space|is a fraction closer to zero, but interestingly, using a > negative value spaces each letter in the opposite of > the|direction|parameter. > This is more or less correct, but what it doesn't say is that "spacing" is almost completely useless for a proportionally spaced font, for two reasons.  Ref https://github.com/openscad/openscad/issues/3859 . * It does not take ligatures into account; it spaces a ligature as a single glyph, yielding text that looks like "d i ffi c u l t". * Because it's a multiplier on the advance value, and because the advance value is larger for a wide glyph than it is for a narrow glyph, spacing between narrow glyphs and wide glyphs is radically different.  "IIIMMM" demonstrates this problem. The "spacing" parameter should probably be downplayed, and should probably be deprecated. > > Text Examples > > *Simulating Formatted Text* > Needs to define what it means by "formatted". > > When text needs to be drawn as if it was formatted it is possible to > use translate() to space lines of text vertically. Fonts that descend > below the baseline need to be spaced apart vertically by > about|1.4*size|to not overlap. Some word processing programs use a > more generous spacing of|1.6*size|for "single spacing" and double > spacing can use|3.2*size|. > fontmetrics() can supply more correct values for the particular font. But really this is advice, not reference material. > Fonts in OpenSCAD > > The fonts available for use in a script are thosed: > > * registered in the local system > * included in the OpenSCAD installation > * imported at run-time by a program > > A call to fontmetrics() using only default settings shows the > installation's standard font and settings: > Any reference to fontmetrics() needs a "requires release XXX" note, which at the moment is still "requires development snapshot".  But really this should be at most a reference to the fontmetrics() section. > { > nominal = { > ascent = 12.5733; > descent = -2.9433; > }; > max = { > ascent = 13.6109; descent = -4.2114; > }; > interline = 15.9709; > font = { > family = "Liberation Sans"; > style = "Regular"; > }; > } Wherever this ends up, the indentation needs work.  It should match the indentation style used in the examples. > None of the platforms OpenSCAD is available on include the Liberation > font family so having it as part of the app's installation, and making > it the default font, avoids problems of font availability. > "None" is an awfully broad statement about a moving target.  It would be better to say "To avoid problems of font availability, OpenSCAD includes the Liberation font family as part of its installation, and has Liberation Sans as the default font.". > *Note*: It was previously noted in the docs that fonts may be added to > the installation by drag-and-drop of a font file into the editor > window, but as of version 2025 Snapshot this is*not*the case > That isn't what it said.  It said: You can drag a font in the font list, into the editor window to use in the text() statement. I can't readily check a 2025 build at the moment, but as of Oct 2024 the it does exactly as described:  dragging a font from the OpenSCAD font list into the editor window drops its name in the editor window.  If that is no longer the case, it's a bug. In general, don't say things like this.  If the documentation said X, and you find that X is not true, then one of the following is true: * You didn't understand, and X is indeed true.  (And maybe the documentation needs to be clearer.) * X is false, and it's a bug.  (The bug should be fixed, not the documentation.) * X is false, and has always been false, and it was always a documentation error.  (And the documentation needs to be fixed.) * Indeed, X used to be true and is no longer true, and it's an intentional change, and nobody updated the documentation.  This is a very rare case, because it often means a compatibility problem or feature regression. Regardless, the right answer is to file an issue to get the actual answer. > In the following sample code a True Type Font, Andika, has been added > to the system fonts using its Font Management service. > We shouldn't talk about adding fonts to the system.  That's not our problem. But also, that's not what the sample does.  It adds a font *to OpenSCAD*, and has nothing to do with the platform font mechanisms. > Supported font file formats areTrueType > <https://en.wikipedia.org/wiki/TrueType>fonts (*.ttf) andOpenType > <https://en.wikipedia.org/wiki/OpenType>fonts (*.otf). Once a file is > registered to the project the details of the fonts in it may be seen > in the font list dialog (see image) so that the logical font names, > variations, and their available styles are available for use in the > project. > This says "see image", but doesn't indicate *which* image. And:  OpenSCAD doesn't have the notion of "projects" or "registered to the project". > > 3D Text by Extrusion > This is true of all 2D objects and so does not need to be mentioned.  Delete. > position > a vector [X,Y], the origin of the first glyph, thus the lower-left > corner of the drawn text. > No, it's not the origin of the first glyph, or at least that's a confusing phrase to use.  A glyph is usually positioned slightly to the right of the origin, and if it's a descender then it's below the origin, and some characters (e.g. quotes) are well above the origin.  A more correct statement would be that it's the lower left corner of the bounding box of the text. If one is going to talk about the origin of a glyph, it should be the point on the baseline to at the left edge of the advance... which this isn't. > size > a vector [a,b], the size of the generated text. > Should be [x,y].  [a,b] doesn't tell you what "a" and "b" mean. > ascent > positive float, the amount that the text extends above the baseline. > Use the word "number" rather than "float". It's not always positive; for a glyph entirely below the baseline (like underscore in Liberation Sans) it's negative.  (I'm not sure that's truly the right definition, but it's the current behavior.) > descent > negative float, the amount that the text extends below the baseline. > Not always negative; for a glyph that is entirely above the baseline (like apostrophe in Liberation Sans) it's positive. Again, I'm not sure that's the right definition, but it's the current behavior. > offset > a vector default [0, 0], the lower-left corner of the box > containing the text, including inter-glyph spacing before the > first glyph. > There is no default; this is a value that's returned to you. This is not the correct definition (and it wasn't correct in the original that I wrote).  It's the position of the origin of the text, after adjusting for halign and valign.  For normal LTR text, the X coordinate is the X coordinate at the left edge of the first glyph's advance, and the Y component is the Y coordinate of the baseline. > advance > a vector default [153.09, 0], amount of space to leave to any > following text. > There is no default (and certainly not that one!). The original definition ("the "other end" of the text, the point at which additional text should be positioned.") wasn't great, but was more correct.  I would say "The point at which additional text should be positioned, relative to the text's origin as reported by 'offset'.". > This example displays the text metrics for the default font used by > OpenSCAD: > "text metrics for ... font" is a non sequitur.  Text metrics measure a particular string.  (And "used by OpenSCAD" is unnecessary; the entire document is in that context.) And it's incorrect; the default font is Liberation Sans and this example uses Liberation Serif. Better would be: This example displays the text metrics for "Hello, World!" for Liberation Serif with size=20: > <https://en.wikibooks.org/wiki/File:OpenSCAD_textmetrics.png>Using > textmetrics() to draw a box around text > > s="Hello, World!"; > size=20; > font="Liberation Serif"; > translate([0,0,1]) > text("Hello, World!",size=size,font=font); Should use "s" instead of repeating the string.  (And this is in my original, sigh.) > displays (formatted for readability): > The original "yields" is better, because it might or might not be displayed. > ECHO:{ > position=[0.7936,-4.2752]; > size=[149.306,23.552]; > ascent=19.2768; > descent=-4.2752; > offset=[0,0]; > advance=[153.09,0]; > } The indentation should match the examples, with the close brace at the left margin. > > fontmetrics() > > size > Decimal, optional. The size of the font, as described above > for|text()|. > Replace "decimal" with "number". > > 0% developed  as of November 17, 2009 > <https://en.wikibooks.org/wiki/Help:Development_stages>3D to 2D > Projection > <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/3D_to_2D_Projection> > > Using the|projection()|function, you can create 2d drawings from 3d > models, > So far so good. > >  and export them to the dxf format. > This part should be deleted.  There are any number of things you might do with a 2D projection of a 3D object.  Exporting to DXF is only one. >  It works by projecting a 3D model to the (x,y) plane, with z at 0. > If|cut=true|, only points with z=0 are considered (effectively cutting > the object), with|cut=false|(/the default/), points above and below > the plane are considered as well (creating a proper projection). > > *Example*: Consider example002.scad, that comes with OpenSCAD. > > <https://en.wikibooks.org/wiki/File:Openscad_projection_example_2x.png> > > Then you can do a 'cut' projection, which gives you the 'slice' of the > x-y plane with z=0. > Doing the non-default case as the first example seems wrong; I would swap the two examples. > *Another Example* > > You can also use projection to get a 'side view' of an object. > This example seems unnecessary for a reference manual.  It's a straightforward combination of the features described. > Links: > > * More complicated example > <http://www.gilesbathgate.com/2010/06/extracting-2d-mendel-outlines-using-openscad/>from > Giles Bathgate's blog > Seems inappropriate for a reference manual.  Also, doesn't seem more complicated at all. > 0% developed  as of November 17, 2009 > <https://en.wikibooks.org/wiki/Help:Development_stages>2D to 3D > Extrusion > <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/2D_to_3D_Extrusion> > > Extrusion <https://en.wikipedia.org/wiki/Extrusion>is the process of > creating an object with a fixed cross-sectional profile. OpenSCAD > provides two commands > "Commands" isn't the right word.  "Modules" is more correct, but "operations" is probably best. > Both extrusion methods work on a (possibly disjointed) 2D shape > normally drawn in the relevant plane (see below). > The old description of the behavior of extrusion for 2D objects that have been moved off the Z=0 plane is an example of something that should never have been documented.  It's not a particularly useful behavior, and we might eventually want a different behavior.  At most, it should have said "don't do that". It should probably say "drawn on the Z=0 plane". > This child object is first projected onto the X-Y plane along the Z > axis to create the starting face of the extrusion. > Delete.  We shouldn't document that behavior. > The start face is duplicated at the Z position given by the height > parameter to create the extrusion's end face. The extrusion is then > formed by creating a surface that joins each point along the edges of > the two faces. > That's a seriously incomplete description, because it's only true with all of the parameters at their defaults. > The 2D shape may be any2D primitive shape > <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/2D_Primitives>, > a2d polygon > <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/2D_Primitives#Polygon>, > animported 2D drawing > <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/2D_Primitives#Importing_a_2D_Drawing>, > or aboolean combination > <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/CSG_Modelling>of them. > Or, in other words, the 2D shape may be ... a 2D shape. Delete the whole sentence. > The 2D shape may have a Z value that moves it out of the X-Y plane, > and it may even be rotated out of parallel with it. As stated above, > the extrusion's starting face is the projection of the 2D shape onto > the X-Y plane, which, if it is rotated, will have the effect of > fore-shortening it normal to the axis of the rotation. > Delete. > Using a 3D object as the extrusion's child will cause a compile time > error. > Factually incorrect.  It's not a compile-time error; it's a run-time error. Also, we just said that the child must be a 2D shape.  Exact behavior when that requirement is violated need not be (and probably should not be) specified. Delete. > Including a 3D object in a composition of 2D objects (formed using > boolean combinations on them) will be detected, the 3D object(s) will > be deleted from it and the remaining 2D objects will be the basis for > projecting their shape onto the X-Y plane. > We need not (and generally should not) specify the behavior in error conditions.  Delete. > Parameters For Linear Extrusion > > There are no required parameters. The default operation is to extrude > the child by 100 units vertically from the X-Y Plane, centered on the > [0,0] origin. > "centered" is at best meaningless (because it's extruded wherever the child is, without respect to the origin) and at worst incorrect (because the default is to extrude into +Z, not to center in Z). Delete that last phrase. > 1) height > a non-negative integer, default 100, giving the length of the > extrusion > Doesn't have to be an integer. I don't know how strong a pattern we have for specifying parameters, but they shouldn't be numbered.  (Except maybe if they are usable as positional parameters - which don't match these numbers.) > 2) v - twist axis vector > a vector of 3 signed decimal values, default [0,0,1], used as an > eigen vector specifying the axis of rotation for the > twist.[Note:Requires versionDevelopment snapshot] > I can't say that I truly understand eigenvectors, but I don't think this is one.  The "signed" part is unnecessary, because all numbers are signed, and the "decimal" part is meaningless because abstract numbers have no base. "v" is a vector of three numbers that controls the vector along which the extrusion is done. It has an interesting interaction with "height".  If both are specified, height is used as the length of the extrusion, along the direction that v points, and v's magnitude is ignored.  If only v is specified, it is used to control both the direction and length of the extrusion. Saying that it's the axis of rotation for twist is sort of right, but maybe needs more explanation.  Normally when you think of an axis of rotation, you're rotating along the plane perpendicular to that axis.  Here, though, it is perhaps more correct to say that it controls the *origin* of the rotation.  At each slice, the 2D shape is rotated around Z, with the origin being the XY position of the extrusion vector. > 3) center > a boolean, default false, that, when true, causes the resulting > solid to be vertically centered at the X-Y plane. > "at the Z=0 plane" would be a bit more obvious. > 4) convexity > a non-negative integer, default 1, giving a measure of the > complexity of the generated surface. See the Section on Convexity > later on this page. > Should include a link... which should not be pointing at this page, no matter which page we're talking about. > 5) twist > a signed decimal, > a number >  180 degrees is a half twist, 360 is all the way around, and so on. > Unnecessary, delete. > 6) scale > either : a non-negative, decimal value, > a non-negative number > minimum 0.0, > Implied by "non-negative", delete. >  that specifies the factor by which the end face should be scaled > up, or down, in size from that of the start face. > All scaling is either up or down.  Just "should be scaled". > or : an [x,y] vector that scales the extrusion in the X and Y > directions separately. > Delete the colon. > 7) slices > a non-negative integer for the number of rows of polygons that the > extr. > Needs help. > h > a named parameter, synonym to height > Just list it in the same block as height. > $fn $fs $fa > Special Parameters - given as named parameters. > They have standard special-variable semantics, which means they can be specified in the context or in the call.  They should be mentioned, but perhaps not as parameters per se.  I believe they only affect twisted extrusions, so maybe they should be mentioned there. > Center > > This parameter affects only affects the vertical position or the > extrusion. Its X-Y position is always that of the projection that sets > its starting face. > "or" should be "of". This is a nice comment, but doesn't say what the parameter *does*. "When true, the extrusion is centered vertically around Z=0." seems adequate to me, without any further comment, but a subsequent comment about not affecting X and Y would be OK. > Scale > > This is multiplicative factor that affects the size of extrusion's end > face. As such 1.0 means no change, a value greater than one expands > the end face, and a value between 0.001 and less than 1 shrinks it. > "As such" is unnecessary. I don't know where 0.001 came from.  I would say "a value less than 1 shrinks it". >  A value of 0.0 causes the end face to degenerate to a point, turning > the extrusion into a pyramid, cone, or complex pointy shape according > to what the starting shape is. > I'd say this is unnecessary. > Using the vector form sets the scale factor in the X and Y directions > separately > > > Twist > > Twist is applied, by default, as a rotation about the Z Axis. > As discussed above, twist is always around Z.  What v controls is the origin of that rotation. > When the start face is at the origin a twist creates a spiral out of > any corners in the child shape. If the start face is translated away > from the origin the twist creates a spring shape. > I don't know if it's truly useful to try to describe the various shapes that can result from twisting. One thing that might be worth explicitly mentioning is that you can't practically use linear_extrude to generate threads.  You can come temptingly close, but they won't be shaped right.  (It is actually possible to get right, but requires an unobvious base shape.) > A positive twist rotates clockwise, negative twist the opposite. > Huh.  I basically never use twist, so I never noticed that it's backwards from rotate.  That seems very wrong... and it's way too late to fix it.  It might be worth mentioning this difference. > Twist Axis Vector > > The second parameter is an [x,y,z] eigen vector that specifies the > axis of rotation of the applied twist. > Suggest referring to it by name instead of by position. >  The ratios of the three dimensional values to their respective > coordinate axes specify the tilt away from the default axis, [0,0,1], > the Z-Axis. For instance, v=[cos(45),0,1] tilts the extrusion at 45 > degrees to the X axis. > It's actually a skew rather than a tilt. > The start and end faces are always normal to the Z-axis, even when the > twist axis is tilted. The extruded and twisted surfaces are thus > distorted from what might be expected in an extruded shape. The more > expected result may be achieved by applying a rotation to then twisted > extrusion on the Z Axis to tilt it into the desired position. > It's best not to make assumptions about what the user expects. Describe the operation, and describe it carefully.  Do not describe how to do things that are straightforward combinations of operations. --- Note that the documentation does not discuss which happens first:  twist or scale.  I don't believe it matters when using the same scaling for X and Y, but matters a great deal with using different scaling on the two axes.  It twists and then scales, which can mean (for instance) that a shape that started out rectangular turns into a parallelogram.  There's an argument that this is *not* the useful behavior, and that scale-and-then-twist is more useful since it retains the general shape throughout the extrusion.  I've started a discussion a few times about maybe changing this, but I don't think it ever came to a conclusion.  It might be best not to document this without that conclusion. > $fn, $fa, $fs Special Parameters > > The special variables must be given as named parameters and are > applied to the extrusion, overriding the global setting. When the same > special variables are set on the base shape its values override their > use as parameters on the extrusion. > None of this is really accurate. The special variables have standard special-variable behavior, which means that you can specify them in the context or in the particular call, and they apply to that context (including a specific call) and everything that that is called from that context.  There is no "global setting" that is special. What matters for the linear_extrude (and in particular for twisted extrusions) is the setting that *it* sees. If the child 2D shape *also* uses these variables, what matters for it is what *it* sees... which, absent an inner setting, will be the same as what linear_extrude sees. Thus, either: linear_extrude(height=10, twist=20, $fn=100) circle(10); or $fn=100; linear_extrude(height=10, twist=20) circle(10); will yield a high-resolution twist of a high-resolution circle. On the other hand, either linear_extrude(height=10, twist=20, $fn=100) circle(10, $fn=3); or $fn=100; linear_extrude(height=10, twist=20) circle(10, $fn=3); will yield a high-resolution twist of a low-resolution circle - a triangle. > > Extrusion From Imported DXF > Does not need to be discussed.  You can linear_extrude any 2D shape, and an import of a DXF yields a 2D shape. > > A Unit Circle with No Twist > I don't think all of these examples are necessary. > Generate an extrusion from a circle 2 units along the X Axis from the > origin, > unit circle > centered vertically on the X-Y plane, with no twist. The extrusion > appears to have a pentagonal cross-section because the extrusion's > child is a 2D circle with the default value for $fn. > It doesn't *appear* to have a pentagonal cross-section.  It *does* have a pentagonal cross-section. > The same circle, but made into a spiral by 500 degrees of > counter-clockwise twist. > If you look carefully, this example demonstrates why you can't make threads.  As you twist it more, it becomes thinner and thinner in Z.  The problem is that the cross-section of a thread is a strange shape. > Mesh Refinement > > The slices parameter defines the number of intermediate points along > the Z axis of the extrusion. > I am not sure of the exactly right way to describe this, because of fence post errors. "slices" controls the number of 3D "chunks" that make up the extrusion.  The total number of instances of the original 2D object is slices+1. > Its default increases with the value of twist. > It's some function of that and $fa/$fs/$fn.  I don't know what the function is or exactly how to describe it. > Additional the segments parameter > Addition -> Additionally > Segments need to be a multiple of the polygon's fragments to have an > effect (6 or 9.. for a circle($fn=3), 8,12.. for a square() ). > I don't know what the actual behavior is, but that's not it.  For more complex shapes (I experimented with a right triangle) intermediate values do have an effect. > Thespecial variables > <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Other_Language_Features>$fn, > $fs and $fa can also be used to improve the output. If slices is not > defined, its value is taken from the defined $fn value. > Again, I don't know what the behavior is, but that's not it. Increasing $fn does increase the number of slices, but it isn't simply used as the number of slices. $fa/$fs/$fn seem to control both slices and segments. > > Using with imported SVG > Does not need to be separately discussed. > rotate_extrude() Operator Module > > Rotational extrusion spins a 2D shape around the Z-axis to form a > solid which has rotational symmetry. One way to think of this > operation is to imagine a Potter's wheel placed on the X-Y plane with > its axis of rotation pointing up towards +Z. Then place the to-be-made > object on this virtual Potter's wheel (possibly extending down below > the X-Y plane towards -Z). The to-be-made object is the cross-section > of the object on the X-Y plane (keeping only the right half, X >= 0). > That is the 2D shape that will be fed to rotate_extrude() as the child > in order to generate this solid. Note that the object started on the > X-Y plane but is tilted up (rotated +90 degrees about the X-axis) to > extrude. > I'm not sure that this is the best possible explanation. > Since a 2D shape is rendered by OpenSCAD on the X-Y plane, an > alternative way to think of this operation is as follows: spins a 2D > shape around the Y-axis to form a solid. The resultant solid is placed > so that its axis of rotation lies along the Z-axis. > That's the way that I always think of it, though I mentally rotate it to vertical before spinning it. > Just like the linear_extrude, the extrusion is always performed on the > projection of the 2D polygon to the XY plane. > Again, we should not document this behavior. > Transformations like rotate, translate, etc. applied to the 2D polygon > before extrusion modify the projection of the 2D polygon to the XY > plane and therefore also modify the appearance of the final 3D object. > > * A translation in Z of the 2D polygon has no effect on the result > (as also the projection is not affected). > * A translation in X increases the diameter of the final object. > * A translation in Y results in a shift of the final object in Z > direction. > * A rotation about the X or Y axis distorts the cross section of the > final object, as also the projection to the XY plane is distorted. > This is perhaps good stuff, if the part about projecting is removed. > Don't get confused, as OpenSCAD displays 2D polygons with a certain > height in the Z direction, so the 2D object (with its height) appears > to have a bigger projection to the XY plane. But for the projection to > the XY plane and also for the later extrusion only the base polygon > without height is used. > Once you get rid of the part about projecting this goes away too. > You cannot use rotate_extrude to produce a helix or screw thread. > Doing this properly can be difficult, so it's best to find a thread > library to make them for you. > This kind of comment can be valuable, but I'm not sure it belongs in a reference manual.  If it *is* in a reference manual, it should be in a clear and separate section (of the description of the particular feature) marked "Application Notes" or something like that, to make it clear that it's *not* part of the description of the feature. > If the shape spans the X axis a warning appears in the console windows > and the rotate_extrude() is ignored. > Don't talk about what window something appears in, because not everybody uses the OpenSCAD GUI. Don't talk about what happens "after" the error. Just say that it's an error, period. (And, BTW, this particular one is something that I think should not be an error; I think that the result should be as if you split the 2D shape in half, rotationally extruded both, and unioned them.  That is, take the shape, sweep it 360 degrees, and anything it sweeps through (whether once or twice) is part of the result.) >  If the 2D shape touches the Y axis, i.e. at x=0, it*must*be a line > that touches, not a point, as a point results in a zero thickness 3D > object, which is invalid and results in a CGAL error. > This may have been addressed with Manifold. > *convexity* : If the extrusion fails for a non-trival 2D shape, > try setting the convexity parameter (the default is not 10, but 10 > is a "good" value to try). See explanation further down. > Just point at the general discussion of convexity.  (Which should not be on this page.) And the extrusion does not "fail".  In fact, the artifacts may be quite subtle. > *start*[Note:Requires versionDevelopment snapshot] : Defaults to 0 > if*angle*is specified, and 180 if not. Specifies the starting > angle of the extrusion, counter-clockwise from the positive X axis. > start was part of an effort to align rotational extrusion behavior with the behavior of other round things.  I don't remember all of the details, but there are few reasons why it isn't equivalent to rotating the result. > *$fa* : minimum angle (in degrees) of each fragment. > *$fs* : minimum circumferential length of each fragment. > *$fn* :*fixed*number of fragments in 360 degrees. Values of 3 or > more override $fa and $fs > > $fa, $fs and $fn must be named parameters.click here for more > details, > <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Other_Language_Features>. > Do not describe these in detail here.  Refer to a general description of them elsewhere. Do not ever, ever, say "click here".  Any text that would not make sense when printed is wrong. > Rotate Extrude on Imported DXF > Delete. > Increasing the number of fragments composing the 2D shape improves the > quality of the mesh, but takes longer to render. > Unnecessary. > rotate_extrude(convexity = 10) > translate([2, 0, 0]) > circle(r = 1, $fn = 100); This example is unnecessary; this is a description of rotate_extrude, not circle() > The number of fragments used by the extrusion can also be increased. > > rotate_extrude(convexity = 10, $fn = 100) > translate([2, 0, 0]) > circle(r = 1, $fn = 100); Use $fs and $fa here.  In fact, supply them at the top level. And this case doesn't require specifying convexity (though I'm not sure why not).  Also, for circles this small high resolution is not practical; make them bigger to make the example more real. Thus: $fa = 1; $fs = 1; rotate_extrude() translate([20, 0, 0]) circle(r = 10); That's really the best practice.  You almost never want to use $fn if your intent is to create a circle. (Minor exception that is itself something of a bug:  if you're trying to force the number of sides to be a multiple of 4.  But that shouldn't be discussed here.) > Using the parameter angle (with OpenSCAD versions 2016.xx), a hook can > be modeled . > > <https://en.wikibooks.org/wiki/File:Hook.png>OpenSCAD - a hook > > eps = 0.01; > translate([eps, 60, 0]) > rotate_extrude(angle=270, convexity=10) > translate([40, 0]) circle(10); > rotate_extrude(angle=90, convexity=10) > translate([20, 0]) circle(10); > translate([20, eps, 0]) > rotate([90, 0, 0]) cylinder(r=10, h=80+eps); Delete. > Extruding a Polygon > Delete. > Description of extrude parameters > Why are we repeating these here?  Don't, especially because there is little commonality between linear_extrude and rotate_extrude. > 0% developed  as of November 17, 2009 > <https://en.wikibooks.org/wiki/Help:Development_stages>DXF > Extrusion > <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/DXF_Extrusion> > Delete. > > Import 2D > > Import 2D Shapes > <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Import_2D> > This should get more content.  At the current state of things it can probably all go on the 2D page, but if it gets much more complex it might want its own page with a brief summary and reference here.
RD
Revar Desmera
Fri, Aug 8, 2025 8:14 AM

For the record, several modules in BOSL2 that can create multiple copies of a shape, create $idx (or similar) special variables in their scope, that the child modules can use to change their behavior.  For example:

xcopies(10,n=4) circle(d=$idx+1);

will create four circles of increasing diameter, spread every 10 units along the X axis.

  • Revar

On Aug 8, 2025, at 1:06 AM, Jordan Brown via Discuss discuss@lists.openscad.org wrote:

[ Sigh yet again... what e-mail address I use is largely automatically handled on my desktop, but not on this laptop. ]

Mattheiu is right; this needs a subject change.

On 8/6/2025 12:51 AM, vulcan_--- via Discuss wrote:

One should not attempt to infer the API contract from the behavior.

umm .. then how better to understand it?

Reread the documentation.  Repeat repeat repeat.  Then ask and/or inspect the sources.  Behavior is good only for very targeted questions, and even then should be tempered by the others.

i am not at all clear what overfit means ..

He means that you may assume that the behavior that you see is the only possible behavior.  (For instance, you may assume that some particular triangularization (or lack thereof) is the promised answer, and it isn't.)

Yeah, specials are still a fuzzy thing for me .. even after Jordan’s diligent attempt to educate me on how they work i am not at all clear on what they bring to the language that is any different from having global variables at the top level of scope

They aren't necessarily at the top level.  Try running this...

normal = "top";
$special = "top";

module foo() {
echo(normal=normal, $special=$special);
}

module bar() {
$special = "bar";
normal = "bar";
foo();
}

foo();
foo($special="top per-call");
bar();
echo(normal=normal, $special=$special);

Normal variables are scoped based on the program's static structure, so "normal" is visible from the top, from foo(), and from bar() until the definition of the new "normal" on bar's second line.  Nothing ever refers to bar's definition of "normal".

Special variables ($ variables) are scoped based on the call stack.  The initial setting ("top") is visible at the top level, and in anything called from the top level - which means the top-level call to foo(), and the call to bar() until bar's first line, where a new $special is created ("bar").  That new $special is visible to bar() and to everything that bar() calls - notably, its call to foo().  The second call to foo() sets $special in the call, and that setting applies to that call to foo() and everything that it calls (which is nothing).

Another way to put it:

For a normal variable, to find the assignment, start at the reference to the variable, then look at that scope.  If it's defined there, you're done.  Move to the next higher scope (one fewer level of braces).  If it's defined there, you're done.  Continue until you reach the top scope.

For a special variable, look at the current scope.  If it's defined there, you're done.  Move to the place that called this module; look at the scope there.  If it's defined there, you're done.  Continue until you reach the top scope.

It's actually a little more complicated than that, in in both cases that a reference in an assignment needs to look at earlier assignments in that scope.


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

For the record, several modules in BOSL2 that can create multiple copies of a shape, create $idx (or similar) special variables in their scope, that the child modules can use to change their behavior. For example: xcopies(10,n=4) circle(d=$idx+1); will create four circles of increasing diameter, spread every 10 units along the X axis.  - Revar > On Aug 8, 2025, at 1:06 AM, Jordan Brown via Discuss <discuss@lists.openscad.org> wrote: > > [ Sigh yet again... what e-mail address I use is largely automatically handled on my desktop, but not on this laptop. ] > > Mattheiu is right; this needs a subject change. > > On 8/6/2025 12:51 AM, vulcan_--- via Discuss wrote: >> One should not attempt to infer the API contract from the behavior. >> >> umm .. then how better to understand it? >> > Reread the documentation. Repeat repeat repeat. Then ask and/or inspect the sources. Behavior is good only for very targeted questions, and even then should be tempered by the others. > >> i am not at all clear what overfit means .. >> > He means that you may assume that the behavior that you see is the only possible behavior. (For instance, you may assume that some particular triangularization (or lack thereof) is the promised answer, and it isn't.) > > >> Yeah, specials are still a fuzzy thing for me .. even after Jordan’s diligent attempt to educate me on how they work i am not at all clear on what they bring to the language that is any different from having global variables at the top level of scope >> > > They *aren't* necessarily at the top level. Try running this... > > normal = "top"; > $special = "top"; > > module foo() { > echo(normal=normal, $special=$special); > } > > module bar() { > $special = "bar"; > normal = "bar"; > foo(); > } > > foo(); > foo($special="top per-call"); > bar(); > echo(normal=normal, $special=$special); > > Normal variables are scoped based on the program's static structure, so "normal" is visible from the top, from foo(), and from bar() until the definition of the new "normal" on bar's second line. Nothing ever refers to bar's definition of "normal". > > Special variables ($ variables) are scoped based on the call stack. The initial setting ("top") is visible at the top level, and in anything called from the top level - which means the top-level call to foo(), and the call to bar() until bar's first line, where a new $special is created ("bar"). That new $special is visible to bar() and to everything that bar() calls - notably, its call to foo(). The second call to foo() sets $special in the call, and that setting applies to that call to foo() and everything that it calls (which is nothing). > > Another way to put it: > > For a normal variable, to find the assignment, start at the reference to the variable, then look at that scope. If it's defined there, you're done. Move to the next higher scope (one fewer level of braces). If it's defined there, you're done. Continue until you reach the top scope. > > For a special variable, look at the current scope. If it's defined there, you're done. Move to the place that called this module; look at the scope there. If it's defined there, you're done. Continue until you reach the top scope. > > It's actually a little more complicated than that, in in both cases that a reference in an assignment needs to look at earlier assignments in that scope. > > > > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org
JB
Jordan Brown
Fri, Aug 8, 2025 8:21 AM

On 8/8/2025 1:14 AM, Revar Desmera via Discuss wrote:

For the record, several modules in BOSL2 that can create multiple
copies of a shape, create $idx (or similar) special variables in their
scope, that the child modules can use to change their behavior.  For
example:

    xcopies(10,n=4) circle(d=$idx+1);

will create four circles of increasing diameter, spread every 10 units
along the X axis.

Yes.  This capability - passing special variables from parent to child -
is implied by the "the scope it's defined in and all scopes called from
that scope" rule.

It does point out one subtle aspect of the semantics:  the top level
does not "call" circle() in this case.  Rather, xcopies() calls it (via
children() and the particular call supplied by the top level.  I don't
remember exactly what thread it was, but there's been a significant
discussion about the need for documentation to discuss this behavior,
while at the same time keeping the description of the  "rotate() cube()"
case simple.

On 8/8/2025 1:14 AM, Revar Desmera via Discuss wrote: > For the record, several modules in BOSL2 that can create multiple > copies of a shape, create $idx (or similar) special variables in their > scope, that the child modules can use to change their behavior.  For > example: > >     xcopies(10,n=4) circle(d=$idx+1); > > will create four circles of increasing diameter, spread every 10 units > along the X axis. Yes.  This capability - passing special variables from parent to child - is implied by the "the scope it's defined in and all scopes called from that scope" rule. It does point out one subtle aspect of the semantics:  the top level does not "call" circle() in this case.  Rather, xcopies() calls it (via children() and the particular call supplied by the top level.  I don't remember exactly what thread it was, but there's been a significant discussion about the need for documentation to discuss this behavior, while at the same time keeping the description of the  "rotate() cube()" case simple.
AM
Adrian Mariano
Fri, Aug 8, 2025 10:34 AM

A note on the fontfeatures option in the font name.  The text says it has
to be a plus sign followed by a feature name.  But actually it can also be
<featurename>=<value>, such as smcp=1 instead of +smcp, but in the case of
the font I was looking at, frac=1 and frac=2 produce different
results----it's not a boolean setting.  And yes, this means it looks like
fontfeatures=frac=2.

On Fri, Aug 8, 2025 at 4:14 AM Jordan Brown via Discuss <
discuss@lists.openscad.org> wrote:

[ I'll spend the effort to fix up this laptop configuration, again, sorry
for the duplicates. ]

Two Dimensional Modelling
[image: 0% developed  as of November 17, 2009]
https://en.wikibooks.org/wiki/Help:Development_stages 2D Primitives
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/2D_Primitives

All 2D primitives can be transformed with 3D transformations.

Really bad place to start.  Yes, you can transform them with 3D
transforms, but if you do then the results can be weird.  It should be
discouraged; you should almost always work with 2D transforms when working
with a 2D subassembly.

Also, maybe we should talk about the primitives before we talk about what
you can do with them.

They are usually used as part of a 3D extrusion.

Yeah, eventually.  But again this doesn't seem appropriate for a "2D
primitives" section.  Maybe for an overview section above that.

Although they are infinitely thin, they are rendered with a 1-unit
thickness.

Again, maybe in an overview section.

Note: Trying to subtract with difference() from 3D object will lead to
unexpected results in final rendering.

The real rule is "don't mix 2D objects with 3D objects and 3D
operations".  It isn't necessary or appropriate to say very much about what
will happen if you do.  Some cases will yield errors, while others will do
something weird.  We don't want the documentation to nail down any
particular behavior, because there are reasons that we might want to change
the behavior in these cases.

Ref, e.g., OEP 7 "Mixed Dimension Geometry Support"
https://github.com/openscad/openscad/wiki/OEP7%3A-Mixed-Dimension-Geometry-Support
.

Square Object Module

By default this module draws a unit square in the first quadrant, (+X,+Y),
starting at the origin [0,0]. Its four lines have no thickness but the
shape is drawn as a 1 unit high, filled plane.

The second sentence should probably just go away:

- The first part "its four lines have no thickness" is both misleading
- the lines have no independent existence - and incorrect; when rendered
they *do* have thickness.
- The second half (drawn as 1 unit high) restates something already
said in above.

The module's arguments may be written in the order <size>, center=<bool> without
being named, but the names may be used as shown in the examples:

There needs to be (but probably isn't) enough documentation convention
that this need not be said.

Parameters
size has two forms: single value or vector single - non-negative
float, length of all four sides

Should use the word "number" rather than the word "float".  OpenSCAD does
not have distinct floating point and integer types; it has only numbers.

center boolean, default false, to set the shape's position in the X-Y
plane

Center When false, as it is by default, the shape will be drawn from
its first point at (0,0) in the First Quadrant, (+X,+Y). With center set to
true the shape is drawn centered on the origin.

These two paragraphs should be merged.

Circle Object Module

By default this module draws a unit circle centered on the origin [0,0] as
a pentagon with its starting point on the X-axis at X=1. Its lines have no
thickness but the shape is drawn as a 1 unit high, filled plane.

The part of the first sentence starting "as a pentagon ..." should go
away.  It's true, but it really belongs as part of the description of
$fa/$fs.

Again, the second sentence should just go away.

Somewhere it should say "Circles are approximated as regular polygons; see
<reference to $fa/$fs/$fn> for the details of the polygons generated."

The argument radius may be given without being named, but the r and d arguments
must be named.

There is no "radius" argument.  There are r and d.

Again, we should have a documentation convention so that we don't have to
repeat positional/named rules, but the behavior here is that r can be
supplied as the first argument, but d must be named.

(Technically, if you say "circle(undef, 10)" the 10 is the second  it
creates a 10-unit-diameter circle.  I would say that the fact that this
works is a minor bug.)

$fa Special Variable $fs Special Variable $fn Special Variable

Theses should be described only to the extent of pointing at the general
description of $fa/$fs/$fn.

The default circle displays as a pentagram as that is the minimum number
of fragments used to approximate a curved shape calculated from the default
values for $fs and $fa. To have it draw as a smooth shape increase the $fn
value, the minimum number of fragments to draw, to 20 or more (best $fn <
128).

This is just bad.  First, everything here should be covered in the
description of $fa/$fs/$fn.  Second, using $fn to control the resolution of
a circle is generally the wrong answer; you are better off setting $fa and
$fs.  Finally, specific advice on $fn values is a bad idea, because the
"looks smooth" value varies dramatically with size.  A 20-gon is okay for a
medium-small circle; a 72-gon is not good enough for a 100-unit circle.

An alternative method to draw a very smooth circle scale is to scale down
a very large circle.

scale( 0.001 ) circle(200);

This should just go away; it confuses the issue.

Another way to solve the lack of a built-in module for regular polygons is
to write a custom one: module regular_polygon()
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/example_module_regular_polygon()

I wouldn't include this.  Using polygon() is harder than using circle(),
and anybody who's capable of using it should have little trouble simulating
circle().

convexity Integer, default=1 - complex edge geometry may require a higher
value value to preview correctly.

Should include a link to a general discussion of convexity.  Probably
should not even mention the default; that should be covered in the general
discussion.

Points Parameter A list of X-Y coordinates in this form:

[[1, 1], [1, 4], [3, 4], [3, 1], [1, 1]]

which defines four points and makes it explicit that the last one is the
same as the first.

Including the first point twice is not strictly necessary as this:

[[1, 1], [1, 4], [3, 4], [3, 1]]

gives the same result.

This seems like it should be simplified.  In the absence of a paths
parameter, the last point always connects to the first, because polygons
are always closed.

Paths Parameter

This optional parameter is a nested vector of paths.

A "path" is a list of index values that reference points in the points vector.
It can explicitly describe a closed loop by its last index being the same
as its first, as in:

[1, 2, 3, 4, 1]

but this is equivalent to:

[1, 2, 3, 4]

Again, this seems like unnecessary complexity; the last point always
connects to the first.

Notice that the points vector is simple list,

No, it's a list of lists.

while each path is a separate vector.

Yes... points and paths are the same order. They are both lists of lists.

This means that paths, that are lists of references to points, have to
"know" which points it needs to include.

While it's true that paths need to "know" the indexes they connect, I
don't see how that follows from the previous sentences.

This can be an issue if the polygon is assembled from a number of shapes
at run time as the order of adding shapes affects their point's index
values.

It's true that this is something that you must handle, but I don't think
that a reference manual needs to discuss it.

. Convexity

Formatting error:  this title is merged with the previous paragraph. (But
should be deleted, see below.)

Shapes with a lot of detail in their edges may need the convexity
parameter increased to preview correctly. See Convexity

Already discussed, should be deleted.

Example With Multiple Holes

[Note: Requires version 2015.03] (for use of concat())

https://en.wikibooks.org/wiki/File:OpenSCAD_romboid_with_holes.jpg

We are using "a" for the point lists and "b" for their paths:

a0 = [[0,0],[100,0],[130,50],[30,50]];    // outer boundary
b0 = [1,0,3,2];
a1 = [[20,20],[40,20],[30,30]];            // hole 1
b1 = [4,5,6];
a2 = [[50,20],[60,20],[40,30]];            // hole 2
b2 = [7,8,9];
a3 = [[65,10],[80,10],[80,40],[65,40]];    // hole 3
b3 = [10,11,12,13];
a4 = [[98,10],[115,40],[85,40],[85,10]];  // hole 4
b4 = [14,15,16,17];
a  = concat( a0,a1,a2,a3,a4 ); // merge all points into "a"
b  = [b0,b1,b2,b3,b4]; // place all paths into a vector
polygon(a,b);
//alternate
polygon(a,[b0,b1,b2,b3,b4]);

The "alternate" at the end of the example seems unnecessary - of course
you can use either a particular expression or a variable that has been set
to that expression.

2D to 3D by Extrusion

A polygon may be the basis for an extrusion, just as any of the 2D
primitives can. This example script
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/example_module_2D_to_3D_extrusion
may be used to draw the shape in this image:

Yes, a polygon can be used as the basis for extrusion, just as any of the
2D primitives can.  That means that you do not need a specific example of
that case.

Import a 2D Shape From a DXF

[Deprecated: import_dxf()  will be removed in a future release. Use Use import()
Object Module
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/The_OpenSCAD_Language#import
instead. instead*]*

As a deprecated feature, this should be pushed to the bottom.

Read a DXF file and create a 2D shape.

Example

linear_extrude(height = 5, center = true)
import_dxf(file = "example009.dxf", layer = "plate");

Example with Import()

linear_extrude(height = 5, center = true)
import(file = "example009.dxf", layer = "plate");

The second should perhaps be titled "Replacement example with import()".
Note also that since OpenSCAD is case sensitive the word "import" should
not be capitalized.

[image: 0% developed  as of November 17, 2009]
https://en.wikibooks.org/wiki/Help:Development_stages Text
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Text

Text is a big enough topic that it should probably have its own page, with
just a brief mention and cross-reference here.

I see that it has its own page and is transcluded here.  It should not
be transcluded, because that makes it harder to just read everything.

Text in OpenSCAD

Being able to use text objects as a part of a model is valuable in a lot
of design solutions.

Delete this sentence.  This is reference material, not sales material.
The user already knows whether or not it's valuable to them.

The fonts available to use in a script
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Text#Fonts_in_OpenSCAD
are from the system that OpenSCAD is running in with the addition of
those explicitly added by the script itself.

And OpenSCAD includes several.  (And this duplicates a more extensive
discussion below.)

text() Object Module

The text() object module draws a single string of text as a 2D geometric
object, using fonts installed on the local system or provided as separate
font file.

provided as +a+ separate font file

The shape starts at the origin and is drawn along the positive X axis.

By default, ...

(because halign and valign change things)

text String. A single line of any character allowed
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Characters_Strings#Characters
. Limitation: non-printable ASCII characters like newline and tab
rendered as placeholders

Delete the second sentence.  If it's a string, it's allowed.  As for being
a single line and treatment of non-printable characters, need to phrase
that as a current restriction, not as a permanent behavior - it would be
good if we could eventually provide more support there, and we wouldn't
want to be prevented from adding that support by compatibility concerns.
Ref https://github.com/openscad/openscad/issues/5018 for the desire for
multi-line text.

font a formatted string
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Text#Parameters with
default font of "Liberation Sans:style=Regular"

"formatted string" is a poor phrase there.  Better would be something like
"String.  A font specification with ...".

Also I see that this is a link over to a separate Text page.  A separate
Text page is good, as discussed above, but it shouldn't be duplicated here.

size non-negative decimal, default=10. The generated text has a height
above the baseline of approximately this value, varying for different fonts
but typically being slightly smaller.

The "decimal" part should be "number".  (It isn't even sensible to talk
about a base.)

I don't feel the need for the "non-negative" part.  (It should probably
also be non-zero.)  Unless we have a special meaning for a negative size,
we should be able to let people figure out for themselves that if they make
a silly request they will get a silly answer.

Current behavior is ... interesting... though when you think about it
unsurprising:  the text is mirrored in X and Y, leading to it being
effectively rotated 180 degrees.  Unless we really want to keep that
behavior, we should probably make it be an error instead.  Until and unless
we decide that we want to keep that behavior, we should not document it.

There needs to be a footnote about size.  Because of an arithmetic error
in the implementation (issue #4304
https://github.com/openscad/openscad/issues/4304), the "size" parameter
does not correspond to a typical font size specification.  It is a
coincidence that the arithmetic error approximately cancels out the usual
ratio between the specified font size and the size of a capital letter,
making "size" approximately specify the size of a capital letter in a
typical Western font.  However, since the result is useful, and the error
has been in place since the beginning, we really can't fix it.  Maybe at
some point we can introduce an alternative parameter that specifies a more
conventional font size, eg PR#4306
https://github.com/openscad/openscad/pull/4306.

spacing float, default=1. Multiplicative factor that increases or
decreases spacing between characters.

"float" should be "number".

language String. The language of the text (e.g., "en", "ar", "ch").
Default is "en". script String, default="latin". The script of the text
(e.g. "latin", "arabic", "hani").

Somebody needs to figure out what these actually do.

$fn higher values generate smoother curves (refer to Special Variables
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Other_Language_Features#special_variables
)

This should refer to $fa, $fs, and $fn... and really you shouldn't be
using $fn here.

Font & Style Parameter

The "name" of a font is a string starting with its logical font name and
variation,

I don't see variation as a separate part of the specification.

Also, use of the "typewriter" font here is inappropriate; neither of these
is a language keyword or language component.  Either use plain text or
perhaps italics.

optionally followed by a colon (":") separated list of font
specifications like a style selection, and a set of zero or more features.

We should include a list of the name=value specifications supported, or
refer to external (fontconfig?) documentation.

Again, "features" is not a keyword and should not be in typewriter font.

The common variations in a font family are sans and serif though many
others will be seen in the list of fonts available. Each font variation can
be drawn with a style to support textual emphasis.

I think those are part of the font name, and that there they are usually
capitalized.  I'm a bit torn on whether they should be in typewriter font.

The default, upright appearance is usually called "Regular" with "Bold",
"Italic", and "Bold Italic" being the other three styles commonly included
in a font. In general the styles offered by a font may only be known by
using the platform's font configuration tools or the OpenSCAD font list
dialog
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Text#Fonts_in_Openscad
.

This should explicitly tie to the "style=" parameter.

The fontfeatures property is appended to the font name after the

"fontfeatures" should be in typewriter font because it is a keyword.

"font name" should not be in typewriter font because it is not a keyword.

optional style parameter. Its value is a semi-colon separated list of
feature codes, each prefixed by a plus, "+", to indicate that it is being
added,

Should end with a colon, not a comma.

font = "Linux Libertine G:style=Regular:fontfeatures=+smcp;+onum");

Size Parameter

Text size is normally given in points, and a point is 1/72 of an inch
high. The formula to convert the size value to "points" is pt =
size/3.937, so a size argument of 3.05 is about 12 points.

This is incorrect, because OpenSCAD is unitless.  "size" specifies some
dimension of the font, in OpenSCAD units.  See the discussion above about
exactly what dimension it measures. (OpenSCAD units are typically
interpreted as millimeters, but that's up to the user and the consuming
program; it is not part of OpenSCAD's definitions.)

There should be no reference to "points" except perhaps to disclaim that
anything is measured in points.

Note: Character size the distance from ascent to descent, not from
ascent to baseline.

Ref the arithmetic error mentioned above and the long discussion in issue
#4304, this is incorrect.  "size" should have measured approximately the
font ascent plus descent, but instead measures (even more approximately)
the font ascent.

One of these four names must be given as a string to the valign parameter.

Since the valign parameter itself is optional, the word "must" seems
inappropriate.  Perhaps "The valign parameter may be set to one of these
four words".

top The text is aligned so the top of the tallest character in your text
is at the given Y coordinate.

There is no "given Y coordinate".  The top of the tallest character in
your text is at the X axis, Y=0.

center The text is aligned with the center of the bounding box at the
given Y coordinate.

Again, at Y=0.

baseline The text is aligned with the font baseline at the given Y
coordinate.

Again, at Y=0.

bottom The text is aligned so the bottom of the lowest-reaching character
in your text is at the given Y coordinate.

Again, at Y=0.

Note: only the "baseline" vertical alignment option will ensure correct
alignment of texts that use mix of fonts and sizes.

This overlaps a lot with the last sentence of the definition of "baseline"
and should probably be merged with it.

One of these three names must be given as a string to the halign
parameter.

Again, the word "must" seems inappropriate.

left The text is aligned with the left side of the bounding box at the
given X coordinate. center The text is aligned with the center of the
bounding box at the given X coordinate. right The text is aligned with
the right of the bounding box at the given X coordinate.

None of these are correct.  The alignment is based on spacing, not on the
bounding box.  For most letters, "left" will position the ink slightly to
the right of X=0.  (For a size=10 M in Liberation Sans, it's about 1.1
units right of X=0.)  I'd need to do more research to figure out the
exactly correct wording.

And for all of them, there is no "given [XY] coordinate".  Positioning is
relative to the origin.

Spacing Parameter

Characters in a text element have the size dictated by their glyph in the
font being used. As such their size in X and Y is fixed. Each glyph also
has fixed advance values (it is a vector [a,b], see textmetrics
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Text#textmetrics)
for the offset to the origin of the next character. The position of each
following character is the advance.x value multiplied by the space value.
Obviously letters in the string can be stretched out when the factor is
greater than 1, and can be made to overlap when space is a fraction
closer to zero, but interestingly, using a negative value spaces each
letter in the opposite of the direction parameter.

This is more or less correct, but what it doesn't say is that "spacing" is
almost completely useless for a proportionally spaced font, for two
reasons.  Ref https://github.com/openscad/openscad/issues/3859 .

- It does not take ligatures into account; it spaces a ligature as a
single glyph, yielding text that looks like "d i ffi c u l t".
- Because it's a multiplier on the advance value, and because the
advance value is larger for a wide glyph than it is for a narrow glyph,
spacing between narrow glyphs and wide glyphs is radically different.
"IIIMMM" demonstrates this problem.

The "spacing" parameter should probably be downplayed, and should probably
be deprecated.

Text Examples

Simulating Formatted Text

Needs to define what it means by "formatted".

When text needs to be drawn as if it was formatted it is possible to use
translate() to space lines of text vertically. Fonts that descend below the
baseline need to be spaced apart vertically by about 1.4size to not
overlap. Some word processing programs use a more generous spacing of
1.6
size for "single spacing" and double spacing can use 3.2*size.

fontmetrics() can supply more correct values for the particular font.

But really this is advice, not reference material.

Fonts in OpenSCAD

The fonts available for use in a script are thosed:

- registered in the local system
- included in the OpenSCAD installation
- imported at run-time by a program

A call to fontmetrics() using only default settings shows the
installation's standard font and settings:

Any reference to fontmetrics() needs a "requires release XXX" note, which
at the moment is still "requires development snapshot".  But really this
should be at most a reference to the fontmetrics() section.

{
nominal = {
ascent = 12.5733;
descent = -2.9433;
};
max = {
ascent = 13.6109; descent = -4.2114;
};
interline = 15.9709;
font = {
family = "Liberation Sans";
style = "Regular";
};
}

Wherever this ends up, the indentation needs work.  It should match the
indentation style used in the examples.

None of the platforms OpenSCAD is available on include the Liberation font
family so having it as part of the app's installation, and making it the
default font, avoids problems of font availability.

"None" is an awfully broad statement about a moving target.  It would be
better to say "To avoid problems of font availability, OpenSCAD includes
the Liberation font family as part of its installation, and has Liberation
Sans as the default font.".

Note: It was previously noted in the docs that fonts may be added to
the installation by drag-and-drop of a font file into the editor window,
but as of version 2025 Snapshot this is not the case

That isn't what it said.  It said:

You can drag a font in the font list, into the editor window to use in the
text() statement.

I can't readily check a 2025 build at the moment, but as of Oct 2024 the
it does exactly as described:  dragging a font from the OpenSCAD font list
into the editor window drops its name in the editor window.  If that is no
longer the case, it's a bug.

In general, don't say things like this.  If the documentation said X, and
you find that X is not true, then one of the following is true:

- You didn't understand, and X is indeed true.  (And maybe the
documentation needs to be clearer.)
- X is false, and it's a bug.  (The bug should be fixed, not the
documentation.)
- X is false, and has always been false, and it was always a
documentation error.  (And the documentation needs to be fixed.)
- Indeed, X used to be true and is no longer true, and it's an
intentional change, and nobody updated the documentation.  This is a very
rare case, because it often means a compatibility problem or feature
regression.

Regardless, the right answer is to file an issue to get the actual answer.

In the following sample code a True Type Font, Andika, has been added to
the system fonts using its Font Management service.

We shouldn't talk about adding fonts to the system.  That's not our
problem.

But also, that's not what the sample does.  It adds a font to OpenSCAD,
and has nothing to do with the platform font mechanisms.

Supported font file formats are TrueType
https://en.wikipedia.org/wiki/TrueType fonts (.ttf) and OpenType
https://en.wikipedia.org/wiki/OpenType fonts (
.otf). Once a file is
registered to the project the details of the fonts in it may be seen in the
font list dialog (see image) so that the logical font names, variations,
and their available styles are available for use in the project.

This says "see image", but doesn't indicate which image.

And:  OpenSCAD doesn't have the notion of "projects" or "registered to the
project".

3D Text by Extrusion

This is true of all 2D objects and so does not need to be mentioned.
Delete.

position a vector [X,Y], the origin of the first glyph, thus the
lower-left corner of the drawn text.

No, it's not the origin of the first glyph, or at least that's a confusing
phrase to use.  A glyph is usually positioned slightly to the right of the
origin, and if it's a descender then it's below the origin, and some
characters (e.g. quotes) are well above the origin.  A more correct
statement would be that it's the lower left corner of the bounding box of
the text.

If one is going to talk about the origin of a glyph, it should be the
point on the baseline to at the left edge of the advance... which this
isn't.

size a vector [a,b], the size of the generated text.

Should be [x,y].  [a,b] doesn't tell you what "a" and "b" mean.

ascent positive float, the amount that the text extends above the
baseline.

Use the word "number" rather than "float".

It's not always positive; for a glyph entirely below the baseline (like
underscore in Liberation Sans) it's negative.  (I'm not sure that's truly
the right definition, but it's the current behavior.)

descent negative float, the amount that the text extends below the
baseline.

Not always negative; for a glyph that is entirely above the baseline (like
apostrophe in Liberation Sans) it's positive.  Again, I'm not sure that's
the right definition, but it's the current behavior.

offset a vector default [0, 0], the lower-left corner of the box
containing the text, including inter-glyph spacing before the first glyph.

There is no default; this is a value that's returned to you.

This is not the correct definition (and it wasn't correct in the original
that I wrote).  It's the position of the origin of the text, after
adjusting for halign and valign.  For normal LTR text, the X coordinate is
the X coordinate at the left edge of the first glyph's advance, and the Y
component is the Y coordinate of the baseline.

advance a vector default [153.09, 0], amount of space to leave to any
following text.

There is no default (and certainly not that one!).

The original definition ("the "other end" of the text, the point at which
additional text should be positioned.") wasn't great, but was more
correct.  I would say "The point at which additional text should be
positioned, relative to the text's origin as reported by 'offset'.".

This example displays the text metrics for the default font used by
OpenSCAD:

"text metrics for ... font" is a non sequitur.  Text metrics measure a
particular string.  (And "used by OpenSCAD" is unnecessary; the entire
document is in that context.)

And it's incorrect; the default font is Liberation Sans and this example
uses Liberation Serif.

Better would be:

This example displays the text metrics for "Hello, World!" for Liberation
Serif with size=20:

https://en.wikibooks.org/wiki/File:OpenSCAD_textmetrics.pngUsing
textmetrics() to draw a box around text

s = "Hello, World!";size = 20;font = "Liberation Serif";

translate([0,0,1])    text("Hello, World!", size=size, font=font);

Should use "s" instead of repeating the string.  (And this is in my
original, sigh.)

displays (formatted for readability):

The original "yields" is better, because it might or might not be
displayed.

ECHO: {  position = [0.7936, -4.2752];  size = [149.306, 23.552];  ascent = 19.2768;  descent = -4.2752;  offset = [0, 0];  advance = [153.09, 0];  }

The indentation should match the examples, with the close brace at the
left margin.

fontmetrics()

size Decimal, optional. The size of the font, as described above for
text().

Replace "decimal" with "number".

[image: 0% developed  as of November 17, 2009]
https://en.wikibooks.org/wiki/Help:Development_stages 3D to 2D
Projection
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/3D_to_2D_Projection

Using the projection() function, you can create 2d drawings from 3d
models,

So far so good.

and export them to the dxf format.

This part should be deleted.  There are any number of things you might do
with a 2D projection of a 3D object.  Exporting to DXF is only one.

It works by projecting a 3D model to the (x,y) plane, with z at 0. If
cut=true, only points with z=0 are considered (effectively cutting the
object), with cut=false(the default), points above and below the plane
are considered as well (creating a proper projection).

Example: Consider example002.scad, that comes with OpenSCAD.

https://en.wikibooks.org/wiki/File:Openscad_projection_example_2x.png

Then you can do a 'cut' projection, which gives you the 'slice' of the x-y
plane with z=0.

Doing the non-default case as the first example seems wrong; I would swap
the two examples.

Another Example

You can also use projection to get a 'side view' of an object.

This example seems unnecessary for a reference manual.  It's a
straightforward combination of the features described.

Links:

- More complicated example
<http://www.gilesbathgate.com/2010/06/extracting-2d-mendel-outlines-using-openscad/>
 from Giles Bathgate's blog

Seems inappropriate for a reference manual.  Also, doesn't seem more
complicated at all.

[image: 0% developed  as of November 17, 2009]
https://en.wikibooks.org/wiki/Help:Development_stages 2D to 3D Extrusion
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/2D_to_3D_Extrusion

Extrusion https://en.wikipedia.org/wiki/Extrusion is the process of
creating an object with a fixed cross-sectional profile. OpenSCAD provides
two commands

"Commands" isn't the right word.  "Modules" is more correct, but
"operations" is probably best.

Both extrusion methods work on a (possibly disjointed) 2D shape normally
drawn in the relevant plane (see below).

The old description of the behavior of extrusion for 2D objects that have
been moved off the Z=0 plane is an example of something that should never
have been documented.  It's not a particularly useful behavior, and we
might eventually want a different behavior.  At most, it should have said
"don't do that".

It should probably say "drawn on the Z=0 plane".

This child object is first projected onto the X-Y plane along the Z axis
to create the starting face of the extrusion.

Delete.  We shouldn't document that behavior.

The start face is duplicated at the Z position given by the height
parameter to create the extrusion's end face. The extrusion is then formed
by creating a surface that joins each point along the edges of the two
faces.

That's a seriously incomplete description, because it's only true with all
of the parameters at their defaults.

The 2D shape may be any 2D primitive shape
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/2D_Primitives, a 2d
polygon
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/2D_Primitives#Polygon,
an imported 2D drawing
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/2D_Primitives#Importing_a_2D_Drawing,
or a boolean combination
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/CSG_Modelling of
them.

Or, in other words, the 2D shape may be ... a 2D shape.

Delete the whole sentence.

The 2D shape may have a Z value that moves it out of the X-Y plane, and it
may even be rotated out of parallel with it. As stated above, the
extrusion's starting face is the projection of the 2D shape onto the X-Y
plane, which, if it is rotated, will have the effect of fore-shortening it
normal to the axis of the rotation.

Delete.

Using a 3D object as the extrusion's child will cause a compile time error.

Factually incorrect.  It's not a compile-time error; it's a run-time error.

Also, we just said that the child must be a 2D shape.  Exact behavior when
that requirement is violated need not be (and probably should not be)
specified.

Delete.

Including a 3D object in a composition of 2D objects (formed using boolean
combinations on them) will be detected, the 3D object(s) will be deleted
from it and the remaining 2D objects will be the basis for projecting their
shape onto the X-Y plane.

We need not (and generally should not) specify the behavior in error
conditions.  Delete.

Parameters For Linear Extrusion

There are no required parameters. The default operation is to extrude the
child by 100 units vertically from the X-Y Plane, centered on the [0,0]
origin.

"centered" is at best meaningless (because it's extruded wherever the
child is, without respect to the origin) and at worst incorrect (because
the default is to extrude into +Z, not to center in Z). Delete that last
phrase.

  1. height a non-negative integer, default 100, giving the length of the
    extrusion

Doesn't have to be an integer.

I don't know how strong a pattern we have for specifying parameters, but
they shouldn't be numbered.  (Except maybe if they are usable as positional
parameters - which don't match these numbers.)

  1. v - twist axis vector a vector of 3 signed decimal values, default
    [0,0,1], used as an eigen vector specifying the axis of rotation for the
    twist. [Note: Requires version Development snapshot]

I can't say that I truly understand eigenvectors, but I don't think this
is one.  The "signed" part is unnecessary, because all numbers are signed,
and the "decimal" part is meaningless because abstract numbers have no base.

"v" is a vector of three numbers that controls the vector along which the
extrusion is done.

It has an interesting interaction with "height".  If both are specified,
height is used as the length of the extrusion, along the direction that v
points, and v's magnitude is ignored.  If only v is specified, it is used
to control both the direction and length of the extrusion.

Saying that it's the axis of rotation for twist is sort of right, but
maybe needs more explanation.  Normally when you think of an axis of
rotation, you're rotating along the plane perpendicular to that axis.
Here, though, it is perhaps more correct to say that it controls the
origin of the rotation.  At each slice, the 2D shape is rotated around Z,
with the origin being the XY position of the extrusion vector.

  1. center a boolean, default false, that, when true, causes the resulting
    solid to be vertically centered at the X-Y plane.

"at the Z=0 plane" would be a bit more obvious.

  1. convexity a non-negative integer, default 1, giving a measure of the
    complexity of the generated surface. See the Section on Convexity later on
    this page.

Should include a link... which should not be pointing at this page, no
matter which page we're talking about.

  1. twist a signed decimal,

a number

180 degrees is a half twist, 360 is all the way around, and so on.

Unnecessary, delete.

  1. scale either : a non-negative, decimal value,

a non-negative number

minimum 0.0,

Implied by "non-negative", delete.

that specifies the factor by which the end face should be scaled up, or
down, in size from that of the start face.

All scaling is either up or down.  Just "should be scaled".

or : an [x,y] vector that scales the extrusion in the X and Y directions
separately.

Delete the colon.

  1. slices a non-negative integer for the number of rows of polygons that
    the extr.

Needs help.

h a named parameter, synonym to height

Just list it in the same block as height.

$fn $fs $fa Special Parameters - given as named parameters.

They have standard special-variable semantics, which means they can be
specified in the context or in the call.  They should be mentioned, but
perhaps not as parameters per se.  I believe they only affect twisted
extrusions, so maybe they should be mentioned there.

Center

This parameter affects only affects the vertical position or the
extrusion. Its X-Y position is always that of the projection that sets its
starting face.

"or" should be "of".

This is a nice comment, but doesn't say what the parameter does.

"When true, the extrusion is centered vertically around Z=0." seems
adequate to me, without any further comment, but a subsequent comment about
not affecting X and Y would be OK.

Scale

This is multiplicative factor that affects the size of extrusion's end
face. As such 1.0 means no change, a value greater than one expands the end
face, and a value between 0.001 and less than 1 shrinks it.

"As such" is unnecessary.

I don't know where 0.001 came from.  I would say "a value less than 1
shrinks it".

A value of 0.0 causes the end face to degenerate to a point, turning the
extrusion into a pyramid, cone, or complex pointy shape according to what
the starting shape is.

I'd say this is unnecessary.

Using the vector form sets the scale factor in the X and Y directions
separately
Twist

Twist is applied, by default, as a rotation about the Z Axis.

As discussed above, twist is always around Z.  What v controls is the
origin of that rotation.

When the start face is at the origin a twist creates a spiral out of any
corners in the child shape. If the start face is translated away from the
origin the twist creates a spring shape.

I don't know if it's truly useful to try to describe the various shapes
that can result from twisting.

One thing that might be worth explicitly mentioning is that you can't
practically use linear_extrude to generate threads.  You can come
temptingly close, but they won't be shaped right.  (It is actually possible
to get right, but requires an unobvious base shape.)

A positive twist rotates clockwise, negative twist the opposite.

Huh.  I basically never use twist, so I never noticed that it's backwards
from rotate.  That seems very wrong... and it's way too late to fix it.  It
might be worth mentioning this difference.

Twist Axis Vector

The second parameter is an [x,y,z] eigen vector that specifies the axis of
rotation of the applied twist.

Suggest referring to it by name instead of by position.

The ratios of the three dimensional values to their respective coordinate
axes specify the tilt away from the default axis, [0,0,1], the Z-Axis. For
instance, v=[cos(45),0,1] tilts the extrusion at 45 degrees to the X axis.

It's actually a skew rather than a tilt.

The start and end faces are always normal to the Z-axis, even when the
twist axis is tilted. The extruded and twisted surfaces are thus distorted
from what might be expected in an extruded shape. The more expected result
may be achieved by applying a rotation to then twisted extrusion on the Z
Axis to tilt it into the desired position.

It's best not to make assumptions about what the user expects.  Describe
the operation, and describe it carefully.  Do not describe how to do things
that are straightforward combinations of operations.


Note that the documentation does not discuss which happens first:  twist
or scale.  I don't believe it matters when using the same scaling for X and
Y, but matters a great deal with using different scaling on the two axes.
It twists and then scales, which can mean (for instance) that a shape that
started out rectangular turns into a parallelogram.  There's an argument
that this is not the useful behavior, and that scale-and-then-twist is
more useful since it retains the general shape throughout the extrusion.
I've started a discussion a few times about maybe changing this, but I
don't think it ever came to a conclusion.  It might be best not to document
this without that conclusion.

$fn, $fa, $fs Special Parameters

The special variables must be given as named parameters and are applied to
the extrusion, overriding the global setting. When the same special
variables are set on the base shape its values override their use as
parameters on the extrusion.

None of this is really accurate.

The special variables have standard special-variable behavior, which means
that you can specify them in the context or in the particular call, and
they apply to that context (including a specific call) and everything that
that is called from that context.  There is no "global setting" that is
special.

What matters for the linear_extrude (and in particular for twisted
extrusions) is the setting that it sees.

If the child 2D shape also uses these variables, what matters for it is
what it sees... which, absent an inner setting, will be the same as what
linear_extrude sees.

Thus, either:

linear_extrude(height=10, twist=20, $fn=100) circle(10);

or

$fn=100; linear_extrude(height=10, twist=20) circle(10);

will yield a high-resolution twist of a high-resolution circle.

On the other hand, either

linear_extrude(height=10, twist=20, $fn=100) circle(10, $fn=3);

or

$fn=100; linear_extrude(height=10, twist=20) circle(10, $fn=3);

will yield a high-resolution twist of a low-resolution circle - a triangle.

Extrusion From Imported DXF

Does not need to be discussed.  You can linear_extrude any 2D shape, and
an import of a DXF yields a 2D shape.

A Unit Circle with No Twist

I don't think all of these examples are necessary.

Generate an extrusion from a circle 2 units along the X Axis from the
origin,

unit circle

centered vertically on the X-Y plane, with no twist. The extrusion appears
to have a pentagonal cross-section because the extrusion's child is a 2D
circle with the default value for $fn.

It doesn't appear to have a pentagonal cross-section.  It does have a
pentagonal cross-section.

The same circle, but made into a spiral by 500 degrees of
counter-clockwise twist.

If you look carefully, this example demonstrates why you can't make
threads.  As you twist it more, it becomes thinner and thinner in Z.  The
problem is that the cross-section of a thread is a strange shape.

Mesh Refinement

The slices parameter defines the number of intermediate points along the Z
axis of the extrusion.

I am not sure of the exactly right way to describe this, because of fence
post errors.

"slices" controls the number of 3D "chunks" that make up the extrusion.
The total number of instances of the original 2D object is slices+1.

Its default increases with the value of twist.

It's some function of that and $fa/$fs/$fn.  I don't know what the
function is or exactly how to describe it.

Additional the segments parameter

Addition -> Additionally

Segments need to be a multiple of the polygon's fragments to have an
effect (6 or 9.. for a circle($fn=3), 8,12.. for a square() ).

I don't know what the actual behavior is, but that's not it.  For more
complex shapes (I experimented with a right triangle) intermediate values
do have an effect.

The special variables
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Other_Language_Features
$fn, $fs and $fa can also be used to improve the output. If slices is
not defined, its value is taken from the defined $fn value.

Again, I don't know what the behavior is, but that's not it.  Increasing
$fn does increase the number of slices, but it isn't simply used as the
number of slices.

$fa/$fs/$fn seem to control both slices and segments.

Using with imported SVG

Does not need to be separately discussed.

rotate_extrude() Operator Module

Rotational extrusion spins a 2D shape around the Z-axis to form a solid
which has rotational symmetry. One way to think of this operation is to
imagine a Potter's wheel placed on the X-Y plane with its axis of rotation
pointing up towards +Z. Then place the to-be-made object on this virtual
Potter's wheel (possibly extending down below the X-Y plane towards -Z).
The to-be-made object is the cross-section of the object on the X-Y plane
(keeping only the right half, X >= 0). That is the 2D shape that will be
fed to rotate_extrude() as the child in order to generate this solid. Note
that the object started on the X-Y plane but is tilted up (rotated +90
degrees about the X-axis) to extrude.

I'm not sure that this is the best possible explanation.

Since a 2D shape is rendered by OpenSCAD on the X-Y plane, an alternative
way to think of this operation is as follows: spins a 2D shape around the
Y-axis to form a solid. The resultant solid is placed so that its axis of
rotation lies along the Z-axis.

That's the way that I always think of it, though I mentally rotate it to
vertical before spinning it.

Just like the linear_extrude, the extrusion is always performed on the
projection of the 2D polygon to the XY plane.

Again, we should not document this behavior.

Transformations like rotate, translate, etc. applied to the 2D polygon
before extrusion modify the projection of the 2D polygon to the XY plane
and therefore also modify the appearance of the final 3D object.

- A translation in Z of the 2D polygon has no effect on the result (as
also the projection is not affected).
- A translation in X increases the diameter of the final object.
- A translation in Y results in a shift of the final object in Z
direction.
- A rotation about the X or Y axis distorts the cross section of the
final object, as also the projection to the XY plane is distorted.

This is perhaps good stuff, if the part about projecting is removed.

Don't get confused, as OpenSCAD displays 2D polygons with a certain height
in the Z direction, so the 2D object (with its height) appears to have a
bigger projection to the XY plane. But for the projection to the XY plane
and also for the later extrusion only the base polygon without height is
used.

Once you get rid of the part about projecting this goes away too.

You cannot use rotate_extrude to produce a helix or screw thread. Doing
this properly can be difficult, so it's best to find a thread library to
make them for you.

This kind of comment can be valuable, but I'm not sure it belongs in a
reference manual.  If it is in a reference manual, it should be in a
clear and separate section (of the description of the particular feature)
marked "Application Notes" or something like that, to make it clear that
it's not part of the description of the feature.

If the shape spans the X axis a warning appears in the console windows and
the rotate_extrude() is ignored.

Don't talk about what window something appears in, because not everybody
uses the OpenSCAD GUI.

Don't talk about what happens "after" the error.

Just say that it's an error, period.

(And, BTW, this particular one is something that I think should not be an
error; I think that the result should be as if you split the 2D shape in
half, rotationally extruded both, and unioned them.  That is, take the
shape, sweep it 360 degrees, and anything it sweeps through (whether once
or twice) is part of the result.)

If the 2D shape touches the Y axis, i.e. at x=0, it must be a line
that touches, not a point, as a point results in a zero thickness 3D
object, which is invalid and results in a CGAL error.

This may have been addressed with Manifold.

convexity : If the extrusion fails for a non-trival 2D shape, try
setting the convexity parameter (the default is not 10, but 10 is a "good"
value to try). See explanation further down.

Just point at the general discussion of convexity.  (Which should not be
on this page.)

And the extrusion does not "fail".  In fact, the artifacts may be quite
subtle.

start [Note: Requires version Development snapshot] : Defaults to 0 if
angle is specified, and 180 if not. Specifies the starting angle of the
extrusion, counter-clockwise from the positive X axis.

start was part of an effort to align rotational extrusion behavior with
the behavior of other round things.  I don't remember all of the details,
but there are few reasons why it isn't equivalent to rotating the result.

$fa : minimum angle (in degrees) of each fragment. $fs : minimum
circumferential length of each fragment. $fn : fixed number of
fragments in 360 degrees. Values of 3 or more override $fa and $fs $fa,
$fs and $fn must be named parameters. click here for more details,
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Other_Language_Features
.

Do not describe these in detail here.  Refer to a general description of
them elsewhere.

Do not ever, ever, say "click here".  Any text that would not make sense
when printed is wrong.

Rotate Extrude on Imported DXF

Delete.

Increasing the number of fragments composing the 2D shape improves the
quality of the mesh, but takes longer to render.

Unnecessary.

rotate_extrude(convexity = 10)
translate([2, 0, 0])
circle(r = 1, $fn = 100);

This example is unnecessary; this is a description of rotate_extrude, not
circle()

The number of fragments used by the extrusion can also be increased.

rotate_extrude(convexity = 10, $fn = 100)
translate([2, 0, 0])
circle(r = 1, $fn = 100);

Use $fs and $fa here.  In fact, supply them at the top level.  And this
case doesn't require specifying convexity (though I'm not sure why not).
Also, for circles this small high resolution is not practical; make them
bigger to make the example more real. Thus:

$fa = 1;
$fs = 1;
rotate_extrude()
translate([20, 0, 0])
circle(r = 10);

That's really the best practice.  You almost never want to use $fn if your
intent is to create a circle.

(Minor exception that is itself something of a bug:  if you're trying to
force the number of sides to be a multiple of 4.  But that shouldn't be
discussed here.)

Using the parameter angle (with OpenSCAD versions 2016.xx), a hook can be
modeled .
https://en.wikibooks.org/wiki/File:Hook.pngOpenSCAD - a hook

eps = 0.01;
translate([eps, 60, 0])
rotate_extrude(angle=270, convexity=10)
translate([40, 0]) circle(10);
rotate_extrude(angle=90, convexity=10)
translate([20, 0]) circle(10);
translate([20, eps, 0])
rotate([90, 0, 0]) cylinder(r=10, h=80+eps);

Delete.

Extruding a Polygon

Delete.

Description of extrude parameters

Why are we repeating these here?  Don't, especially because there is
little commonality between linear_extrude and rotate_extrude.

[image: 0% developed  as of November 17, 2009]
https://en.wikibooks.org/wiki/Help:Development_stages DXF Extrusion
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/DXF_Extrusion

Delete.

Import 2D

Import 2D Shapes
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Import_2D

This should get more content.  At the current state of things it can
probably all go on the 2D page, but if it gets much more complex it might
want its own page with a brief summary and reference here.


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

A note on the fontfeatures option in the font name. The text says it has to be a plus sign followed by a feature name. But actually it can also be <featurename>=<value>, such as smcp=1 instead of +smcp, but in the case of the font I was looking at, frac=1 and frac=2 produce different results----it's not a boolean setting. And yes, this means it looks like fontfeatures=frac=2. On Fri, Aug 8, 2025 at 4:14 AM Jordan Brown via Discuss < discuss@lists.openscad.org> wrote: > [ I'll spend the effort to fix up this laptop configuration, again, sorry > for the duplicates. ] > > > Two Dimensional Modelling > [image: 0% developed as of November 17, 2009] > <https://en.wikibooks.org/wiki/Help:Development_stages> 2D Primitives > <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/2D_Primitives> > > All 2D primitives can be transformed with 3D transformations. > > > Really bad place to start. Yes, you can transform them with 3D > transforms, but if you do then the results can be weird. It should be > discouraged; you should almost always work with 2D transforms when working > with a 2D subassembly. > > Also, maybe we should talk about the primitives before we talk about what > you can do with them. > > > They are usually used as part of a 3D extrusion. > > > Yeah, eventually. But again this doesn't seem appropriate for a "2D > primitives" section. Maybe for an overview section *above* that. > > > Although they are infinitely thin, they are rendered with a 1-unit > thickness. > > > Again, maybe in an overview section. > > > *Note*: Trying to subtract with difference() from 3D object will lead to > unexpected results in final rendering. > > > The real rule is "don't mix 2D objects with 3D objects and 3D > operations". It isn't necessary or appropriate to say very much about what > will happen if you do. Some cases will yield errors, while others will do > something weird. We don't want the documentation to nail down any > particular behavior, because there are reasons that we might want to change > the behavior in these cases. > > Ref, e.g., OEP 7 "Mixed Dimension Geometry Support" > <https://github.com/openscad/openscad/wiki/OEP7%3A-Mixed-Dimension-Geometry-Support> > . > > > Square Object Module > > By default this module draws a unit square in the first quadrant, (+X,+Y), > starting at the origin [0,0]. Its four lines have no thickness but the > shape is drawn as a 1 unit high, filled plane. > > > The second sentence should probably just go away: > > - The first part "its four lines have no thickness" is both misleading > - the lines have no independent existence - and incorrect; when rendered > they *do* have thickness. > - The second half (drawn as 1 unit high) restates something already > said in above. > > > The module's arguments may be written in the order <size>, center=<bool> without > being named, but the names may be used as shown in the examples: > > > There needs to be (but probably isn't) enough documentation convention > that this need not be said. > > > *Parameters* > size has two forms: *single value* or *vector* single - non-negative > float, length of all four sides > > Should use the word "number" rather than the word "float". OpenSCAD does > not have distinct floating point and integer types; it has only numbers. > > > center boolean, default false, to set the shape's position in the X-Y > plane > > *Center* When false, as it is by default, the shape will be drawn from > its first point at (0,0) in the First Quadrant, (+X,+Y). With center set to > true the shape is drawn centered on the origin. > > > These two paragraphs should be merged. > > > Circle Object Module > > By default this module draws a unit circle centered on the origin [0,0] as > a pentagon with its starting point on the X-axis at X=1. Its lines have no > thickness but the shape is drawn as a 1 unit high, filled plane. > > The part of the first sentence starting "as a pentagon ..." should go > away. It's true, but it really belongs as part of the description of > $fa/$fs. > > Again, the second sentence should just go away. > > Somewhere it should say "Circles are approximated as regular polygons; see > <reference to $fa/$fs/$fn> for the details of the polygons generated." > > > The argument radius may be given without being named, but the r and d arguments > must be named. > > There is no "radius" argument. There are r and d. > > Again, we should have a documentation convention so that we don't have to > repeat positional/named rules, but the behavior here is that r can be > supplied as the first argument, but d must be named. > > (Technically, if you say "circle(undef, 10)" the 10 is the second it > creates a 10-unit-diameter circle. I would say that the fact that this > works is a minor bug.) > > > $fa Special Variable $fs Special Variable $fn Special Variable > > Theses should be described only to the extent of pointing at the general > description of $fa/$fs/$fn. > > The default circle displays as a pentagram as that is the minimum number > of fragments used to approximate a curved shape calculated from the default > values for $fs and $fa. To have it draw as a smooth shape increase the $fn > value, the minimum number of fragments to draw, to 20 or more (best $fn < > 128). > > This is just bad. First, everything here should be covered in the > description of $fa/$fs/$fn. Second, using $fn to control the resolution of > a circle is generally the wrong answer; you are better off setting $fa and > $fs. Finally, specific advice on $fn values is a bad idea, because the > "looks smooth" value varies dramatically with size. A 20-gon is okay for a > medium-small circle; a 72-gon is not good enough for a 100-unit circle. > > An alternative method to draw a very smooth circle scale is to scale down > a very large circle. > > scale( 0.001 ) circle(200); > > This should just go away; it confuses the issue. > > > Another way to solve the lack of a built-in module for regular polygons is > to write a custom one: module regular_polygon() > <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/example_module_regular_polygon()> > > I wouldn't include this. Using polygon() is harder than using circle(), > and anybody who's capable of using it should have little trouble simulating > circle(). > > > convexity Integer, default=1 - complex edge geometry may require a higher > value value to preview correctly. > > > Should include a link to a general discussion of convexity. Probably > should not even mention the default; that should be covered in the general > discussion. > > > *Points Parameter* A list of X-Y coordinates in this form: > > [[1, 1], [1, 4], [3, 4], [3, 1], [1, 1]] > > which defines four points and makes it explicit that the last one is the > same as the first. > > Including the first point twice is not strictly necessary as this: > > [[1, 1], [1, 4], [3, 4], [3, 1]] > > gives the same result. > > > This seems like it should be simplified. In the absence of a paths > parameter, the last point always connects to the first, because polygons > are always closed. > > > *Paths Parameter* > > This optional parameter is a nested vector of paths. > > A "path" is a list of index values that reference points in the points vector. > It can explicitly describe a closed loop by its last index being the same > as its first, as in: > > [1, 2, 3, 4, 1] > > but this is equivalent to: > > [1, 2, 3, 4] > > > Again, this seems like unnecessary complexity; the last point always > connects to the first. > > > Notice that the points vector is simple list, > > No, it's a list of lists. > > while each path is a separate vector. > > Yes... points and paths are the same order. They are both lists of lists. > > This means that paths, that are lists of references to points, have to > "know" which points it needs to include. > > While it's true that paths need to "know" the indexes they connect, I > don't see how that follows from the previous sentences. > > This can be an issue if the polygon is assembled from a number of shapes > at run time as the order of adding shapes affects their point's index > values. > > It's true that this is something that you must handle, but I don't think > that a reference manual needs to discuss it. > > > . *Convexity* > > > Formatting error: this title is merged with the previous paragraph. (But > should be deleted, see below.) > > > Shapes with a lot of detail in their edges may need the convexity > parameter increased to preview correctly. See Convexity > > Already discussed, should be deleted. > > *Example With Multiple Holes* > > [Note: Requires version 2015.03] (for use of concat()) > > <https://en.wikibooks.org/wiki/File:OpenSCAD_romboid_with_holes.jpg> > > We are using "a" for the point lists and "b" for their paths: > > a0 = [[0,0],[100,0],[130,50],[30,50]]; // outer boundary > b0 = [1,0,3,2]; > a1 = [[20,20],[40,20],[30,30]]; // hole 1 > b1 = [4,5,6]; > a2 = [[50,20],[60,20],[40,30]]; // hole 2 > b2 = [7,8,9]; > a3 = [[65,10],[80,10],[80,40],[65,40]]; // hole 3 > b3 = [10,11,12,13]; > a4 = [[98,10],[115,40],[85,40],[85,10]]; // hole 4 > b4 = [14,15,16,17]; > a = concat( a0,a1,a2,a3,a4 ); // merge all points into "a" > b = [b0,b1,b2,b3,b4]; // place all paths into a vector > polygon(a,b); > //alternate > polygon(a,[b0,b1,b2,b3,b4]); > > > The "alternate" at the end of the example seems unnecessary - of course > you can use either a particular expression or a variable that has been set > to that expression. > > > *2D to 3D by Extrusion* > > A polygon may be the basis for an extrusion, just as any of the 2D > primitives can. This example script > <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/example_module_2D_to_3D_extrusion> > may be used to draw the shape in this image: > > > Yes, a polygon can be used as the basis for extrusion, just as any of the > 2D primitives can. That means that you do *not* need a specific example of > that case. > > > Import a 2D Shape From a DXF > > [Deprecated: import_dxf() will be removed in a future release. Use Use import() > Object Module > <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/The_OpenSCAD_Language#import> > instead. instead*]* > > As a deprecated feature, this should be pushed to the bottom. > > Read a DXF file and create a 2D shape. > > *Example* > > linear_extrude(height = 5, center = true) > import_dxf(file = "example009.dxf", layer = "plate"); > > *Example with Import()* > > linear_extrude(height = 5, center = true) > import(file = "example009.dxf", layer = "plate"); > > > The second should perhaps be titled "Replacement example with import()". > Note also that since OpenSCAD is case sensitive the word "import" should > not be capitalized. > > > [image: 0% developed as of November 17, 2009] > <https://en.wikibooks.org/wiki/Help:Development_stages> Text > <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Text> > > Text is a big enough topic that it should probably have its own page, with > just a brief mention and cross-reference here. > > I see that it *has* its own page and is transcluded here. It should not > be transcluded, because that makes it harder to just read everything. > > Text in OpenSCAD > > Being able to use text objects as a part of a model is valuable in a lot > of design solutions. > > Delete this sentence. This is reference material, not sales material. > The user already knows whether or not it's valuable to them. > > > The fonts available to use in a script > <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Text#Fonts_in_OpenSCAD> > are from the system that OpenSCAD is running in with the addition of > those explicitly added by the script itself. > > > And OpenSCAD includes several. (And this duplicates a more extensive > discussion below.) > > > text() Object Module > > The text() object module draws a single string of text as a 2D geometric > object, using fonts installed on the local system or provided as separate > font file. > > provided as +a+ separate font file > > > The shape starts at the origin and is drawn along the positive X axis. > > > By default, ... > > (because halign and valign change things) > > > text String. A single line of any character allowed > <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Characters_Strings#Characters> > . *Limitation:* non-printable ASCII characters like newline and tab > rendered as placeholders > > Delete the second sentence. If it's a string, it's allowed. As for being > a single line and treatment of non-printable characters, need to phrase > that as a current restriction, not as a permanent behavior - it would be > good if we could eventually provide more support there, and we wouldn't > want to be prevented from adding that support by compatibility concerns. > Ref https://github.com/openscad/openscad/issues/5018 for the desire for > multi-line text. > > font a formatted string > <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Text#Parameters> with > default font of "Liberation Sans:style=Regular" > > > "formatted string" is a poor phrase there. Better would be something like > "String. A font specification with ...". > > Also I see that this is a link over to a separate Text page. A separate > Text page is good, as discussed above, but it shouldn't be duplicated here. > > > size non-negative decimal, default=10. The generated text has a height > above the baseline of approximately this value, varying for different fonts > but typically being slightly smaller. > > The "decimal" part should be "number". (It isn't even sensible to talk > about a base.) > > I don't feel the need for the "non-negative" part. (It should probably > also be non-zero.) Unless we have a special meaning for a negative size, > we should be able to let people figure out for themselves that if they make > a silly request they will get a silly answer. > > Current behavior is ... interesting... though when you think about it > unsurprising: the text is mirrored in X and Y, leading to it being > effectively rotated 180 degrees. Unless we really want to keep that > behavior, we should probably make it be an error instead. Until and unless > we decide that we want to keep that behavior, we should *not* document it. > > There needs to be a footnote about size. Because of an arithmetic error > in the implementation (issue #4304 > <https://github.com/openscad/openscad/issues/4304>), the "size" parameter > does not correspond to a typical font size specification. It is a > coincidence that the arithmetic error approximately cancels out the usual > ratio between the specified font size and the size of a capital letter, > making "size" approximately specify the size of a capital letter in a > typical Western font. However, since the result *is* useful, and the error > has been in place since the beginning, we really can't fix it. Maybe at > some point we can introduce an alternative parameter that specifies a more > conventional font size, eg PR#4306 > <https://github.com/openscad/openscad/pull/4306>. > > > spacing float, default=1. Multiplicative factor that increases or > decreases spacing between characters. > > "float" should be "number". > > language String. The language of the text (e.g., "en", "ar", "ch"). > Default is "en". script String, default="latin". The script of the text > (e.g. "latin", "arabic", "hani"). > > > Somebody needs to figure out what these actually do. > > > $fn higher values generate smoother curves (refer to Special Variables > <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Other_Language_Features#special_variables> > ) > > > This should refer to $fa, $fs, and $fn... and really you shouldn't be > using $fn here. > > > Font & Style Parameter > > The "name" of a font is a string starting with its logical font name and > variation, > > I don't see variation as a separate part of the specification. > > Also, use of the "typewriter" font here is inappropriate; neither of these > is a language keyword or language component. Either use plain text or > perhaps italics. > > > optionally followed by a colon (":") separated list of font > specifications like a style selection, and a set of zero or more features. > > > We should include a list of the name=value specifications supported, or > refer to external (fontconfig?) documentation. > > Again, "features" is not a keyword and should not be in typewriter font. > > > The common variations in a font family are sans and serif though many > others will be seen in the list of fonts available. Each font variation can > be drawn with a *style* to support textual emphasis. > > > I think those are part of the font name, and that there they are usually > capitalized. I'm a bit torn on whether they should be in typewriter font. > > > The default, upright appearance is usually called "Regular" with "Bold", > "Italic", and "Bold Italic" being the other three styles commonly included > in a font. In general the styles offered by a font may only be known by > using the platform's font configuration tools or the OpenSCAD font list > dialog > <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Text#Fonts_in_Openscad> > . > > > This should explicitly tie to the "style=" parameter. > > > The fontfeatures property is appended to the font name after the > > > "fontfeatures" should be in typewriter font because it is a keyword. > > "font name" should not be in typewriter font because it is *not* a keyword. > > > optional style parameter. Its value is a semi-colon separated list of > feature codes, each prefixed by a plus, "+", to indicate that it is being > added, > > > Should end with a colon, not a comma. > > > font = "Linux Libertine G:style=Regular:fontfeatures=+smcp;+onum"); > > *Size Parameter* > > Text size is normally given in points, and a point is 1/72 of an inch > high. The formula to convert the *size* value to "points" is pt = > size/3.937, so a *size* argument of 3.05 is about 12 points. > > > This is incorrect, because OpenSCAD is unitless. "size" specifies some > dimension of the font, in OpenSCAD units. See the discussion above about > exactly what dimension it measures. (OpenSCAD units are *typically* > interpreted as millimeters, but that's up to the user and the consuming > program; it is not part of OpenSCAD's definitions.) > > There should be no reference to "points" except perhaps to *disclaim* that > anything is measured in points. > > *Note*: Character size the distance from ascent to descent, not from > ascent to baseline. > > Ref the arithmetic error mentioned above and the long discussion in issue > #4304, this is incorrect. "size" *should have* measured approximately the > font ascent plus descent, but instead measures (even more approximately) > the font ascent. > > One of these four names must be given as a string to the valign parameter. > > Since the valign parameter itself is optional, the word "must" seems > inappropriate. Perhaps "The valign parameter may be set to one of these > four words". > > top The text is aligned so the top of the tallest character in your text > is at the given Y coordinate. > > > There is no "given Y coordinate". The top of the tallest character in > your text is at the X axis, Y=0. > > center The text is aligned with the center of the bounding box at the > given Y coordinate. > > > Again, at Y=0. > > > baseline The text is aligned with the font baseline at the given Y > coordinate. > > Again, at Y=0. > > bottom The text is aligned so the bottom of the lowest-reaching character > in your text is at the given Y coordinate. > > > Again, at Y=0. > > > *Note*: only the "baseline" vertical alignment option will ensure correct > alignment of texts that use mix of fonts and sizes. > > This overlaps a lot with the last sentence of the definition of "baseline" > and should probably be merged with it. > > One of these three names must be given as a string to the halign > parameter. > > > Again, the word "must" seems inappropriate. > > > left The text is aligned with the left side of the bounding box at the > given X coordinate. center The text is aligned with the center of the > bounding box at the given X coordinate. right The text is aligned with > the right of the bounding box at the given X coordinate. > > > None of these are correct. The alignment is based on spacing, not on the > bounding box. For most letters, "left" will position the ink slightly to > the right of X=0. (For a size=10 M in Liberation Sans, it's about 1.1 > units right of X=0.) I'd need to do more research to figure out the > exactly correct wording. > > And for all of them, there is no "given [XY] coordinate". Positioning is > relative to the origin. > > *Spacing Parameter* > > Characters in a text element have the size dictated by their glyph in the > font being used. As such their size in X and Y is fixed. Each glyph also > has fixed advance values (it is a vector [a,b], see textmetrics > <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Text#textmetrics>) > for the offset to the origin of the next character. The position of each > following character is the advance.x value multiplied by the space value. > Obviously letters in the string can be stretched out when the factor is > greater than 1, and can be made to overlap when space is a fraction > closer to zero, but interestingly, using a negative value spaces each > letter in the opposite of the direction parameter. > > > This is more or less correct, but what it doesn't say is that "spacing" is > almost completely useless for a proportionally spaced font, for two > reasons. Ref https://github.com/openscad/openscad/issues/3859 . > > - It does not take ligatures into account; it spaces a ligature as a > single glyph, yielding text that looks like "d i ffi c u l t". > - Because it's a multiplier on the advance value, and because the > advance value is larger for a wide glyph than it is for a narrow glyph, > spacing between narrow glyphs and wide glyphs is radically different. > "IIIMMM" demonstrates this problem. > > The "spacing" parameter should probably be downplayed, and should probably > be deprecated. > > Text Examples > > *Simulating Formatted Text* > > Needs to define what it means by "formatted". > > When text needs to be drawn as if it was formatted it is possible to use > translate() to space lines of text vertically. Fonts that descend below the > baseline need to be spaced apart vertically by about 1.4*size to not > overlap. Some word processing programs use a more generous spacing of > 1.6*size for "single spacing" and double spacing can use 3.2*size. > > fontmetrics() can supply more correct values for the particular font. > > But really this is advice, not reference material. > > > Fonts in OpenSCAD > > The fonts available for use in a script are thosed: > > - registered in the local system > - included in the OpenSCAD installation > - imported at run-time by a program > > A call to fontmetrics() using only default settings shows the > installation's standard font and settings: > > > Any reference to fontmetrics() needs a "requires release XXX" note, which > at the moment is still "requires development snapshot". But really this > should be at most a reference to the fontmetrics() section. > > { > nominal = { > ascent = 12.5733; > descent = -2.9433; > }; > max = { > ascent = 13.6109; descent = -4.2114; > }; > interline = 15.9709; > font = { > family = "Liberation Sans"; > style = "Regular"; > }; > } > > > Wherever this ends up, the indentation needs work. It should match the > indentation style used in the examples. > > > None of the platforms OpenSCAD is available on include the Liberation font > family so having it as part of the app's installation, and making it the > default font, avoids problems of font availability. > > "None" is an awfully broad statement about a moving target. It would be > better to say "To avoid problems of font availability, OpenSCAD includes > the Liberation font family as part of its installation, and has Liberation > Sans as the default font.". > > *Note*: It was previously noted in the docs that fonts may be added to > the installation by drag-and-drop of a font file into the editor window, > but as of version 2025 Snapshot this is *not* the case > > > That isn't what it said. It said: > > You can drag a font in the font list, into the editor window to use in the > text() statement. > > I can't readily check a 2025 build at the moment, but as of Oct 2024 the > it does exactly as described: dragging a font from the OpenSCAD font list > into the editor window drops its name in the editor window. If that is no > longer the case, it's a bug. > > In general, don't say things like this. If the documentation said X, and > you find that X is not true, then one of the following is true: > > - You didn't understand, and X is indeed true. (And maybe the > documentation needs to be clearer.) > - X is false, and it's a bug. (The bug should be fixed, not the > documentation.) > - X is false, and has always been false, and it was always a > documentation error. (And the documentation needs to be fixed.) > - Indeed, X used to be true and is no longer true, and it's an > intentional change, and nobody updated the documentation. This is a very > rare case, because it often means a compatibility problem or feature > regression. > > Regardless, the right answer is to file an issue to get the actual answer. > > In the following sample code a True Type Font, Andika, has been added to > the system fonts using its Font Management service. > > > We shouldn't talk about adding fonts to the system. That's not our > problem. > > But also, that's not what the sample does. It adds a font *to OpenSCAD*, > and has nothing to do with the platform font mechanisms. > > > Supported font file formats are TrueType > <https://en.wikipedia.org/wiki/TrueType> fonts (*.ttf) and OpenType > <https://en.wikipedia.org/wiki/OpenType> fonts (*.otf). Once a file is > registered to the project the details of the fonts in it may be seen in the > font list dialog (see image) so that the logical font names, variations, > and their available styles are available for use in the project. > > This says "see image", but doesn't indicate *which* image. > > And: OpenSCAD doesn't have the notion of "projects" or "registered to the > project". > > 3D Text by Extrusion > > > This is true of all 2D objects and so does not need to be mentioned. > Delete. > > > position a vector [X,Y], the origin of the first glyph, thus the > lower-left corner of the drawn text. > > No, it's not the origin of the first glyph, or at least that's a confusing > phrase to use. A glyph is usually positioned slightly to the right of the > origin, and if it's a descender then it's below the origin, and some > characters (e.g. quotes) are well above the origin. A more correct > statement would be that it's the lower left corner of the bounding box of > the text. > > If one is going to talk about the origin of a glyph, it should be the > point on the baseline to at the left edge of the advance... which this > isn't. > > > size a vector [a,b], the size of the generated text. > > Should be [x,y]. [a,b] doesn't tell you what "a" and "b" mean. > > ascent positive float, the amount that the text extends above the > baseline. > > Use the word "number" rather than "float". > > It's not always positive; for a glyph entirely below the baseline (like > underscore in Liberation Sans) it's negative. (I'm not sure that's truly > the right definition, but it's the current behavior.) > > descent negative float, the amount that the text extends below the > baseline. > > > Not always negative; for a glyph that is entirely above the baseline (like > apostrophe in Liberation Sans) it's positive. Again, I'm not sure that's > the right definition, but it's the current behavior. > > > offset a vector default [0, 0], the lower-left corner of the box > containing the text, including inter-glyph spacing before the first glyph. > > > There is no default; this is a value that's returned to you. > > This is not the correct definition (and it wasn't correct in the original > that I wrote). It's the position of the origin of the text, after > adjusting for halign and valign. For normal LTR text, the X coordinate is > the X coordinate at the left edge of the first glyph's advance, and the Y > component is the Y coordinate of the baseline. > > > advance a vector default [153.09, 0], amount of space to leave to any > following text. > > There is no default (and certainly not that one!). > > The original definition ("the "other end" of the text, the point at which > additional text should be positioned.") wasn't great, but was more > correct. I would say "The point at which additional text should be > positioned, relative to the text's origin as reported by 'offset'.". > > This example displays the text metrics for the default font used by > OpenSCAD: > > "text metrics for ... font" is a non sequitur. Text metrics measure a > particular string. (And "used by OpenSCAD" is unnecessary; the entire > document is in that context.) > > And it's incorrect; the default font is Liberation Sans and this example > uses Liberation Serif. > > Better would be: > > This example displays the text metrics for "Hello, World!" for Liberation > Serif with size=20: > > <https://en.wikibooks.org/wiki/File:OpenSCAD_textmetrics.png>Using > textmetrics() to draw a box around text > > s = "Hello, World!";size = 20;font = "Liberation Serif"; > > translate([0,0,1]) text("Hello, World!", size=size, font=font); > > > Should use "s" instead of repeating the string. (And this is in my > original, sigh.) > > > displays (formatted for readability): > > The original "yields" is better, because it might or might not be > displayed. > > ECHO: { position = [0.7936, -4.2752]; size = [149.306, 23.552]; ascent = 19.2768; descent = -4.2752; offset = [0, 0]; advance = [153.09, 0]; } > > The indentation should match the examples, with the close brace at the > left margin. > > fontmetrics() > > > size Decimal, optional. The size of the font, as described above for > text(). > > Replace "decimal" with "number". > > [image: 0% developed as of November 17, 2009] > <https://en.wikibooks.org/wiki/Help:Development_stages> 3D to 2D > Projection > <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/3D_to_2D_Projection> > > Using the projection() function, you can create 2d drawings from 3d > models, > > So far so good. > > and export them to the dxf format. > > This part should be deleted. There are any number of things you might do > with a 2D projection of a 3D object. Exporting to DXF is only one. > > It works by projecting a 3D model to the (x,y) plane, with z at 0. If > cut=true, only points with z=0 are considered (effectively cutting the > object), with cut=false(*the default*), points above and below the plane > are considered as well (creating a proper projection). > > *Example*: Consider example002.scad, that comes with OpenSCAD. > > <https://en.wikibooks.org/wiki/File:Openscad_projection_example_2x.png> > > Then you can do a 'cut' projection, which gives you the 'slice' of the x-y > plane with z=0. > > > Doing the non-default case as the first example seems wrong; I would swap > the two examples. > > *Another Example* > > You can also use projection to get a 'side view' of an object. > > This example seems unnecessary for a reference manual. It's a > straightforward combination of the features described. > > Links: > > - More complicated example > <http://www.gilesbathgate.com/2010/06/extracting-2d-mendel-outlines-using-openscad/> > from Giles Bathgate's blog > > > Seems inappropriate for a reference manual. Also, doesn't seem more > complicated at all. > > > [image: 0% developed as of November 17, 2009] > <https://en.wikibooks.org/wiki/Help:Development_stages> 2D to 3D Extrusion > <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/2D_to_3D_Extrusion> > > Extrusion <https://en.wikipedia.org/wiki/Extrusion> is the process of > creating an object with a fixed cross-sectional profile. OpenSCAD provides > two commands > > > "Commands" isn't the right word. "Modules" is more correct, but > "operations" is probably best. > > > Both extrusion methods work on a (possibly disjointed) 2D shape normally > drawn in the relevant plane (see below). > > > The old description of the behavior of extrusion for 2D objects that have > been moved off the Z=0 plane is an example of something that should never > have been documented. It's not a particularly useful behavior, and we > might eventually want a different behavior. At most, it should have said > "don't do that". > > It should probably say "drawn on the Z=0 plane". > > > This child object is first projected onto the X-Y plane along the Z axis > to create the starting face of the extrusion. > > > Delete. We shouldn't document that behavior. > > > The start face is duplicated at the Z position given by the height > parameter to create the extrusion's end face. The extrusion is then formed > by creating a surface that joins each point along the edges of the two > faces. > > > That's a seriously incomplete description, because it's only true with all > of the parameters at their defaults. > > > The 2D shape may be any 2D primitive shape > <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/2D_Primitives>, a 2d > polygon > <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/2D_Primitives#Polygon>, > an imported 2D drawing > <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/2D_Primitives#Importing_a_2D_Drawing>, > or a boolean combination > <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/CSG_Modelling> of > them. > > Or, in other words, the 2D shape may be ... a 2D shape. > > Delete the whole sentence. > > > The 2D shape may have a Z value that moves it out of the X-Y plane, and it > may even be rotated out of parallel with it. As stated above, the > extrusion's starting face is the projection of the 2D shape onto the X-Y > plane, which, if it is rotated, will have the effect of fore-shortening it > normal to the axis of the rotation. > > > Delete. > > > Using a 3D object as the extrusion's child will cause a compile time error. > > > Factually incorrect. It's not a compile-time error; it's a run-time error. > > Also, we just said that the child must be a 2D shape. Exact behavior when > that requirement is violated need not be (and probably should not be) > specified. > > Delete. > > Including a 3D object in a composition of 2D objects (formed using boolean > combinations on them) will be detected, the 3D object(s) will be deleted > from it and the remaining 2D objects will be the basis for projecting their > shape onto the X-Y plane. > > We need not (and generally should not) specify the behavior in error > conditions. Delete. > > > Parameters For Linear Extrusion > > There are no required parameters. The default operation is to extrude the > child by 100 units vertically from the X-Y Plane, centered on the [0,0] > origin. > > "centered" is at best meaningless (because it's extruded wherever the > child is, without respect to the origin) and at worst incorrect (because > the default is to extrude into +Z, not to center in Z). Delete that last > phrase. > > 1) height a non-negative integer, default 100, giving the length of the > extrusion > > Doesn't have to be an integer. > > I don't know how strong a pattern we have for specifying parameters, but > they shouldn't be numbered. (Except maybe if they are usable as positional > parameters - which don't match these numbers.) > > > 2) v - twist axis vector a vector of 3 signed decimal values, default > [0,0,1], used as an eigen vector specifying the axis of rotation for the > twist. [Note: Requires version Development snapshot] > > I can't say that I truly understand eigenvectors, but I don't think this > is one. The "signed" part is unnecessary, because all numbers are signed, > and the "decimal" part is meaningless because abstract numbers have no base. > > "v" is a vector of three numbers that controls the vector along which the > extrusion is done. > > It has an interesting interaction with "height". If both are specified, > height is used as the length of the extrusion, along the direction that v > points, and v's magnitude is ignored. If only v is specified, it is used > to control both the direction and length of the extrusion. > > Saying that it's the axis of rotation for twist is sort of right, but > maybe needs more explanation. Normally when you think of an axis of > rotation, you're rotating along the plane perpendicular to that axis. > Here, though, it is perhaps more correct to say that it controls the > *origin* of the rotation. At each slice, the 2D shape is rotated around Z, > with the origin being the XY position of the extrusion vector. > > 3) center a boolean, default false, that, when true, causes the resulting > solid to be vertically centered at the X-Y plane. > > "at the Z=0 plane" would be a bit more obvious. > > 4) convexity a non-negative integer, default 1, giving a measure of the > complexity of the generated surface. See the Section on Convexity later on > this page. > > Should include a link... which should not be pointing at this page, no > matter which page we're talking about. > > 5) twist a signed decimal, > > a number > > 180 degrees is a half twist, 360 is all the way around, and so on. > > Unnecessary, delete. > > > 6) scale either : a non-negative, decimal value, > > a non-negative number > > minimum 0.0, > > > Implied by "non-negative", delete. > > > that specifies the factor by which the end face should be scaled up, or > down, in size from that of the start face. > > All scaling is either up or down. Just "should be scaled". > > > or : an [x,y] vector that scales the extrusion in the X and Y directions > separately. > > > Delete the colon. > > > 7) slices a non-negative integer for the number of rows of polygons that > the extr. > > Needs help. > > > h a named parameter, synonym to height > > > Just list it in the same block as height. > > > $fn $fs $fa Special Parameters - given as named parameters. > > > They have standard special-variable semantics, which means they can be > specified in the context or in the call. They should be mentioned, but > perhaps not as parameters per se. I believe they only affect twisted > extrusions, so maybe they should be mentioned there. > > > Center > > This parameter affects only affects the vertical position or the > extrusion. Its X-Y position is always that of the projection that sets its > starting face. > > "or" should be "of". > > This is a nice comment, but doesn't say what the parameter *does*. > > "When true, the extrusion is centered vertically around Z=0." seems > adequate to me, without any further comment, but a subsequent comment about > not affecting X and Y would be OK. > > > Scale > > This is multiplicative factor that affects the size of extrusion's end > face. As such 1.0 means no change, a value greater than one expands the end > face, and a value between 0.001 and less than 1 shrinks it. > > "As such" is unnecessary. > > I don't know where 0.001 came from. I would say "a value less than 1 > shrinks it". > > A value of 0.0 causes the end face to degenerate to a point, turning the > extrusion into a pyramid, cone, or complex pointy shape according to what > the starting shape is. > > I'd say this is unnecessary. > > > Using the vector form sets the scale factor in the X and Y directions > separately > Twist > > Twist is applied, by default, as a rotation about the Z Axis. > > As discussed above, twist is always around Z. What v controls is the > origin of that rotation. > > > When the start face is at the origin a twist creates a spiral out of any > corners in the child shape. If the start face is translated away from the > origin the twist creates a spring shape. > > I don't know if it's truly useful to try to describe the various shapes > that can result from twisting. > > One thing that might be worth explicitly mentioning is that you can't > practically use linear_extrude to generate threads. You can come > temptingly close, but they won't be shaped right. (It is actually possible > to get right, but requires an unobvious base shape.) > > > A positive twist rotates clockwise, negative twist the opposite. > > > Huh. I basically never use twist, so I never noticed that it's backwards > from rotate. That seems very wrong... and it's way too late to fix it. It > might be worth mentioning this difference. > > > Twist Axis Vector > > The second parameter is an [x,y,z] eigen vector that specifies the axis of > rotation of the applied twist. > > > Suggest referring to it by name instead of by position. > > > The ratios of the three dimensional values to their respective coordinate > axes specify the tilt away from the default axis, [0,0,1], the Z-Axis. For > instance, v=[cos(45),0,1] tilts the extrusion at 45 degrees to the X axis. > > > It's actually a skew rather than a tilt. > > > The start and end faces are always normal to the Z-axis, even when the > twist axis is tilted. The extruded and twisted surfaces are thus distorted > from what might be expected in an extruded shape. The more expected result > may be achieved by applying a rotation to then twisted extrusion on the Z > Axis to tilt it into the desired position. > > It's best not to make assumptions about what the user expects. Describe > the operation, and describe it carefully. Do not describe how to do things > that are straightforward combinations of operations. > > --- > > Note that the documentation does not discuss which happens first: twist > or scale. I don't believe it matters when using the same scaling for X and > Y, but matters a great deal with using different scaling on the two axes. > It twists and then scales, which can mean (for instance) that a shape that > started out rectangular turns into a parallelogram. There's an argument > that this is *not* the useful behavior, and that scale-and-then-twist is > more useful since it retains the general shape throughout the extrusion. > I've started a discussion a few times about maybe changing this, but I > don't think it ever came to a conclusion. It might be best not to document > this without that conclusion. > > > $fn, $fa, $fs Special Parameters > > The special variables must be given as named parameters and are applied to > the extrusion, overriding the global setting. When the same special > variables are set on the base shape its values override their use as > parameters on the extrusion. > > None of this is really accurate. > > The special variables have standard special-variable behavior, which means > that you can specify them in the context or in the particular call, and > they apply to that context (including a specific call) and everything that > that is called from that context. There is no "global setting" that is > special. > > What matters for the linear_extrude (and in particular for twisted > extrusions) is the setting that *it* sees. > > If the child 2D shape *also* uses these variables, what matters for it is > what *it* sees... which, absent an inner setting, will be the same as what > linear_extrude sees. > > Thus, either: > > linear_extrude(height=10, twist=20, $fn=100) circle(10); > > or > > $fn=100; linear_extrude(height=10, twist=20) circle(10); > > will yield a high-resolution twist of a high-resolution circle. > > On the other hand, either > > linear_extrude(height=10, twist=20, $fn=100) circle(10, $fn=3); > > or > > $fn=100; linear_extrude(height=10, twist=20) circle(10, $fn=3); > > will yield a high-resolution twist of a low-resolution circle - a triangle. > > Extrusion From Imported DXF > > Does not need to be discussed. You can linear_extrude any 2D shape, and > an import of a DXF yields a 2D shape. > > A Unit Circle with No Twist > > > I don't think all of these examples are necessary. > > > Generate an extrusion from a circle 2 units along the X Axis from the > origin, > > unit circle > > centered vertically on the X-Y plane, with no twist. The extrusion appears > to have a pentagonal cross-section because the extrusion's child is a 2D > circle with the default value for $fn. > > > It doesn't *appear* to have a pentagonal cross-section. It *does* have a > pentagonal cross-section. > > The same circle, but made into a spiral by 500 degrees of > counter-clockwise twist. > > > If you look carefully, this example demonstrates why you can't make > threads. As you twist it more, it becomes thinner and thinner in Z. The > problem is that the cross-section of a thread is a strange shape. > > > Mesh Refinement > > The slices parameter defines the number of intermediate points along the Z > axis of the extrusion. > > > I am not sure of the exactly right way to describe this, because of fence > post errors. > > "slices" controls the number of 3D "chunks" that make up the extrusion. > The total number of instances of the original 2D object is slices+1. > > Its default increases with the value of twist. > > > It's some function of that and $fa/$fs/$fn. I don't know what the > function is or exactly how to describe it. > > > Additional the segments parameter > > Addition -> Additionally > > > Segments need to be a multiple of the polygon's fragments to have an > effect (6 or 9.. for a circle($fn=3), 8,12.. for a square() ). > > > I don't know what the actual behavior is, but that's not it. For more > complex shapes (I experimented with a right triangle) intermediate values > do have an effect. > > > The special variables > <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Other_Language_Features> > $fn, $fs and $fa can also be used to improve the output. If slices is > not defined, its value is taken from the defined $fn value. > > > Again, I don't know what the behavior is, but that's not it. Increasing > $fn does increase the number of slices, but it isn't simply used as the > number of slices. > > $fa/$fs/$fn seem to control both slices and segments. > > Using with imported SVG > > > Does not need to be separately discussed. > > > rotate_extrude() Operator Module > > Rotational extrusion spins a 2D shape around the Z-axis to form a solid > which has rotational symmetry. One way to think of this operation is to > imagine a Potter's wheel placed on the X-Y plane with its axis of rotation > pointing up towards +Z. Then place the to-be-made object on this virtual > Potter's wheel (possibly extending down below the X-Y plane towards -Z). > The to-be-made object is the cross-section of the object on the X-Y plane > (keeping only the right half, X >= 0). That is the 2D shape that will be > fed to rotate_extrude() as the child in order to generate this solid. Note > that the object started on the X-Y plane but is tilted up (rotated +90 > degrees about the X-axis) to extrude. > > > I'm not sure that this is the best possible explanation. > > > Since a 2D shape is rendered by OpenSCAD on the X-Y plane, an alternative > way to think of this operation is as follows: spins a 2D shape around the > Y-axis to form a solid. The resultant solid is placed so that its axis of > rotation lies along the Z-axis. > > > That's the way that I always think of it, though I mentally rotate it to > vertical before spinning it. > > > Just like the linear_extrude, the extrusion is always performed on the > projection of the 2D polygon to the XY plane. > > > Again, we should not document this behavior. > > > Transformations like rotate, translate, etc. applied to the 2D polygon > before extrusion modify the projection of the 2D polygon to the XY plane > and therefore also modify the appearance of the final 3D object. > > - A translation in Z of the 2D polygon has no effect on the result (as > also the projection is not affected). > - A translation in X increases the diameter of the final object. > - A translation in Y results in a shift of the final object in Z > direction. > - A rotation about the X or Y axis distorts the cross section of the > final object, as also the projection to the XY plane is distorted. > > > This is perhaps good stuff, if the part about projecting is removed. > > > Don't get confused, as OpenSCAD displays 2D polygons with a certain height > in the Z direction, so the 2D object (with its height) appears to have a > bigger projection to the XY plane. But for the projection to the XY plane > and also for the later extrusion only the base polygon without height is > used. > > > Once you get rid of the part about projecting this goes away too. > > > You cannot use rotate_extrude to produce a helix or screw thread. Doing > this properly can be difficult, so it's best to find a thread library to > make them for you. > > > This kind of comment can be valuable, but I'm not sure it belongs in a > reference manual. If it *is* in a reference manual, it should be in a > clear and separate section (of the description of the particular feature) > marked "Application Notes" or something like that, to make it clear that > it's *not* part of the description of the feature. > > > If the shape spans the X axis a warning appears in the console windows and > the rotate_extrude() is ignored. > > Don't talk about what window something appears in, because not everybody > uses the OpenSCAD GUI. > > Don't talk about what happens "after" the error. > > Just say that it's an error, period. > > (And, BTW, this particular one is something that I think should not be an > error; I think that the result should be as if you split the 2D shape in > half, rotationally extruded both, and unioned them. That is, take the > shape, sweep it 360 degrees, and anything it sweeps through (whether once > or twice) is part of the result.) > > > If the 2D shape touches the Y axis, i.e. at x=0, it *must* be a line > that touches, not a point, as a point results in a zero thickness 3D > object, which is invalid and results in a CGAL error. > > > This may have been addressed with Manifold. > > > *convexity* : If the extrusion fails for a non-trival 2D shape, try > setting the convexity parameter (the default is not 10, but 10 is a "good" > value to try). See explanation further down. > > > Just point at the general discussion of convexity. (Which should not be > on this page.) > > And the extrusion does not "fail". In fact, the artifacts may be quite > subtle. > > > *start* [Note: Requires version Development snapshot] : Defaults to 0 if > *angle* is specified, and 180 if not. Specifies the starting angle of the > extrusion, counter-clockwise from the positive X axis. > > > start was part of an effort to align rotational extrusion behavior with > the behavior of other round things. I don't remember all of the details, > but there are few reasons why it isn't equivalent to rotating the result. > > > *$fa* : minimum angle (in degrees) of each fragment. *$fs* : minimum > circumferential length of each fragment. *$fn* : *fixed* number of > fragments in 360 degrees. Values of 3 or more override $fa and $fs $fa, > $fs and $fn must be named parameters. click here for more details, > <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Other_Language_Features> > . > > Do not describe these in detail here. Refer to a general description of > them elsewhere. > > Do not ever, ever, say "click here". Any text that would not make sense > when printed is wrong. > > > Rotate Extrude on Imported DXF > > > Delete. > > > Increasing the number of fragments composing the 2D shape improves the > quality of the mesh, but takes longer to render. > > > Unnecessary. > > > rotate_extrude(convexity = 10) > translate([2, 0, 0]) > circle(r = 1, $fn = 100); > > This example is unnecessary; this is a description of rotate_extrude, not > circle() > > The number of fragments used by the extrusion can also be increased. > > rotate_extrude(convexity = 10, $fn = 100) > translate([2, 0, 0]) > circle(r = 1, $fn = 100); > > > Use $fs and $fa here. In fact, supply them at the top level. And this > case doesn't require specifying convexity (though I'm not sure why not). > Also, for circles this small high resolution is not practical; make them > bigger to make the example more real. Thus: > > $fa = 1; > $fs = 1; > rotate_extrude() > translate([20, 0, 0]) > circle(r = 10); > > That's really the best practice. You almost never want to use $fn if your > intent is to create a circle. > > (Minor exception that is itself something of a bug: if you're trying to > force the number of sides to be a multiple of 4. But that shouldn't be > discussed here.) > > > Using the parameter angle (with OpenSCAD versions 2016.xx), a hook can be > modeled . > <https://en.wikibooks.org/wiki/File:Hook.png>OpenSCAD - a hook > > eps = 0.01; > translate([eps, 60, 0]) > rotate_extrude(angle=270, convexity=10) > translate([40, 0]) circle(10); > rotate_extrude(angle=90, convexity=10) > translate([20, 0]) circle(10); > translate([20, eps, 0]) > rotate([90, 0, 0]) cylinder(r=10, h=80+eps); > > > Delete. > > > Extruding a Polygon > > > Delete. > > Description of extrude parameters > > > Why are we repeating these here? Don't, especially because there is > little commonality between linear_extrude and rotate_extrude. > > [image: 0% developed as of November 17, 2009] > <https://en.wikibooks.org/wiki/Help:Development_stages> DXF Extrusion > <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/DXF_Extrusion> > > > Delete. > > Import 2D > > Import 2D Shapes > <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Import_2D> > > > This should get more content. At the current state of things it can > probably all go on the 2D page, but if it gets much more complex it might > want its own page with a brief summary and reference here. > > > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org >
JB
Jon Bondy
Fri, Aug 8, 2025 11:36 AM

What is the community getting for this INCREDIBLE level of effort?

I think we should

  1. revert the documentation back to prior to when Vulcan started
    changing things

  2. make a list of problems with the documentation (an explicit,
    reviewable requirements list from which we can make controlled changes
    to the documentation)

  3. make small, localized changes that can be validated with minimal effort.

  4. perhaps this should be controlled in a manner similar to the
    development of the software itself, with a GIT-like system of problem
    descriptions and resolutions.

The people who really contribute to OpenSCAD are few, perhaps less than
half a dozen.  To force them to spend their time working on a project
THAT DOES NOT NEED TO BE DONE, and is not going well, will slow down
development and bug fixes that DO need to be done.

It is clear to me that having an OpenSCAD novice working on the
documentation is not a great idea.   Good intentions but bad results.

Vulcan: if you REALLY want to help this community, use OpenSCAD actively
(every day) for a year, making complex designs, and then come back.

Is there anyone (or any group) that is in control of the documentation
Wiki?  If not, we need such an entity.  If so, someone needs to take
control of this project.

Again, if I'm wrong, I apologize.  But I have been getting private
messages agreeing with me.

Jon

On 8/8/2025 4:08 AM, Jordan Brown via Discuss wrote:

[ I'll spend the effort to fix up this laptop configuration, again,
sorry for the duplicates. ]

Two Dimensional Modelling

0% developed  as of November 17, 2009
https://en.wikibooks.org/wiki/Help:Development_stages2D
Primitives
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/2D_Primitives

All 2D primitives can be transformed with 3D transformations.

Really bad place to start.  Yes, you can transform them with 3D
transforms, but if you do then the results can be weird.  It should be
discouraged; you should almost always work with 2D transforms when
working with a 2D subassembly.

Also, maybe we should talk about the primitives before we talk about
what you can do with them.

 They are usually used as part of a 3D extrusion.

Yeah, eventually.  But again this doesn't seem appropriate for a "2D
primitives" section.  Maybe for an overview section above that.

 Although they are infinitely thin, they are rendered with a 1-unit
thickness.

Again, maybe in an overview section.

Note: Trying to subtract with|difference()|from 3D object will lead
to unexpected results in final rendering.

The real rule is "don't mix 2D objects with 3D objects and 3D
operations".  It isn't necessary or appropriate to say very much about
what will happen if you do.  Some cases will yield errors, while
others will do something weird.  We don't want the documentation to
nail down any particular behavior, because there are reasons that we
might want to change the behavior in these cases.

Ref, e.g., OEP 7 "Mixed Dimension Geometry Support"
https://github.com/openscad/openscad/wiki/OEP7%3A-Mixed-Dimension-Geometry-Support.

 Square Object Module

By default this module draws a unit square in the first quadrant,
(+X,+Y), starting at the origin [0,0]. Its four lines have no
thickness but the shape is drawn as a 1 unit high, filled plane.

The second sentence should probably just go away:

  • The first part "its four lines have no thickness" is both
    misleading - the lines have no independent existence - and
    incorrect; when rendered they do have thickness.
  • The second half (drawn as 1 unit high) restates something already
    said in above.

The module's arguments may be written in the order|<size>,
center=<bool>|without being named, but the names may be used as shown
in the examples:

There needs to be (but probably isn't) enough documentation convention
that this need not be said.

Parameters

size
has two forms:/single value/or/vector/
single - non-negative float, length of all four sides

Should use the word "number" rather than the word "float". OpenSCAD
does not have distinct floating point and integer types; it has only
numbers.

center
boolean, default false, to set the shape's position in the X-Y plane

CenterWhen|false|, as it is by default, the shape will be drawn
from its first point at (0,0) in the First Quadrant, (+X,+Y). With
center set to|true|the shape is drawn centered on the origin.

These two paragraphs should be merged.

 Circle Object Module

By default this module draws a unit circle centered on the origin
[0,0] as a pentagon with its starting point on the X-axis at X=1. Its
lines have no thickness but the shape is drawn as a 1 unit high,
filled plane.

The part of the first sentence starting "as a pentagon ..." should go
away.  It's true, but it really belongs as part of the description of
$fa/$fs.

Again, the second sentence should just go away.

Somewhere it should say "Circles are approximated as regular polygons;
see <reference to $fa/$fs/$fn> for the details of the polygons generated."

The argument|radius|may be given without being named, but
the|r|and|d|arguments must be named.

There is no "radius" argument.  There are r and d.

Again, we should have a documentation convention so that we don't have
to repeat positional/named rules, but the behavior here is that r can
be supplied as the first argument, but d must be named.

(Technically, if you say "circle(undef, 10)" the 10 is the second  it
creates a 10-unit-diameter circle.  I would say that the fact that
this works is a minor bug.)

$fa
Special Variable
$fs
Special Variable
$fn
Special Variable

Theses should be described only to the extent of pointing at the
general description of $fa/$fs/$fn.

The default circle displays as a pentagram as that is the minimum
number of fragments used to approximate a curved shape calculated
from the default values for $fs and $fa. To have it draw as a smooth
shape increase the $fn value, the minimum number of fragments to
draw, to 20 or more (best $fn < 128).

This is just bad.  First, everything here should be covered in the
description of $fa/$fs/$fn.  Second, using $fn to control the
resolution of a circle is generally the wrong answer; you are better
off setting $fa and $fs.  Finally, specific advice on $fn values is a
bad idea, because the "looks smooth" value varies dramatically with
size.  A 20-gon is okay for a medium-small circle; a 72-gon is not
good enough for a 100-unit circle.

An alternative method to draw a very smooth circle scale is to scale
down a very large circle.

scale( 0.001 ) circle(200);

This should just go away; it confuses the issue.

Another way to solve the lack of a built-in module for regular
polygons is to write a custom one:module regular_polygon()
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/example_module_regular_polygon()

I wouldn't include this.  Using polygon() is harder than using
circle(), and anybody who's capable of using it should have little
trouble simulating circle().

convexity
Integer, default=1 - complex edge geometry may require a higher
value value to preview correctly.

Should include a link to a general discussion of convexity. Probably
should not even mention the default; that should be covered in the
general discussion.

Points ParameterA list of X-Y coordinates in this form:

[[1, 1], [1, 4], [3, 4], [3, 1], [1, 1]]

which defines four points and makes it explicit that the last one is
the same as the first.

Including the first point twice is not strictly necessary as this:

[[1, 1], [1, 4], [3, 4], [3, 1]]

gives the same result.

This seems like it should be simplified.  In the absence of a paths
parameter, the last point always connects to the first, because
polygons are always closed.

Paths Parameter

This optional parameter is a nested vector of paths.

A "path" is a list of index values that reference points in
the|points|vector. It can explicitly describe a closed loop by its
last index being the same as its first, as in:

[1, 2, 3, 4, 1]

but this is equivalent to:

[1, 2, 3, 4]

Again, this seems like unnecessary complexity; the last point always
connects to the first.

Notice that the points vector is simple list,

No, it's a list of lists.

 while each path is a separate vector.

Yes... points and paths are the same order. They are both lists of lists.

 This means that paths, that are lists of references to points, have
to "know" which points it needs to include.

While it's true that paths need to "know" the indexes they connect, I
don't see how that follows from the previous sentences.

 This can be an issue if the polygon is assembled from a number of
shapes at run time as the order of adding shapes affects their
point's index values.

It's true that this is something that you must handle, but I don't
think that a reference manual needs to discuss it.

 .Convexity

Formatting error:  this title is merged with the previous paragraph.
(But should be deleted, see below.)

Shapes with a lot of detail in their edges may need the convexity
parameter increased to preview correctly. See Convexity

Already discussed, should be deleted.

Example With Multiple Holes

[Note:Requires version2015.03] (for use of|concat()|)

https://en.wikibooks.org/wiki/File:OpenSCAD_romboid_with_holes.jpg

We are using "a" for the point lists and "b" for their paths:

a0 = [[0,0],[100,0],[130,50],[30,50]];    // outer boundary
b0 = [1,0,3,2];
a1 = [[20,20],[40,20],[30,30]];            // hole 1
b1 = [4,5,6];
a2 = [[50,20],[60,20],[40,30]];            // hole 2
b2 = [7,8,9];
a3 = [[65,10],[80,10],[80,40],[65,40]];    // hole 3
b3 = [10,11,12,13];
a4 = [[98,10],[115,40],[85,40],[85,10]];  // hole 4
b4 = [14,15,16,17];
a  = concat( a0,a1,a2,a3,a4 ); // merge all points into "a"
b  = [b0,b1,b2,b3,b4]; // place all paths into a vector
polygon(a,b);
//alternate
polygon(a,[b0,b1,b2,b3,b4]);

The "alternate" at the end of the example seems unnecessary - of
course you can use either a particular expression or a variable that
has been set to that expression.

2D to 3D by Extrusion

A polygon may be the basis for an extrusion, just as any of the 2D
primitives can. Thisexample script
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/example_module_2D_to_3D_extrusionmay
be used to draw the shape in this image:

Yes, a polygon can be used as the basis for extrusion, just as any of
the 2D primitives can.  That means that you do not need a specific
example of that case.

 Import a 2D Shape From a DXF

[Deprecated:import_dxf() will be removed in a future release. Use
Useimport() Object Module
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/The_OpenSCAD_Language#importinstead.
instead*]*

As a deprecated feature, this should be pushed to the bottom.

Read a DXF file and create a 2D shape.

Example

linear_extrude(height = 5, center = true)
import_dxf(file = "example009.dxf", layer = "plate");

Example with Import()

linear_extrude(height = 5, center = true)
import(file = "example009.dxf", layer = "plate");

The second should perhaps be titled "Replacement example with
import()".  Note also that since OpenSCAD is case sensitive the word
"import" should not be capitalized.

Text is a big enough topic that it should probably have its own page,
with just a brief mention and cross-reference here.

I see that it has its own page and is transcluded here.  It should
not be transcluded, because that makes it harder to just read everything.

Text in OpenSCAD

Being able to use text objects as a part of a model is valuable in a
lot of design solutions.

Delete this sentence.  This is reference material, not sales
material.  The user already knows whether or not it's valuable to them.

The fontsavailable to use in a script
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Text#Fonts_in_OpenSCADare
from the system that OpenSCAD is running in with the addition of
those explicitly added by the script itself.

And OpenSCAD includes several.  (And this duplicates a more extensive
discussion below.)

 text() Object Module

The|text()|object module draws a single string of text as a 2D
geometric object, using fonts installed on the local system or
provided as separate font file.

provided as +a+ separate font file

The shape starts at the origin and is drawn along the positive X axis.

By default, ...

(because halign and valign change things)

text
String. A single line ofany character allowed
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Characters_Strings#Characters.*Limitation:*non-printable
ASCII characters like newline and tab rendered as placeholders

Delete the second sentence.  If it's a string, it's allowed. As for
being a single line and treatment of non-printable characters, need to
phrase that as a current restriction, not as a permanent behavior - it
would be good if we could eventually provide more support there, and
we wouldn't want to be prevented from adding that support by
compatibility concerns.  Ref
https://github.com/openscad/openscad/issues/5018 for the desire for
multi-line text.

font
aformatted string
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Text#Parameterswith
default font of "Liberation Sans:style=Regular"

"formatted string" is a poor phrase there.  Better would be something
like "String.  A font specification with ...".

Also I see that this is a link over to a separate Text page.  A
separate Text page is good, as discussed above, but it shouldn't be
duplicated here.

size
non-negative decimal, default=10. The generated text has a height
above the baseline of approximately this value, varying for
different fonts but typically being slightly smaller.

The "decimal" part should be "number".  (It isn't even sensible to
talk about a base.)

I don't feel the need for the "non-negative" part.  (It should
probably also be non-zero.)  Unless we have a special meaning for a
negative size, we should be able to let people figure out for
themselves that if they make a silly request they will get a silly answer.

Current behavior is ... interesting... though when you think about it
unsurprising:  the text is mirrored in X and Y, leading to it being
effectively rotated 180 degrees.  Unless we really want to keep that
behavior, we should probably make it be an error instead.  Until and
unless we decide that we want to keep that behavior, we should not
document it.

There needs to be a footnote about size.  Because of an arithmetic
error in the implementation (issue #4304
https://github.com/openscad/openscad/issues/4304), the "size"
parameter does not correspond to a typical font size specification. 
It is a coincidence that the arithmetic error approximately cancels
out the usual ratio between the specified font size and the size of a
capital letter, making "size" approximately specify the size of a
capital letter in a typical Western font.  However, since the result
is useful, and the error has been in place since the beginning, we
really can't fix it.  Maybe at some point we can introduce an
alternative parameter that specifies a more conventional font size, eg
PR#4306 https://github.com/openscad/openscad/pull/4306.

spacing
float, default=1. Multiplicative factor that increases or
decreases spacing between characters.

"float" should be "number".

language
String. The language of the text (e.g., "en", "ar", "ch").
Default is "en".
script
String, default="latin". The script of the text (e.g. "latin",
"arabic", "hani").

Somebody needs to figure out what these actually do.

$fn
higher values generate smoother curves (refer toSpecial Variables
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Other_Language_Features#special_variables)

This should refer to $fa, $fs, and $fn... and really you shouldn't be
using $fn here.

   Font & Style Parameter

The "name" of a font is a string starting with its|logical font
name|and|variation|,

I don't see variation as a separate part of the specification.

Also, use of the "typewriter" font here is inappropriate; neither of
these is a language keyword or language component. Either use plain
text or perhaps italics.

 optionally followed by a colon (":") separated list of font
specifications like a|style|selection, and a set of zero or
more|features|.

We should include a list of the name=value specifications supported,
or refer to external (fontconfig?) documentation.

Again, "features" is not a keyword and should not be in typewriter font.

The common variations in a font family are|sans|and|serif|though many
others will be seen in the list of fonts available. Each font
variation can be drawn with a/style/to support textual emphasis.

I think those are part of the font name, and that there they are
usually capitalized.  I'm a bit torn on whether they should be in
typewriter font.

The default, upright appearance is usually called "Regular" with
"Bold", "Italic", and "Bold Italic" being the other three styles
commonly included in a font. In general the styles offered by a font
may only be known by using the platform's font configuration tools or
theOpenSCAD font list dialog
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Text#Fonts_in_Openscad.

This should explicitly tie to the "style=" parameter.

The fontfeatures property is appended to the|font name|after the

"fontfeatures" should be in typewriter font because it is a keyword.

"font name" should not be in typewriter font because it is not a
keyword.

optional style parameter. Its value is a semi-colon separated list of
feature codes, each prefixed by a plus, "+", to indicate that it is
being added,

Should end with a colon, not a comma.

font = "Linux Libertine G:style=Regular:fontfeatures=+smcp;+onum");

Size Parameter

Text size is normally given in points, and a point is 1/72 of an inch
high. The formula to convert thesizevalue to "points" is|pt =
size/3.937|, so asizeargument of 3.05 is about 12 points.

This is incorrect, because OpenSCAD is unitless.  "size" specifies
some dimension of the font, in OpenSCAD units.  See the discussion
above about exactly what dimension it measures. (OpenSCAD units are
typically interpreted as millimeters, but that's up to the user and
the consuming program; it is not part of OpenSCAD's definitions.)

There should be no reference to "points" except perhaps to disclaim
that anything is measured in points.

Note: Character size the distance from ascent to descent, not from
ascent to baseline.

Ref the arithmetic error mentioned above and the long discussion in
issue #4304, this is incorrect.  "size" should have measured
approximately the font ascent plus descent, but instead measures (even
more approximately) the font ascent.

One of these four names must be given as a string to
the|valign|parameter.

Since the valign parameter itself is optional, the word "must" seems
inappropriate.  Perhaps "The valign parameter may be set to one of
these four words".

top
The text is aligned so the top of the tallest character in your
text is at the given Y coordinate.

There is no "given Y coordinate".  The top of the tallest character in
your text is at the X axis, Y=0.

center
The text is aligned with the center of the bounding box at the
given Y coordinate.

Again, at Y=0.

baseline
The text is aligned with the font baseline at the given Y coordinate.

Again, at Y=0.

bottom
The text is aligned so the bottom of the lowest-reaching
character in your text is at the given Y coordinate.

Again, at Y=0.

Note: only the "baseline" vertical alignment option will ensure
correct alignment of texts that use mix of fonts and sizes.

This overlaps a lot with the last sentence of the definition of
"baseline" and should probably be merged with it.

One of these three names must be given as a string to
the|halign|parameter.

Again, the word "must" seems inappropriate.

left
The text is aligned with the left side of the bounding box at the
given X coordinate.
center
The text is aligned with the center of the bounding box at the
given X coordinate.
right
The text is aligned with the right of the bounding box at the
given X coordinate.

None of these are correct.  The alignment is based on spacing, not on
the bounding box.  For most letters, "left" will position the ink
slightly to the right of X=0.  (For a size=10 M in Liberation Sans,
it's about 1.1 units right of X=0.)  I'd need to do more research to
figure out the exactly correct wording.

And for all of them, there is no "given [XY] coordinate". Positioning
is relative to the origin.

Spacing Parameter

Characters in a text element have the size dictated by their glyph in
the font being used. As such their size in X and Y is fixed. Each
glyph also has fixed|advance|values (it is a vector [a,b],
seetextmetrics
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Text#textmetrics)
for the offset to the origin of the next character. The position of
each following character is the|advance.x|value multiplied by
the|space|value. Obviously letters in the string can be stretched out
when the factor is greater than 1, and can be made to overlap
when|space|is a fraction closer to zero, but interestingly, using a
negative value spaces each letter in the opposite of
the|direction|parameter.

This is more or less correct, but what it doesn't say is that
"spacing" is almost completely useless for a proportionally spaced
font, for two reasons.  Ref
https://github.com/openscad/openscad/issues/3859 .

  • It does not take ligatures into account; it spaces a ligature as a
    single glyph, yielding text that looks like "d i ffi c u l t".
  • Because it's a multiplier on the advance value, and because the
    advance value is larger for a wide glyph than it is for a narrow
    glyph, spacing between narrow glyphs and wide glyphs is radically
    different.  "IIIMMM" demonstrates this problem.

The "spacing" parameter should probably be downplayed, and should
probably be deprecated.

   Text Examples

Simulating Formatted Text

Needs to define what it means by "formatted".

When text needs to be drawn as if it was formatted it is possible to
use translate() to space lines of text vertically. Fonts that descend
below the baseline need to be spaced apart vertically by
about|1.4size|to not overlap. Some word processing programs use a
more generous spacing of|1.6
size|for "single spacing" and double
spacing can use|3.2*size|.

fontmetrics() can supply more correct values for the particular font.

But really this is advice, not reference material.

 Fonts in OpenSCAD

The fonts available for use in a script are thosed:

  • registered in the local system
  • included in the OpenSCAD installation
  • imported at run-time by a program

A call to fontmetrics() using only default settings shows the
installation's standard font and settings:

Any reference to fontmetrics() needs a "requires release XXX" note,
which at the moment is still "requires development snapshot".  But
really this should be at most a reference to the fontmetrics() section.

{
nominal = {
ascent = 12.5733;
descent = -2.9433;
};
max = {
ascent = 13.6109; descent = -4.2114;
};
interline = 15.9709;
font = {
family = "Liberation Sans";
style = "Regular";
};
}

Wherever this ends up, the indentation needs work.  It should match
the indentation style used in the examples.

None of the platforms OpenSCAD is available on include the Liberation
font family so having it as part of the app's installation, and
making it the default font, avoids problems of font availability.

"None" is an awfully broad statement about a moving target.  It would
be better to say "To avoid problems of font availability, OpenSCAD
includes the Liberation font family as part of its installation, and
has Liberation Sans as the default font.".

Note: It was previously noted in the docs that fonts may be added
to the installation by drag-and-drop of a font file into the editor
window, but as of version 2025 Snapshot this isnotthe case

That isn't what it said.  It said:

 You can drag a font in the font list, into the editor window to
 use in the text() statement.

I can't readily check a 2025 build at the moment, but as of Oct 2024
the it does exactly as described:  dragging a font from the OpenSCAD
font list into the editor window drops its name in the editor window. 
If that is no longer the case, it's a bug.

In general, don't say things like this.  If the documentation said X,
and you find that X is not true, then one of the following is true:

  • You didn't understand, and X is indeed true.  (And maybe the
    documentation needs to be clearer.)
  • X is false, and it's a bug.  (The bug should be fixed, not the
    documentation.)
  • X is false, and has always been false, and it was always a
    documentation error.  (And the documentation needs to be fixed.)
  • Indeed, X used to be true and is no longer true, and it's an
    intentional change, and nobody updated the documentation. This is
    a very rare case, because it often means a compatibility problem
    or feature regression.

Regardless, the right answer is to file an issue to get the actual answer.

In the following sample code a True Type Font, Andika, has been added
to the system fonts using its Font Management service.

We shouldn't talk about adding fonts to the system.  That's not our
problem.

But also, that's not what the sample does.  It adds a font to
OpenSCAD
, and has nothing to do with the platform font mechanisms.

Supported font file formats areTrueType
https://en.wikipedia.org/wiki/TrueTypefonts (.ttf) andOpenType
https://en.wikipedia.org/wiki/OpenTypefonts (
.otf). Once a file is
registered to the project the details of the fonts in it may be seen
in the font list dialog (see image) so that the logical font names,
variations, and their available styles are available for use in the
project.

This says "see image", but doesn't indicate which image.

And:  OpenSCAD doesn't have the notion of "projects" or "registered to
the project".

 3D Text by Extrusion

This is true of all 2D objects and so does not need to be mentioned. 
Delete.

position
a vector [X,Y], the origin of the first glyph, thus the
lower-left corner of the drawn text.

No, it's not the origin of the first glyph, or at least that's a
confusing phrase to use.  A glyph is usually positioned slightly to
the right of the origin, and if it's a descender then it's below the
origin, and some characters (e.g. quotes) are well above the origin. 
A more correct statement would be that it's the lower left corner of
the bounding box of the text.

If one is going to talk about the origin of a glyph, it should be the
point on the baseline to at the left edge of the advance... which this
isn't.

size
a vector [a,b], the size of the generated text.

Should be [x,y].  [a,b] doesn't tell you what "a" and "b" mean.

ascent
positive float, the amount that the text extends above the baseline.

Use the word "number" rather than "float".

It's not always positive; for a glyph entirely below the baseline
(like underscore in Liberation Sans) it's negative. (I'm not sure
that's truly the right definition, but it's the current behavior.)

descent
negative float, the amount that the text extends below the baseline.

Not always negative; for a glyph that is entirely above the baseline
(like apostrophe in Liberation Sans) it's positive. Again, I'm not
sure that's the right definition, but it's the current behavior.

offset
a vector default [0, 0], the lower-left corner of the box
containing the text, including inter-glyph spacing before the
first glyph.

There is no default; this is a value that's returned to you.

This is not the correct definition (and it wasn't correct in the
original that I wrote).  It's the position of the origin of the text,
after adjusting for halign and valign.  For normal LTR text, the X
coordinate is the X coordinate at the left edge of the first glyph's
advance, and the Y component is the Y coordinate of the baseline.

advance
a vector default [153.09, 0], amount of space to leave to any
following text.

There is no default (and certainly not that one!).

The original definition ("the "other end" of the text, the point at
which additional text should be positioned.") wasn't great, but was
more correct.  I would say "The point at which additional text should
be positioned, relative to the text's origin as reported by 'offset'.".

This example displays the text metrics for the default font used by
OpenSCAD:

"text metrics for ... font" is a non sequitur.  Text metrics measure a
particular string.  (And "used by OpenSCAD" is unnecessary; the entire
document is in that context.)

And it's incorrect; the default font is Liberation Sans and this
example uses Liberation Serif.

Better would be:

 This example displays the text metrics for "Hello, World!" for
 Liberation Serif with size=20:

https://en.wikibooks.org/wiki/File:OpenSCAD_textmetrics.pngUsing
textmetrics() to draw a box around text

s="Hello, World!";
size=20;
font="Liberation Serif";

translate([0,0,1])
text("Hello, World!",size=size,font=font);

Should use "s" instead of repeating the string.  (And this is in my
original, sigh.)

displays (formatted for readability):

The original "yields" is better, because it might or might not be
displayed.

ECHO:{
position=[0.7936,-4.2752];
size=[149.306,23.552];
ascent=19.2768;
descent=-4.2752;
offset=[0,0];
advance=[153.09,0];
}

The indentation should match the examples, with the close brace at the
left margin.

   fontmetrics()

size
Decimal, optional. The size of the font, as described above
for|text()|.

Replace "decimal" with "number".

0% developed  as of November 17, 2009
https://en.wikibooks.org/wiki/Help:Development_stages3D to 2D
Projection
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/3D_to_2D_Projection

Using the|projection()|function, you can create 2d drawings from 3d
models,

So far so good.

 and export them to the dxf format.

This part should be deleted.  There are any number of things you might
do with a 2D projection of a 3D object.  Exporting to DXF is only one.

 It works by projecting a 3D model to the (x,y) plane, with z at 0.
If|cut=true|, only points with z=0 are considered (effectively
cutting the object), with|cut=false|(/the default/), points above and
below the plane are considered as well (creating a proper projection).

Example: Consider example002.scad, that comes with OpenSCAD.

https://en.wikibooks.org/wiki/File:Openscad_projection_example_2x.png

Then you can do a 'cut' projection, which gives you the 'slice' of
the x-y plane with z=0.

Doing the non-default case as the first example seems wrong; I would
swap the two examples.

Another Example

You can also use projection to get a 'side view' of an object.

This example seems unnecessary for a reference manual.  It's a
straightforward combination of the features described.

Links:

Seems inappropriate for a reference manual.  Also, doesn't seem more
complicated at all.

0% developed  as of November 17, 2009
https://en.wikibooks.org/wiki/Help:Development_stages2D to 3D
Extrusion
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/2D_to_3D_Extrusion

Extrusion https://en.wikipedia.org/wiki/Extrusionis the process of
creating an object with a fixed cross-sectional profile. OpenSCAD
provides two commands

"Commands" isn't the right word.  "Modules" is more correct, but
"operations" is probably best.

Both extrusion methods work on a (possibly disjointed) 2D shape
normally drawn in the relevant plane (see below).

The old description of the behavior of extrusion for 2D objects that
have been moved off the Z=0 plane is an example of something that
should never have been documented.  It's not a particularly useful
behavior, and we might eventually want a different behavior.  At most,
it should have said "don't do that".

It should probably say "drawn on the Z=0 plane".

This child object is first projected onto the X-Y plane along the Z
axis to create the starting face of the extrusion.

Delete.  We shouldn't document that behavior.

The start face is duplicated at the Z position given by the height
parameter to create the extrusion's end face. The extrusion is then
formed by creating a surface that joins each point along the edges of
the two faces.

That's a seriously incomplete description, because it's only true with
all of the parameters at their defaults.

Or, in other words, the 2D shape may be ... a 2D shape.

Delete the whole sentence.

The 2D shape may have a Z value that moves it out of the X-Y plane,
and it may even be rotated out of parallel with it. As stated above,
the extrusion's starting face is the projection of the 2D shape onto
the X-Y plane, which, if it is rotated, will have the effect of
fore-shortening it normal to the axis of the rotation.

Delete.

Using a 3D object as the extrusion's child will cause a compile time
error.

Factually incorrect.  It's not a compile-time error; it's a run-time
error.

Also, we just said that the child must be a 2D shape.  Exact behavior
when that requirement is violated need not be (and probably should not
be) specified.

Delete.

Including a 3D object in a composition of 2D objects (formed using
boolean combinations on them) will be detected, the 3D object(s) will
be deleted from it and the remaining 2D objects will be the basis for
projecting their shape onto the X-Y plane.

We need not (and generally should not) specify the behavior in error
conditions.  Delete.

 Parameters For Linear Extrusion

There are no required parameters. The default operation is to extrude
the child by 100 units vertically from the X-Y Plane, centered on the
[0,0] origin.

"centered" is at best meaningless (because it's extruded wherever the
child is, without respect to the origin) and at worst incorrect
(because the default is to extrude into +Z, not to center in Z).
Delete that last phrase.

  1. height
    a non-negative integer, default 100, giving the length of the
    extrusion

Doesn't have to be an integer.

I don't know how strong a pattern we have for specifying parameters,
but they shouldn't be numbered.  (Except maybe if they are usable as
positional parameters - which don't match these numbers.)

  1. v - twist axis vector
    a vector of 3 signed decimal values, default [0,0,1], used as an
    eigen vector specifying the axis of rotation for the
    twist.[Note:Requires versionDevelopment snapshot]

I can't say that I truly understand eigenvectors, but I don't think
this is one.  The "signed" part is unnecessary, because all numbers
are signed, and the "decimal" part is meaningless because abstract
numbers have no base.

"v" is a vector of three numbers that controls the vector along which
the extrusion is done.

It has an interesting interaction with "height".  If both are
specified, height is used as the length of the extrusion, along the
direction that v points, and v's magnitude is ignored.  If only v is
specified, it is used to control both the direction and length of the
extrusion.

Saying that it's the axis of rotation for twist is sort of right, but
maybe needs more explanation.  Normally when you think of an axis of
rotation, you're rotating along the plane perpendicular to that axis. 
Here, though, it is perhaps more correct to say that it controls the
origin of the rotation. At each slice, the 2D shape is rotated
around Z, with the origin being the XY position of the extrusion vector.

  1. center
    a boolean, default false, that, when true, causes the resulting
    solid to be vertically centered at the X-Y plane.

"at the Z=0 plane" would be a bit more obvious.

  1. convexity
    a non-negative integer, default 1, giving a measure of the
    complexity of the generated surface. See the Section on Convexity
    later on this page.

Should include a link... which should not be pointing at this page, no
matter which page we're talking about.

  1. twist
    a signed decimal,

a number

  180 degrees is a half twist, 360 is all the way around, and so on.

Unnecessary, delete.

  1. scale
    either : a non-negative, decimal value,

a non-negative number

 minimum 0.0,

Implied by "non-negative", delete.

  that specifies the factor by which the end face should be scaled
 up, or down, in size from that of the start face.

All scaling is either up or down.  Just "should be scaled".

 or : an [x,y] vector that scales the extrusion in the X and Y
 directions separately.

Delete the colon.

  1. slices
    a non-negative integer for the number of rows of polygons that
    the extr.

Needs help.

h
a named parameter, synonym to height

Just list it in the same block as height.

$fn $fs $fa
Special Parameters - given as named parameters.

They have standard special-variable semantics, which means they can be
specified in the context or in the call.  They should be mentioned,
but perhaps not as parameters per se.  I believe they only affect
twisted extrusions, so maybe they should be mentioned there.

   Center

This parameter affects only affects the vertical position or the
extrusion. Its X-Y position is always that of the projection that
sets its starting face.

"or" should be "of".

This is a nice comment, but doesn't say what the parameter does.

"When true, the extrusion is centered vertically around Z=0." seems
adequate to me, without any further comment, but a subsequent comment
about not affecting X and Y would be OK.

   Scale

This is multiplicative factor that affects the size of extrusion's
end face. As such 1.0 means no change, a value greater than one
expands the end face, and a value between 0.001 and less than 1
shrinks it.

"As such" is unnecessary.

I don't know where 0.001 came from.  I would say "a value less than 1
shrinks it".

 A value of 0.0 causes the end face to degenerate to a point, turning
the extrusion into a pyramid, cone, or complex pointy shape according
to what the starting shape is.

I'd say this is unnecessary.

Using the vector form sets the scale factor in the X and Y directions
separately

   Twist

Twist is applied, by default, as a rotation about the Z Axis.

As discussed above, twist is always around Z.  What v controls is the
origin of that rotation.

When the start face is at the origin a twist creates a spiral out of
any corners in the child shape. If the start face is translated away
from the origin the twist creates a spring shape.

I don't know if it's truly useful to try to describe the various
shapes that can result from twisting.

One thing that might be worth explicitly mentioning is that you can't
practically use linear_extrude to generate threads.  You can come
temptingly close, but they won't be shaped right.  (It is actually
possible to get right, but requires an unobvious base shape.)

A positive twist rotates clockwise, negative twist the opposite.

Huh.  I basically never use twist, so I never noticed that it's
backwards from rotate.  That seems very wrong... and it's way too late
to fix it.  It might be worth mentioning this difference.

   Twist Axis Vector

The second parameter is an [x,y,z] eigen vector that specifies the
axis of rotation of the applied twist.

Suggest referring to it by name instead of by position.

 The ratios of the three dimensional values to their respective
coordinate axes specify the tilt away from the default axis, [0,0,1],
the Z-Axis. For instance, v=[cos(45),0,1] tilts the extrusion at 45
degrees to the X axis.

It's actually a skew rather than a tilt.

The start and end faces are always normal to the Z-axis, even when
the twist axis is tilted. The extruded and twisted surfaces are thus
distorted from what might be expected in an extruded shape. The more
expected result may be achieved by applying a rotation to then
twisted extrusion on the Z Axis to tilt it into the desired position.

It's best not to make assumptions about what the user expects.
Describe the operation, and describe it carefully.  Do not describe
how to do things that are straightforward combinations of operations.


Note that the documentation does not discuss which happens first: 
twist or scale.  I don't believe it matters when using the same
scaling for X and Y, but matters a great deal with using different
scaling on the two axes.  It twists and then scales, which can mean
(for instance) that a shape that started out rectangular turns into a
parallelogram.  There's an argument that this is not the useful
behavior, and that scale-and-then-twist is more useful since it
retains the general shape throughout the extrusion.  I've started a
discussion a few times about maybe changing this, but I don't think it
ever came to a conclusion.  It might be best not to document this
without that conclusion.

   $fn, $fa, $fs Special Parameters

The special variables must be given as named parameters and are
applied to the extrusion, overriding the global setting. When the
same special variables are set on the base shape its values override
their use as parameters on the extrusion.

None of this is really accurate.

The special variables have standard special-variable behavior, which
means that you can specify them in the context or in the particular
call, and they apply to that context (including a specific call) and
everything that that is called from that context.  There is no "global
setting" that is special.

What matters for the linear_extrude (and in particular for twisted
extrusions) is the setting that it sees.

If the child 2D shape also uses these variables, what matters for it
is what it sees... which, absent an inner setting, will be the same
as what linear_extrude sees.

Thus, either:

 linear_extrude(height=10, twist=20, $fn=100) circle(10);

or

 $fn=100; linear_extrude(height=10, twist=20) circle(10);

will yield a high-resolution twist of a high-resolution circle.

On the other hand, either

 linear_extrude(height=10, twist=20, $fn=100) circle(10, $fn=3);

or

 $fn=100; linear_extrude(height=10, twist=20) circle(10, $fn=3);

will yield a high-resolution twist of a low-resolution circle - a
triangle.

   Extrusion From Imported DXF

Does not need to be discussed.  You can linear_extrude any 2D shape,
and an import of a DXF yields a 2D shape.

     A Unit Circle with No Twist

I don't think all of these examples are necessary.

Generate an extrusion from a circle 2 units along the X Axis from the
origin,

unit circle

centered vertically on the X-Y plane, with no twist. The extrusion
appears to have a pentagonal cross-section because the extrusion's
child is a 2D circle with the default value for $fn.

It doesn't appear to have a pentagonal cross-section.  It does
have a pentagonal cross-section.

The same circle, but made into a spiral by 500 degrees of
counter-clockwise twist.

If you look carefully, this example demonstrates why you can't make
threads.  As you twist it more, it becomes thinner and thinner in Z. 
The problem is that the cross-section of a thread is a strange shape.

     Mesh Refinement

The slices parameter defines the number of intermediate points along
the Z axis of the extrusion.

I am not sure of the exactly right way to describe this, because of
fence post errors.

"slices" controls the number of 3D "chunks" that make up the
extrusion.  The total number of instances of the original 2D object is
slices+1.

Its default increases with the value of twist.

It's some function of that and $fa/$fs/$fn.  I don't know what the
function is or exactly how to describe it.

Additional the segments parameter

Addition -> Additionally

Segments need to be a multiple of the polygon's fragments to have an
effect (6 or 9.. for a circle($fn=3), 8,12.. for a square() ).

I don't know what the actual behavior is, but that's not it. For more
complex shapes (I experimented with a right triangle) intermediate
values do have an effect.

Thespecial variables
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Other_Language_Features$fn,
$fs and $fa can also be used to improve the output. If slices is not
defined, its value is taken from the defined $fn value.

Again, I don't know what the behavior is, but that's not it.
Increasing $fn does increase the number of slices, but it isn't simply
used as the number of slices.

$fa/$fs/$fn seem to control both slices and segments.

   Using with imported SVG

Does not need to be separately discussed.

 rotate_extrude() Operator Module

Rotational extrusion spins a 2D shape around the Z-axis to form a
solid which has rotational symmetry. One way to think of this
operation is to imagine a Potter's wheel placed on the X-Y plane with
its axis of rotation pointing up towards +Z. Then place the
to-be-made object on this virtual Potter's wheel (possibly extending
down below the X-Y plane towards -Z). The to-be-made object is the
cross-section of the object on the X-Y plane (keeping only the right
half, X >= 0). That is the 2D shape that will be fed to
rotate_extrude() as the child in order to generate this solid. Note
that the object started on the X-Y plane but is tilted up (rotated
+90 degrees about the X-axis) to extrude.

I'm not sure that this is the best possible explanation.

Since a 2D shape is rendered by OpenSCAD on the X-Y plane, an
alternative way to think of this operation is as follows: spins a 2D
shape around the Y-axis to form a solid. The resultant solid is
placed so that its axis of rotation lies along the Z-axis.

That's the way that I always think of it, though I mentally rotate it
to vertical before spinning it.

Just like the linear_extrude, the extrusion is always performed on
the projection of the 2D polygon to the XY plane.

Again, we should not document this behavior.

Transformations like rotate, translate, etc. applied to the 2D
polygon before extrusion modify the projection of the 2D polygon to
the XY plane and therefore also modify the appearance of the final 3D
object.

  • A translation in Z of the 2D polygon has no effect on the result
    (as also the projection is not affected).
  • A translation in X increases the diameter of the final object.
  • A translation in Y results in a shift of the final object in Z
    direction.
  • A rotation about the X or Y axis distorts the cross section of
    the final object, as also the projection to the XY plane is
    distorted.

This is perhaps good stuff, if the part about projecting is removed.

Don't get confused, as OpenSCAD displays 2D polygons with a certain
height in the Z direction, so the 2D object (with its height) appears
to have a bigger projection to the XY plane. But for the projection
to the XY plane and also for the later extrusion only the base
polygon without height is used.

Once you get rid of the part about projecting this goes away too.

You cannot use rotate_extrude to produce a helix or screw thread.
Doing this properly can be difficult, so it's best to find a thread
library to make them for you.

This kind of comment can be valuable, but I'm not sure it belongs in a
reference manual.  If it is in a reference manual, it should be in a
clear and separate section (of the description of the particular
feature) marked "Application Notes" or something like that, to make it
clear that it's not part of the description of the feature.

If the shape spans the X axis a warning appears in the console
windows and the rotate_extrude() is ignored.

Don't talk about what window something appears in, because not
everybody uses the OpenSCAD GUI.

Don't talk about what happens "after" the error.

Just say that it's an error, period.

(And, BTW, this particular one is something that I think should not be
an error; I think that the result should be as if you split the 2D
shape in half, rotationally extruded both, and unioned them.  That is,
take the shape, sweep it 360 degrees, and anything it sweeps through
(whether once or twice) is part of the result.)

 If the 2D shape touches the Y axis, i.e. at x=0, itmustbe a line
that touches, not a point, as a point results in a zero thickness 3D
object, which is invalid and results in a CGAL error.

This may have been addressed with Manifold.

 *convexity* : If the extrusion fails for a non-trival 2D shape,
 try setting the convexity parameter (the default is not 10, but
 10 is a "good" value to try). See explanation further down.

Just point at the general discussion of convexity.  (Which should not
be on this page.)

And the extrusion does not "fail".  In fact, the artifacts may be
quite subtle.

 *start*[Note:Requires versionDevelopment snapshot] : Defaults to
 0 if*angle*is specified, and 180 if not. Specifies the starting
 angle of the extrusion, counter-clockwise from the positive X axis.

start was part of an effort to align rotational extrusion behavior
with the behavior of other round things.  I don't remember all of the
details, but there are few reasons why it isn't equivalent to rotating
the result.

 *$fa* : minimum angle (in degrees) of each fragment.
 *$fs* : minimum circumferential length of each fragment.
 *$fn* :*fixed*number of fragments in 360 degrees. Values of 3 or
 more override $fa and $fs

     $fa, $fs and $fn must be named parameters.click here for more
     details,
     <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Other_Language_Features>.

Do not describe these in detail here.  Refer to a general description
of them elsewhere.

Do not ever, ever, say "click here".  Any text that would not make
sense when printed is wrong.

   Rotate Extrude on Imported DXF

Delete.

Increasing the number of fragments composing the 2D shape improves
the quality of the mesh, but takes longer to render.

Unnecessary.

rotate_extrude(convexity = 10)
translate([2, 0, 0])
circle(r = 1, $fn = 100);

This example is unnecessary; this is a description of rotate_extrude,
not circle()

The number of fragments used by the extrusion can also be increased.

rotate_extrude(convexity = 10, $fn = 100)
translate([2, 0, 0])
circle(r = 1, $fn = 100);

Use $fs and $fa here.  In fact, supply them at the top level. And this
case doesn't require specifying convexity (though I'm not sure why
not).  Also, for circles this small high resolution is not practical;
make them bigger to make the example more real. Thus:

 $fa = 1;
 $fs = 1;
 rotate_extrude()
      translate([20, 0, 0])
          circle(r = 10);

That's really the best practice.  You almost never want to use $fn if
your intent is to create a circle.

(Minor exception that is itself something of a bug:  if you're trying
to force the number of sides to be a multiple of 4.  But that
shouldn't be discussed here.)

Using the parameter angle (with OpenSCAD versions 2016.xx), a hook
can be modeled .

https://en.wikibooks.org/wiki/File:Hook.pngOpenSCAD - a hook

eps = 0.01;
translate([eps, 60, 0])
rotate_extrude(angle=270, convexity=10)
translate([40, 0]) circle(10);
rotate_extrude(angle=90, convexity=10)
translate([20, 0]) circle(10);
translate([20, eps, 0])
rotate([90, 0, 0]) cylinder(r=10, h=80+eps);

Delete.

     Extruding a Polygon

Delete.

   Description of extrude parameters

Why are we repeating these here?  Don't, especially because there is
little commonality between linear_extrude and rotate_extrude.

 0% developed  as of November 17, 2009
 <https://en.wikibooks.org/wiki/Help:Development_stages>DXF
 Extrusion
 <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/DXF_Extrusion>

Delete.

This should get more content.  At the current state of things it can
probably all go on the 2D page, but if it gets much more complex it
might want its own page with a brief summary and reference here.


OpenSCAD mailing list
To unsubscribe send an email todiscuss-leave@lists.openscad.org

--
This email has been checked for viruses by AVG antivirus software.
www.avg.com

What is the community getting for this INCREDIBLE level of effort? I think we should 1) revert the documentation back to prior to when Vulcan started changing things 2) make a list of problems with the documentation (an explicit, reviewable requirements list from which we can make controlled changes to the documentation) 3) make small, localized changes that can be validated with minimal effort. 4) perhaps this should be controlled in a manner similar to the development of the software itself, with a GIT-like system of problem descriptions and resolutions. The people who really contribute to OpenSCAD are few, perhaps less than half a dozen.  To force them to spend their time working on a project THAT DOES NOT NEED TO BE DONE, and is not going well, will slow down development and bug fixes that DO need to be done. It is clear to me that having an OpenSCAD novice working on the documentation is not a great idea.   Good intentions but bad results. Vulcan: if you REALLY want to help this community, use OpenSCAD actively (every day) for a year, making complex designs, and then come back. Is there anyone (or any group) that is in control of the documentation Wiki?  If not, we need such an entity.  If so, someone needs to take control of this project. Again, if I'm wrong, I apologize.  But I have been getting private messages agreeing with me. Jon On 8/8/2025 4:08 AM, Jordan Brown via Discuss wrote: > > [ I'll spend the effort to fix up this laptop configuration, again, > sorry for the duplicates. ] > > >> Two Dimensional Modelling >> >> >> 0% developed  as of November 17, 2009 >> <https://en.wikibooks.org/wiki/Help:Development_stages>2D >> Primitives >> <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/2D_Primitives> >> >> All 2D primitives can be transformed with 3D transformations. >> > > Really bad place to start.  Yes, you can transform them with 3D > transforms, but if you do then the results can be weird.  It should be > discouraged; you should almost always work with 2D transforms when > working with a 2D subassembly. > > Also, maybe we should talk about the primitives before we talk about > what you can do with them. > > >>  They are usually used as part of a 3D extrusion. >> > > Yeah, eventually.  But again this doesn't seem appropriate for a "2D > primitives" section.  Maybe for an overview section *above* that. > > >>  Although they are infinitely thin, they are rendered with a 1-unit >> thickness. >> > > Again, maybe in an overview section. > > >> *Note*: Trying to subtract with|difference()|from 3D object will lead >> to unexpected results in final rendering. >> > > The real rule is "don't mix 2D objects with 3D objects and 3D > operations".  It isn't necessary or appropriate to say very much about > what will happen if you do.  Some cases will yield errors, while > others will do something weird.  We don't want the documentation to > nail down any particular behavior, because there are reasons that we > might want to change the behavior in these cases. > > Ref, e.g., OEP 7 "Mixed Dimension Geometry Support" > <https://github.com/openscad/openscad/wiki/OEP7%3A-Mixed-Dimension-Geometry-Support>. > > >> Square Object Module >> >> By default this module draws a unit square in the first quadrant, >> (+X,+Y), starting at the origin [0,0]. Its four lines have no >> thickness but the shape is drawn as a 1 unit high, filled plane. >> > > The second sentence should probably just go away: > > * The first part "its four lines have no thickness" is both > misleading - the lines have no independent existence - and > incorrect; when rendered they *do* have thickness. > * The second half (drawn as 1 unit high) restates something already > said in above. > > >> The module's arguments may be written in the order|<size>, >> center=<bool>|without being named, but the names may be used as shown >> in the examples: >> > > There needs to be (but probably isn't) enough documentation convention > that this need not be said. > > >> *Parameters* >> >> size >> has two forms:/single value/or/vector/ >> single - non-negative float, length of all four sides >> > Should use the word "number" rather than the word "float". OpenSCAD > does not have distinct floating point and integer types; it has only > numbers. > > >> center >> boolean, default false, to set the shape's position in the X-Y plane >> >> *Center*When|false|, as it is by default, the shape will be drawn >> from its first point at (0,0) in the First Quadrant, (+X,+Y). With >> center set to|true|the shape is drawn centered on the origin. >> > > These two paragraphs should be merged. > > >> Circle Object Module >> >> By default this module draws a unit circle centered on the origin >> [0,0] as a pentagon with its starting point on the X-axis at X=1. Its >> lines have no thickness but the shape is drawn as a 1 unit high, >> filled plane. >> > The part of the first sentence starting "as a pentagon ..." should go > away.  It's true, but it really belongs as part of the description of > $fa/$fs. > > Again, the second sentence should just go away. > > Somewhere it should say "Circles are approximated as regular polygons; > see <reference to $fa/$fs/$fn> for the details of the polygons generated." > > >> The argument|radius|may be given without being named, but >> the|r|and|d|arguments must be named. >> > There is no "radius" argument.  There are r and d. > > Again, we should have a documentation convention so that we don't have > to repeat positional/named rules, but the behavior here is that r can > be supplied as the first argument, but d must be named. > > (Technically, if you say "circle(undef, 10)" the 10 is the second  it > creates a 10-unit-diameter circle.  I would say that the fact that > this works is a minor bug.) > > >> $fa >> Special Variable >> $fs >> Special Variable >> $fn >> Special Variable >> > Theses should be described only to the extent of pointing at the > general description of $fa/$fs/$fn. > >> The default circle displays as a pentagram as that is the minimum >> number of fragments used to approximate a curved shape calculated >> from the default values for $fs and $fa. To have it draw as a smooth >> shape increase the $fn value, the minimum number of fragments to >> draw, to 20 or more (best $fn < 128). >> > This is just bad.  First, everything here should be covered in the > description of $fa/$fs/$fn.  Second, using $fn to control the > resolution of a circle is generally the wrong answer; you are better > off setting $fa and $fs.  Finally, specific advice on $fn values is a > bad idea, because the "looks smooth" value varies dramatically with > size.  A 20-gon is okay for a medium-small circle; a 72-gon is not > good enough for a 100-unit circle. > >> An alternative method to draw a very smooth circle scale is to scale >> down a very large circle. >> >> scale( 0.001 ) circle(200); > > This should just go away; it confuses the issue. > > >> Another way to solve the lack of a built-in module for regular >> polygons is to write a custom one:module regular_polygon() >> <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/example_module_regular_polygon()> >> > I wouldn't include this.  Using polygon() is harder than using > circle(), and anybody who's capable of using it should have little > trouble simulating circle(). > > >> convexity >> Integer, default=1 - complex edge geometry may require a higher >> value value to preview correctly. >> > > Should include a link to a general discussion of convexity. Probably > should not even mention the default; that should be covered in the > general discussion. > > >> *Points Parameter*A list of X-Y coordinates in this form: >> >> [[1, 1], [1, 4], [3, 4], [3, 1], [1, 1]] >> >> which defines four points and makes it explicit that the last one is >> the same as the first. >> >> Including the first point twice is not strictly necessary as this: >> >> [[1, 1], [1, 4], [3, 4], [3, 1]] >> >> gives the same result. >> > > This seems like it should be simplified.  In the absence of a paths > parameter, the last point always connects to the first, because > polygons are always closed. > > >> *Paths Parameter* >> >> This optional parameter is a nested vector of paths. >> >> A "path" is a list of index values that reference points in >> the|points|vector. It can explicitly describe a closed loop by its >> last index being the same as its first, as in: >> >> [1, 2, 3, 4, 1] >> >> but this is equivalent to: >> >> [1, 2, 3, 4] > > > Again, this seems like unnecessary complexity; the last point always > connects to the first. > > >> Notice that the points vector is simple list, >> > No, it's a list of lists. > >>  while each path is a separate vector. >> > Yes... points and paths are the same order. They are both lists of lists. > >>  This means that paths, that are lists of references to points, have >> to "know" which points it needs to include. >> > While it's true that paths need to "know" the indexes they connect, I > don't see how that follows from the previous sentences. > >>  This can be an issue if the polygon is assembled from a number of >> shapes at run time as the order of adding shapes affects their >> point's index values. >> > It's true that this is something that you must handle, but I don't > think that a reference manual needs to discuss it. > > >>  .*Convexity* >> > > Formatting error:  this title is merged with the previous paragraph. > (But should be deleted, see below.) > > >> Shapes with a lot of detail in their edges may need the convexity >> parameter increased to preview correctly. See Convexity >> > Already discussed, should be deleted. > >> *Example With Multiple Holes* >> >> [Note:Requires version2015.03] (for use of|concat()|) >> >> <https://en.wikibooks.org/wiki/File:OpenSCAD_romboid_with_holes.jpg> >> >> We are using "a" for the point lists and "b" for their paths: >> >> a0 = [[0,0],[100,0],[130,50],[30,50]]; // outer boundary >> b0 = [1,0,3,2]; >> a1 = [[20,20],[40,20],[30,30]]; // hole 1 >> b1 = [4,5,6]; >> a2 = [[50,20],[60,20],[40,30]]; // hole 2 >> b2 = [7,8,9]; >> a3 = [[65,10],[80,10],[80,40],[65,40]]; // hole 3 >> b3 = [10,11,12,13]; >> a4 = [[98,10],[115,40],[85,40],[85,10]]; // hole 4 >> b4 = [14,15,16,17]; >> a = concat( a0,a1,a2,a3,a4 ); // merge all points into "a" >> b = [b0,b1,b2,b3,b4]; // place all paths into a vector >> polygon(a,b); >> //alternate >> polygon(a,[b0,b1,b2,b3,b4]); > > > The "alternate" at the end of the example seems unnecessary - of > course you can use either a particular expression or a variable that > has been set to that expression. > > >> *2D to 3D by Extrusion* >> >> A polygon may be the basis for an extrusion, just as any of the 2D >> primitives can. Thisexample script >> <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/example_module_2D_to_3D_extrusion>may >> be used to draw the shape in this image: >> > > Yes, a polygon can be used as the basis for extrusion, just as any of > the 2D primitives can.  That means that you do *not* need a specific > example of that case. > > >> Import a 2D Shape From a DXF >> >> [Deprecated:import_dxf() will be removed in a future release. Use >> Useimport() Object Module >> <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/The_OpenSCAD_Language#import>instead. >> instead*]* >> > As a deprecated feature, this should be pushed to the bottom. > >> Read a DXF file and create a 2D shape. >> >> *Example* >> >> linear_extrude(height = 5, center = true) >> import_dxf(file = "example009.dxf", layer = "plate"); >> >> *Example with Import()* >> >> linear_extrude(height = 5, center = true) >> import(file = "example009.dxf", layer = "plate"); > > > The second should perhaps be titled "Replacement example with > import()".  Note also that since OpenSCAD is case sensitive the word > "import" should not be capitalized. > > >> 0% developed  as of November 17, 2009 >> <https://en.wikibooks.org/wiki/Help:Development_stages>Text >> <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Text> >> > Text is a big enough topic that it should probably have its own page, > with just a brief mention and cross-reference here. > > I see that it *has* its own page and is transcluded here.  It should > not be transcluded, because that makes it harder to just read everything. > >> >> Text in OpenSCAD >> >> Being able to use text objects as a part of a model is valuable in a >> lot of design solutions. >> > Delete this sentence.  This is reference material, not sales > material.  The user already knows whether or not it's valuable to them. > > >> The fontsavailable to use in a script >> <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Text#Fonts_in_OpenSCAD>are >> from the system that OpenSCAD is running in with the addition of >> those explicitly added by the script itself. >> > > And OpenSCAD includes several.  (And this duplicates a more extensive > discussion below.) > > >> text() Object Module >> >> The|text()|object module draws a single string of text as a 2D >> geometric object, using fonts installed on the local system or >> provided as separate font file. >> > provided as +a+ separate font file > > >> The shape starts at the origin and is drawn along the positive X axis. >> > > By default, ... > > (because halign and valign change things) > > >> text >> String. A single line ofany character allowed >> <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Characters_Strings#Characters>.*Limitation:*non-printable >> ASCII characters like newline and tab rendered as placeholders >> > Delete the second sentence.  If it's a string, it's allowed. As for > being a single line and treatment of non-printable characters, need to > phrase that as a current restriction, not as a permanent behavior - it > would be good if we could eventually provide more support there, and > we wouldn't want to be prevented from adding that support by > compatibility concerns.  Ref > https://github.com/openscad/openscad/issues/5018 for the desire for > multi-line text. > >> font >> aformatted string >> <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Text#Parameters>with >> default font of "Liberation Sans:style=Regular" >> > > "formatted string" is a poor phrase there.  Better would be something > like "String.  A font specification with ...". > > Also I see that this is a link over to a separate Text page.  A > separate Text page is good, as discussed above, but it shouldn't be > duplicated here. > > >> size >> non-negative decimal, default=10. The generated text has a height >> above the baseline of approximately this value, varying for >> different fonts but typically being slightly smaller. >> > The "decimal" part should be "number".  (It isn't even sensible to > talk about a base.) > > I don't feel the need for the "non-negative" part.  (It should > probably also be non-zero.)  Unless we have a special meaning for a > negative size, we should be able to let people figure out for > themselves that if they make a silly request they will get a silly answer. > > Current behavior is ... interesting... though when you think about it > unsurprising:  the text is mirrored in X and Y, leading to it being > effectively rotated 180 degrees.  Unless we really want to keep that > behavior, we should probably make it be an error instead.  Until and > unless we decide that we want to keep that behavior, we should *not* > document it. > > There needs to be a footnote about size.  Because of an arithmetic > error in the implementation (issue #4304 > <https://github.com/openscad/openscad/issues/4304>), the "size" > parameter does not correspond to a typical font size specification.  > It is a coincidence that the arithmetic error approximately cancels > out the usual ratio between the specified font size and the size of a > capital letter, making "size" approximately specify the size of a > capital letter in a typical Western font.  However, since the result > *is* useful, and the error has been in place since the beginning, we > really can't fix it.  Maybe at some point we can introduce an > alternative parameter that specifies a more conventional font size, eg > PR#4306 <https://github.com/openscad/openscad/pull/4306>. > > >> spacing >> float, default=1. Multiplicative factor that increases or >> decreases spacing between characters. >> > "float" should be "number". > >> language >> String. The language of the text (e.g., "en", "ar", "ch"). >> Default is "en". >> script >> String, default="latin". The script of the text (e.g. "latin", >> "arabic", "hani"). >> > > Somebody needs to figure out what these actually do. > > >> $fn >> higher values generate smoother curves (refer toSpecial Variables >> <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Other_Language_Features#special_variables>) >> > > This should refer to $fa, $fs, and $fn... and really you shouldn't be > using $fn here. > > >> Font & Style Parameter >> >> The "name" of a font is a string starting with its|logical font >> name|and|variation|, >> > I don't see variation as a separate part of the specification. > > Also, use of the "typewriter" font here is inappropriate; neither of > these is a language keyword or language component. Either use plain > text or perhaps italics. > > >>  optionally followed by a colon (":") separated list of font >> specifications like a|style|selection, and a set of zero or >> more|features|. >> > > We should include a list of the name=value specifications supported, > or refer to external (fontconfig?) documentation. > > Again, "features" is not a keyword and should not be in typewriter font. > > >> The common variations in a font family are|sans|and|serif|though many >> others will be seen in the list of fonts available. Each font >> variation can be drawn with a/style/to support textual emphasis. >> > > I think those are part of the font name, and that there they are > usually capitalized.  I'm a bit torn on whether they should be in > typewriter font. > > >> The default, upright appearance is usually called "Regular" with >> "Bold", "Italic", and "Bold Italic" being the other three styles >> commonly included in a font. In general the styles offered by a font >> may only be known by using the platform's font configuration tools or >> theOpenSCAD font list dialog >> <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Text#Fonts_in_Openscad>. >> > > This should explicitly tie to the "style=" parameter. > > >> The fontfeatures property is appended to the|font name|after the >> > > "fontfeatures" should be in typewriter font because it is a keyword. > > "font name" should not be in typewriter font because it is *not* a > keyword. > > >> optional style parameter. Its value is a semi-colon separated list of >> feature codes, each prefixed by a plus, "+", to indicate that it is >> being added, >> > > Should end with a colon, not a comma. > > >> font = "Linux Libertine G:style=Regular:fontfeatures=+smcp;+onum"); >> >> *Size Parameter* >> >> Text size is normally given in points, and a point is 1/72 of an inch >> high. The formula to convert the*size*value to "points" is|pt = >> size/3.937|, so a*size*argument of 3.05 is about 12 points. >> > > This is incorrect, because OpenSCAD is unitless.  "size" specifies > some dimension of the font, in OpenSCAD units.  See the discussion > above about exactly what dimension it measures. (OpenSCAD units are > *typically* interpreted as millimeters, but that's up to the user and > the consuming program; it is not part of OpenSCAD's definitions.) > > There should be no reference to "points" except perhaps to *disclaim* > that anything is measured in points. > >> *Note*: Character size the distance from ascent to descent, not from >> ascent to baseline. >> > Ref the arithmetic error mentioned above and the long discussion in > issue #4304, this is incorrect.  "size" *should have* measured > approximately the font ascent plus descent, but instead measures (even > more approximately) the font ascent. > >> One of these four names must be given as a string to >> the|valign|parameter. >> > Since the valign parameter itself is optional, the word "must" seems > inappropriate.  Perhaps "The valign parameter may be set to one of > these four words". > >> top >> The text is aligned so the top of the tallest character in your >> text is at the given Y coordinate. >> > > There is no "given Y coordinate".  The top of the tallest character in > your text is at the X axis, Y=0. > >> center >> The text is aligned with the center of the bounding box at the >> given Y coordinate. >> > > Again, at Y=0. > > >> baseline >> The text is aligned with the font baseline at the given Y coordinate. >> > Again, at Y=0. >> >> bottom >> The text is aligned so the bottom of the lowest-reaching >> character in your text is at the given Y coordinate. >> > > Again, at Y=0. > > >> *Note*: only the "baseline" vertical alignment option will ensure >> correct alignment of texts that use mix of fonts and sizes. >> > This overlaps a lot with the last sentence of the definition of > "baseline" and should probably be merged with it. > >> One of these three names must be given as a string to >> the|halign|parameter. >> > > Again, the word "must" seems inappropriate. > > >> left >> The text is aligned with the left side of the bounding box at the >> given X coordinate. >> center >> The text is aligned with the center of the bounding box at the >> given X coordinate. >> right >> The text is aligned with the right of the bounding box at the >> given X coordinate. >> > > None of these are correct.  The alignment is based on spacing, not on > the bounding box.  For most letters, "left" will position the ink > slightly to the right of X=0.  (For a size=10 M in Liberation Sans, > it's about 1.1 units right of X=0.)  I'd need to do more research to > figure out the exactly correct wording. > > And for all of them, there is no "given [XY] coordinate". Positioning > is relative to the origin. > >> *Spacing Parameter* >> >> Characters in a text element have the size dictated by their glyph in >> the font being used. As such their size in X and Y is fixed. Each >> glyph also has fixed|advance|values (it is a vector [a,b], >> seetextmetrics >> <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Text#textmetrics>) >> for the offset to the origin of the next character. The position of >> each following character is the|advance.x|value multiplied by >> the|space|value. Obviously letters in the string can be stretched out >> when the factor is greater than 1, and can be made to overlap >> when|space|is a fraction closer to zero, but interestingly, using a >> negative value spaces each letter in the opposite of >> the|direction|parameter. >> > > This is more or less correct, but what it doesn't say is that > "spacing" is almost completely useless for a proportionally spaced > font, for two reasons.  Ref > https://github.com/openscad/openscad/issues/3859 . > > * It does not take ligatures into account; it spaces a ligature as a > single glyph, yielding text that looks like "d i ffi c u l t". > * Because it's a multiplier on the advance value, and because the > advance value is larger for a wide glyph than it is for a narrow > glyph, spacing between narrow glyphs and wide glyphs is radically > different.  "IIIMMM" demonstrates this problem. > > The "spacing" parameter should probably be downplayed, and should > probably be deprecated. > >> >> Text Examples >> >> *Simulating Formatted Text* >> > Needs to define what it means by "formatted". >> >> When text needs to be drawn as if it was formatted it is possible to >> use translate() to space lines of text vertically. Fonts that descend >> below the baseline need to be spaced apart vertically by >> about|1.4*size|to not overlap. Some word processing programs use a >> more generous spacing of|1.6*size|for "single spacing" and double >> spacing can use|3.2*size|. >> > fontmetrics() can supply more correct values for the particular font. > > But really this is advice, not reference material. > > >> Fonts in OpenSCAD >> >> The fonts available for use in a script are thosed: >> >> * registered in the local system >> * included in the OpenSCAD installation >> * imported at run-time by a program >> >> A call to fontmetrics() using only default settings shows the >> installation's standard font and settings: >> > > Any reference to fontmetrics() needs a "requires release XXX" note, > which at the moment is still "requires development snapshot".  But > really this should be at most a reference to the fontmetrics() section. > >> { >> nominal = { >> ascent = 12.5733; >> descent = -2.9433; >> }; >> max = { >> ascent = 13.6109; descent = -4.2114; >> }; >> interline = 15.9709; >> font = { >> family = "Liberation Sans"; >> style = "Regular"; >> }; >> } > > Wherever this ends up, the indentation needs work.  It should match > the indentation style used in the examples. > > >> None of the platforms OpenSCAD is available on include the Liberation >> font family so having it as part of the app's installation, and >> making it the default font, avoids problems of font availability. >> > "None" is an awfully broad statement about a moving target.  It would > be better to say "To avoid problems of font availability, OpenSCAD > includes the Liberation font family as part of its installation, and > has Liberation Sans as the default font.". > >> *Note*: It was previously noted in the docs that fonts may be added >> to the installation by drag-and-drop of a font file into the editor >> window, but as of version 2025 Snapshot this is*not*the case >> > > That isn't what it said.  It said: > > You can drag a font in the font list, into the editor window to > use in the text() statement. > > I can't readily check a 2025 build at the moment, but as of Oct 2024 > the it does exactly as described:  dragging a font from the OpenSCAD > font list into the editor window drops its name in the editor window.  > If that is no longer the case, it's a bug. > > In general, don't say things like this.  If the documentation said X, > and you find that X is not true, then one of the following is true: > > * You didn't understand, and X is indeed true.  (And maybe the > documentation needs to be clearer.) > * X is false, and it's a bug.  (The bug should be fixed, not the > documentation.) > * X is false, and has always been false, and it was always a > documentation error.  (And the documentation needs to be fixed.) > * Indeed, X used to be true and is no longer true, and it's an > intentional change, and nobody updated the documentation. This is > a very rare case, because it often means a compatibility problem > or feature regression. > > Regardless, the right answer is to file an issue to get the actual answer. > >> In the following sample code a True Type Font, Andika, has been added >> to the system fonts using its Font Management service. >> > > We shouldn't talk about adding fonts to the system.  That's not our > problem. > > But also, that's not what the sample does.  It adds a font *to > OpenSCAD*, and has nothing to do with the platform font mechanisms. > > >> Supported font file formats areTrueType >> <https://en.wikipedia.org/wiki/TrueType>fonts (*.ttf) andOpenType >> <https://en.wikipedia.org/wiki/OpenType>fonts (*.otf). Once a file is >> registered to the project the details of the fonts in it may be seen >> in the font list dialog (see image) so that the logical font names, >> variations, and their available styles are available for use in the >> project. >> > This says "see image", but doesn't indicate *which* image. > > And:  OpenSCAD doesn't have the notion of "projects" or "registered to > the project". > >> >> 3D Text by Extrusion >> > > This is true of all 2D objects and so does not need to be mentioned.  > Delete. > > >> position >> a vector [X,Y], the origin of the first glyph, thus the >> lower-left corner of the drawn text. >> > No, it's not the origin of the first glyph, or at least that's a > confusing phrase to use.  A glyph is usually positioned slightly to > the right of the origin, and if it's a descender then it's below the > origin, and some characters (e.g. quotes) are well above the origin.  > A more correct statement would be that it's the lower left corner of > the bounding box of the text. > > If one is going to talk about the origin of a glyph, it should be the > point on the baseline to at the left edge of the advance... which this > isn't. > > >> size >> a vector [a,b], the size of the generated text. >> > Should be [x,y].  [a,b] doesn't tell you what "a" and "b" mean. > >> ascent >> positive float, the amount that the text extends above the baseline. >> > Use the word "number" rather than "float". > > It's not always positive; for a glyph entirely below the baseline > (like underscore in Liberation Sans) it's negative. (I'm not sure > that's truly the right definition, but it's the current behavior.) > >> descent >> negative float, the amount that the text extends below the baseline. >> > > Not always negative; for a glyph that is entirely above the baseline > (like apostrophe in Liberation Sans) it's positive. Again, I'm not > sure that's the right definition, but it's the current behavior. > > >> offset >> a vector default [0, 0], the lower-left corner of the box >> containing the text, including inter-glyph spacing before the >> first glyph. >> > > There is no default; this is a value that's returned to you. > > This is not the correct definition (and it wasn't correct in the > original that I wrote).  It's the position of the origin of the text, > after adjusting for halign and valign.  For normal LTR text, the X > coordinate is the X coordinate at the left edge of the first glyph's > advance, and the Y component is the Y coordinate of the baseline. > > >> advance >> a vector default [153.09, 0], amount of space to leave to any >> following text. >> > There is no default (and certainly not that one!). > > The original definition ("the "other end" of the text, the point at > which additional text should be positioned.") wasn't great, but was > more correct.  I would say "The point at which additional text should > be positioned, relative to the text's origin as reported by 'offset'.". > >> This example displays the text metrics for the default font used by >> OpenSCAD: >> > "text metrics for ... font" is a non sequitur.  Text metrics measure a > particular string.  (And "used by OpenSCAD" is unnecessary; the entire > document is in that context.) > > And it's incorrect; the default font is Liberation Sans and this > example uses Liberation Serif. > > Better would be: > > This example displays the text metrics for "Hello, World!" for > Liberation Serif with size=20: > >> <https://en.wikibooks.org/wiki/File:OpenSCAD_textmetrics.png>Using >> textmetrics() to draw a box around text >> >> s="Hello, World!"; >> size=20; >> font="Liberation Serif"; > >> translate([0,0,1]) >> text("Hello, World!",size=size,font=font); > > > Should use "s" instead of repeating the string.  (And this is in my > original, sigh.) > > >> displays (formatted for readability): >> > The original "yields" is better, because it might or might not be > displayed. > >> ECHO:{ >> position=[0.7936,-4.2752]; >> size=[149.306,23.552]; >> ascent=19.2768; >> descent=-4.2752; >> offset=[0,0]; >> advance=[153.09,0]; >> } > > The indentation should match the examples, with the close brace at the > left margin. > >> >> fontmetrics() >> > >> size >> Decimal, optional. The size of the font, as described above >> for|text()|. >> > Replace "decimal" with "number". > >> >> 0% developed  as of November 17, 2009 >> <https://en.wikibooks.org/wiki/Help:Development_stages>3D to 2D >> Projection >> <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/3D_to_2D_Projection> >> >> Using the|projection()|function, you can create 2d drawings from 3d >> models, >> > So far so good. >> >>  and export them to the dxf format. >> > This part should be deleted.  There are any number of things you might > do with a 2D projection of a 3D object.  Exporting to DXF is only one. > >>  It works by projecting a 3D model to the (x,y) plane, with z at 0. >> If|cut=true|, only points with z=0 are considered (effectively >> cutting the object), with|cut=false|(/the default/), points above and >> below the plane are considered as well (creating a proper projection). >> >> *Example*: Consider example002.scad, that comes with OpenSCAD. >> >> <https://en.wikibooks.org/wiki/File:Openscad_projection_example_2x.png> >> >> Then you can do a 'cut' projection, which gives you the 'slice' of >> the x-y plane with z=0. >> > > Doing the non-default case as the first example seems wrong; I would > swap the two examples. > >> *Another Example* >> >> You can also use projection to get a 'side view' of an object. >> > This example seems unnecessary for a reference manual.  It's a > straightforward combination of the features described. > >> Links: >> >> * More complicated example >> <http://www.gilesbathgate.com/2010/06/extracting-2d-mendel-outlines-using-openscad/>from >> Giles Bathgate's blog >> > > Seems inappropriate for a reference manual.  Also, doesn't seem more > complicated at all. > > >> 0% developed  as of November 17, 2009 >> <https://en.wikibooks.org/wiki/Help:Development_stages>2D to 3D >> Extrusion >> <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/2D_to_3D_Extrusion> >> >> Extrusion <https://en.wikipedia.org/wiki/Extrusion>is the process of >> creating an object with a fixed cross-sectional profile. OpenSCAD >> provides two commands >> > > "Commands" isn't the right word.  "Modules" is more correct, but > "operations" is probably best. > > >> Both extrusion methods work on a (possibly disjointed) 2D shape >> normally drawn in the relevant plane (see below). >> > > The old description of the behavior of extrusion for 2D objects that > have been moved off the Z=0 plane is an example of something that > should never have been documented.  It's not a particularly useful > behavior, and we might eventually want a different behavior.  At most, > it should have said "don't do that". > > It should probably say "drawn on the Z=0 plane". > > >> This child object is first projected onto the X-Y plane along the Z >> axis to create the starting face of the extrusion. >> > > Delete.  We shouldn't document that behavior. > > >> The start face is duplicated at the Z position given by the height >> parameter to create the extrusion's end face. The extrusion is then >> formed by creating a surface that joins each point along the edges of >> the two faces. >> > > That's a seriously incomplete description, because it's only true with > all of the parameters at their defaults. > > >> The 2D shape may be any2D primitive shape >> <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/2D_Primitives>, >> a2d polygon >> <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/2D_Primitives#Polygon>, >> animported 2D drawing >> <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/2D_Primitives#Importing_a_2D_Drawing>, >> or aboolean combination >> <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/CSG_Modelling>of >> them. >> > Or, in other words, the 2D shape may be ... a 2D shape. > > Delete the whole sentence. > > >> The 2D shape may have a Z value that moves it out of the X-Y plane, >> and it may even be rotated out of parallel with it. As stated above, >> the extrusion's starting face is the projection of the 2D shape onto >> the X-Y plane, which, if it is rotated, will have the effect of >> fore-shortening it normal to the axis of the rotation. >> > > Delete. > > >> Using a 3D object as the extrusion's child will cause a compile time >> error. >> > > Factually incorrect.  It's not a compile-time error; it's a run-time > error. > > Also, we just said that the child must be a 2D shape.  Exact behavior > when that requirement is violated need not be (and probably should not > be) specified. > > Delete. > >> Including a 3D object in a composition of 2D objects (formed using >> boolean combinations on them) will be detected, the 3D object(s) will >> be deleted from it and the remaining 2D objects will be the basis for >> projecting their shape onto the X-Y plane. >> > We need not (and generally should not) specify the behavior in error > conditions.  Delete. > > >> Parameters For Linear Extrusion >> >> There are no required parameters. The default operation is to extrude >> the child by 100 units vertically from the X-Y Plane, centered on the >> [0,0] origin. >> > "centered" is at best meaningless (because it's extruded wherever the > child is, without respect to the origin) and at worst incorrect > (because the default is to extrude into +Z, not to center in Z). > Delete that last phrase. > >> 1) height >> a non-negative integer, default 100, giving the length of the >> extrusion >> > Doesn't have to be an integer. > > I don't know how strong a pattern we have for specifying parameters, > but they shouldn't be numbered.  (Except maybe if they are usable as > positional parameters - which don't match these numbers.) > > >> 2) v - twist axis vector >> a vector of 3 signed decimal values, default [0,0,1], used as an >> eigen vector specifying the axis of rotation for the >> twist.[Note:Requires versionDevelopment snapshot] >> > I can't say that I truly understand eigenvectors, but I don't think > this is one.  The "signed" part is unnecessary, because all numbers > are signed, and the "decimal" part is meaningless because abstract > numbers have no base. > > "v" is a vector of three numbers that controls the vector along which > the extrusion is done. > > It has an interesting interaction with "height".  If both are > specified, height is used as the length of the extrusion, along the > direction that v points, and v's magnitude is ignored.  If only v is > specified, it is used to control both the direction and length of the > extrusion. > > Saying that it's the axis of rotation for twist is sort of right, but > maybe needs more explanation.  Normally when you think of an axis of > rotation, you're rotating along the plane perpendicular to that axis.  > Here, though, it is perhaps more correct to say that it controls the > *origin* of the rotation. At each slice, the 2D shape is rotated > around Z, with the origin being the XY position of the extrusion vector. > >> 3) center >> a boolean, default false, that, when true, causes the resulting >> solid to be vertically centered at the X-Y plane. >> > "at the Z=0 plane" would be a bit more obvious. > >> 4) convexity >> a non-negative integer, default 1, giving a measure of the >> complexity of the generated surface. See the Section on Convexity >> later on this page. >> > Should include a link... which should not be pointing at this page, no > matter which page we're talking about. > >> 5) twist >> a signed decimal, >> > a number > > >>  180 degrees is a half twist, 360 is all the way around, and so on. >> > Unnecessary, delete. > > >> 6) scale >> either : a non-negative, decimal value, >> > a non-negative number > >> minimum 0.0, >> > > Implied by "non-negative", delete. > > >>  that specifies the factor by which the end face should be scaled >> up, or down, in size from that of the start face. >> > All scaling is either up or down.  Just "should be scaled". > > >> or : an [x,y] vector that scales the extrusion in the X and Y >> directions separately. >> > > Delete the colon. > > >> 7) slices >> a non-negative integer for the number of rows of polygons that >> the extr. >> > Needs help. > > >> h >> a named parameter, synonym to height >> > > Just list it in the same block as height. > > >> $fn $fs $fa >> Special Parameters - given as named parameters. >> > > They have standard special-variable semantics, which means they can be > specified in the context or in the call.  They should be mentioned, > but perhaps not as parameters per se.  I believe they only affect > twisted extrusions, so maybe they should be mentioned there. > > >> Center >> >> This parameter affects only affects the vertical position or the >> extrusion. Its X-Y position is always that of the projection that >> sets its starting face. >> > "or" should be "of". > > This is a nice comment, but doesn't say what the parameter *does*. > > "When true, the extrusion is centered vertically around Z=0." seems > adequate to me, without any further comment, but a subsequent comment > about not affecting X and Y would be OK. > > >> Scale >> >> This is multiplicative factor that affects the size of extrusion's >> end face. As such 1.0 means no change, a value greater than one >> expands the end face, and a value between 0.001 and less than 1 >> shrinks it. >> > "As such" is unnecessary. > > I don't know where 0.001 came from.  I would say "a value less than 1 > shrinks it". > >>  A value of 0.0 causes the end face to degenerate to a point, turning >> the extrusion into a pyramid, cone, or complex pointy shape according >> to what the starting shape is. >> > I'd say this is unnecessary. > > >> Using the vector form sets the scale factor in the X and Y directions >> separately >> >> >> Twist >> >> Twist is applied, by default, as a rotation about the Z Axis. >> > As discussed above, twist is always around Z.  What v controls is the > origin of that rotation. > > >> When the start face is at the origin a twist creates a spiral out of >> any corners in the child shape. If the start face is translated away >> from the origin the twist creates a spring shape. >> > I don't know if it's truly useful to try to describe the various > shapes that can result from twisting. > > One thing that might be worth explicitly mentioning is that you can't > practically use linear_extrude to generate threads.  You can come > temptingly close, but they won't be shaped right.  (It is actually > possible to get right, but requires an unobvious base shape.) > > >> A positive twist rotates clockwise, negative twist the opposite. >> > > Huh.  I basically never use twist, so I never noticed that it's > backwards from rotate.  That seems very wrong... and it's way too late > to fix it.  It might be worth mentioning this difference. > > >> Twist Axis Vector >> >> The second parameter is an [x,y,z] eigen vector that specifies the >> axis of rotation of the applied twist. >> > > Suggest referring to it by name instead of by position. > > >>  The ratios of the three dimensional values to their respective >> coordinate axes specify the tilt away from the default axis, [0,0,1], >> the Z-Axis. For instance, v=[cos(45),0,1] tilts the extrusion at 45 >> degrees to the X axis. >> > > It's actually a skew rather than a tilt. > > >> The start and end faces are always normal to the Z-axis, even when >> the twist axis is tilted. The extruded and twisted surfaces are thus >> distorted from what might be expected in an extruded shape. The more >> expected result may be achieved by applying a rotation to then >> twisted extrusion on the Z Axis to tilt it into the desired position. >> > It's best not to make assumptions about what the user expects. > Describe the operation, and describe it carefully.  Do not describe > how to do things that are straightforward combinations of operations. > > --- > > Note that the documentation does not discuss which happens first:  > twist or scale.  I don't believe it matters when using the same > scaling for X and Y, but matters a great deal with using different > scaling on the two axes.  It twists and then scales, which can mean > (for instance) that a shape that started out rectangular turns into a > parallelogram.  There's an argument that this is *not* the useful > behavior, and that scale-and-then-twist is more useful since it > retains the general shape throughout the extrusion.  I've started a > discussion a few times about maybe changing this, but I don't think it > ever came to a conclusion.  It might be best not to document this > without that conclusion. > > >> $fn, $fa, $fs Special Parameters >> >> The special variables must be given as named parameters and are >> applied to the extrusion, overriding the global setting. When the >> same special variables are set on the base shape its values override >> their use as parameters on the extrusion. >> > None of this is really accurate. > > The special variables have standard special-variable behavior, which > means that you can specify them in the context or in the particular > call, and they apply to that context (including a specific call) and > everything that that is called from that context.  There is no "global > setting" that is special. > > What matters for the linear_extrude (and in particular for twisted > extrusions) is the setting that *it* sees. > > If the child 2D shape *also* uses these variables, what matters for it > is what *it* sees... which, absent an inner setting, will be the same > as what linear_extrude sees. > > Thus, either: > > linear_extrude(height=10, twist=20, $fn=100) circle(10); > > or > > $fn=100; linear_extrude(height=10, twist=20) circle(10); > > will yield a high-resolution twist of a high-resolution circle. > > On the other hand, either > > linear_extrude(height=10, twist=20, $fn=100) circle(10, $fn=3); > > or > > $fn=100; linear_extrude(height=10, twist=20) circle(10, $fn=3); > > will yield a high-resolution twist of a low-resolution circle - a > triangle. > >> >> Extrusion From Imported DXF >> > Does not need to be discussed.  You can linear_extrude any 2D shape, > and an import of a DXF yields a 2D shape. > >> >> A Unit Circle with No Twist >> > > I don't think all of these examples are necessary. > > >> Generate an extrusion from a circle 2 units along the X Axis from the >> origin, >> > unit circle > >> centered vertically on the X-Y plane, with no twist. The extrusion >> appears to have a pentagonal cross-section because the extrusion's >> child is a 2D circle with the default value for $fn. >> > > It doesn't *appear* to have a pentagonal cross-section.  It *does* > have a pentagonal cross-section. > >> The same circle, but made into a spiral by 500 degrees of >> counter-clockwise twist. >> > > If you look carefully, this example demonstrates why you can't make > threads.  As you twist it more, it becomes thinner and thinner in Z.  > The problem is that the cross-section of a thread is a strange shape. > > >> Mesh Refinement >> >> The slices parameter defines the number of intermediate points along >> the Z axis of the extrusion. >> > > I am not sure of the exactly right way to describe this, because of > fence post errors. > > "slices" controls the number of 3D "chunks" that make up the > extrusion.  The total number of instances of the original 2D object is > slices+1. > >> Its default increases with the value of twist. >> > > It's some function of that and $fa/$fs/$fn.  I don't know what the > function is or exactly how to describe it. > > >> Additional the segments parameter >> > Addition -> Additionally > > >> Segments need to be a multiple of the polygon's fragments to have an >> effect (6 or 9.. for a circle($fn=3), 8,12.. for a square() ). >> > > I don't know what the actual behavior is, but that's not it. For more > complex shapes (I experimented with a right triangle) intermediate > values do have an effect. > > >> Thespecial variables >> <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Other_Language_Features>$fn, >> $fs and $fa can also be used to improve the output. If slices is not >> defined, its value is taken from the defined $fn value. >> > > Again, I don't know what the behavior is, but that's not it. > Increasing $fn does increase the number of slices, but it isn't simply > used as the number of slices. > > $fa/$fs/$fn seem to control both slices and segments. > >> >> Using with imported SVG >> > > Does not need to be separately discussed. > > >> rotate_extrude() Operator Module >> >> Rotational extrusion spins a 2D shape around the Z-axis to form a >> solid which has rotational symmetry. One way to think of this >> operation is to imagine a Potter's wheel placed on the X-Y plane with >> its axis of rotation pointing up towards +Z. Then place the >> to-be-made object on this virtual Potter's wheel (possibly extending >> down below the X-Y plane towards -Z). The to-be-made object is the >> cross-section of the object on the X-Y plane (keeping only the right >> half, X >= 0). That is the 2D shape that will be fed to >> rotate_extrude() as the child in order to generate this solid. Note >> that the object started on the X-Y plane but is tilted up (rotated >> +90 degrees about the X-axis) to extrude. >> > > I'm not sure that this is the best possible explanation. > > >> Since a 2D shape is rendered by OpenSCAD on the X-Y plane, an >> alternative way to think of this operation is as follows: spins a 2D >> shape around the Y-axis to form a solid. The resultant solid is >> placed so that its axis of rotation lies along the Z-axis. >> > > That's the way that I always think of it, though I mentally rotate it > to vertical before spinning it. > > >> Just like the linear_extrude, the extrusion is always performed on >> the projection of the 2D polygon to the XY plane. >> > > Again, we should not document this behavior. > > >> Transformations like rotate, translate, etc. applied to the 2D >> polygon before extrusion modify the projection of the 2D polygon to >> the XY plane and therefore also modify the appearance of the final 3D >> object. >> >> * A translation in Z of the 2D polygon has no effect on the result >> (as also the projection is not affected). >> * A translation in X increases the diameter of the final object. >> * A translation in Y results in a shift of the final object in Z >> direction. >> * A rotation about the X or Y axis distorts the cross section of >> the final object, as also the projection to the XY plane is >> distorted. >> > > This is perhaps good stuff, if the part about projecting is removed. > > >> Don't get confused, as OpenSCAD displays 2D polygons with a certain >> height in the Z direction, so the 2D object (with its height) appears >> to have a bigger projection to the XY plane. But for the projection >> to the XY plane and also for the later extrusion only the base >> polygon without height is used. >> > > Once you get rid of the part about projecting this goes away too. > > >> You cannot use rotate_extrude to produce a helix or screw thread. >> Doing this properly can be difficult, so it's best to find a thread >> library to make them for you. >> > > This kind of comment can be valuable, but I'm not sure it belongs in a > reference manual.  If it *is* in a reference manual, it should be in a > clear and separate section (of the description of the particular > feature) marked "Application Notes" or something like that, to make it > clear that it's *not* part of the description of the feature. > > >> If the shape spans the X axis a warning appears in the console >> windows and the rotate_extrude() is ignored. >> > Don't talk about what window something appears in, because not > everybody uses the OpenSCAD GUI. > > Don't talk about what happens "after" the error. > > Just say that it's an error, period. > > (And, BTW, this particular one is something that I think should not be > an error; I think that the result should be as if you split the 2D > shape in half, rotationally extruded both, and unioned them.  That is, > take the shape, sweep it 360 degrees, and anything it sweeps through > (whether once or twice) is part of the result.) > > >>  If the 2D shape touches the Y axis, i.e. at x=0, it*must*be a line >> that touches, not a point, as a point results in a zero thickness 3D >> object, which is invalid and results in a CGAL error. >> > > This may have been addressed with Manifold. > > >> *convexity* : If the extrusion fails for a non-trival 2D shape, >> try setting the convexity parameter (the default is not 10, but >> 10 is a "good" value to try). See explanation further down. >> > > Just point at the general discussion of convexity.  (Which should not > be on this page.) > > And the extrusion does not "fail".  In fact, the artifacts may be > quite subtle. > > >> *start*[Note:Requires versionDevelopment snapshot] : Defaults to >> 0 if*angle*is specified, and 180 if not. Specifies the starting >> angle of the extrusion, counter-clockwise from the positive X axis. >> > > start was part of an effort to align rotational extrusion behavior > with the behavior of other round things.  I don't remember all of the > details, but there are few reasons why it isn't equivalent to rotating > the result. > > >> *$fa* : minimum angle (in degrees) of each fragment. >> *$fs* : minimum circumferential length of each fragment. >> *$fn* :*fixed*number of fragments in 360 degrees. Values of 3 or >> more override $fa and $fs >> >> $fa, $fs and $fn must be named parameters.click here for more >> details, >> <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Other_Language_Features>. >> > Do not describe these in detail here.  Refer to a general description > of them elsewhere. > > Do not ever, ever, say "click here".  Any text that would not make > sense when printed is wrong. > > >> Rotate Extrude on Imported DXF >> > > Delete. > > >> Increasing the number of fragments composing the 2D shape improves >> the quality of the mesh, but takes longer to render. >> > > Unnecessary. > > >> rotate_extrude(convexity = 10) >> translate([2, 0, 0]) >> circle(r = 1, $fn = 100); > > This example is unnecessary; this is a description of rotate_extrude, > not circle() > >> The number of fragments used by the extrusion can also be increased. >> >> rotate_extrude(convexity = 10, $fn = 100) >> translate([2, 0, 0]) >> circle(r = 1, $fn = 100); > > > Use $fs and $fa here.  In fact, supply them at the top level. And this > case doesn't require specifying convexity (though I'm not sure why > not).  Also, for circles this small high resolution is not practical; > make them bigger to make the example more real. Thus: > > $fa = 1; > $fs = 1; > rotate_extrude() > translate([20, 0, 0]) > circle(r = 10); > > That's really the best practice.  You almost never want to use $fn if > your intent is to create a circle. > > (Minor exception that is itself something of a bug:  if you're trying > to force the number of sides to be a multiple of 4.  But that > shouldn't be discussed here.) > > >> Using the parameter angle (with OpenSCAD versions 2016.xx), a hook >> can be modeled . >> >> <https://en.wikibooks.org/wiki/File:Hook.png>OpenSCAD - a hook >> >> eps = 0.01; >> translate([eps, 60, 0]) >> rotate_extrude(angle=270, convexity=10) >> translate([40, 0]) circle(10); >> rotate_extrude(angle=90, convexity=10) >> translate([20, 0]) circle(10); >> translate([20, eps, 0]) >> rotate([90, 0, 0]) cylinder(r=10, h=80+eps); > > > Delete. > > >> Extruding a Polygon >> > > Delete. > > >> Description of extrude parameters >> > > Why are we repeating these here?  Don't, especially because there is > little commonality between linear_extrude and rotate_extrude. > > >> 0% developed  as of November 17, 2009 >> <https://en.wikibooks.org/wiki/Help:Development_stages>DXF >> Extrusion >> <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/DXF_Extrusion> >> > > Delete. > >> >> Import 2D >> >> Import 2D Shapes >> <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Import_2D> >> > > This should get more content.  At the current state of things it can > probably all go on the 2D page, but if it gets much more complex it > might want its own page with a brief summary and reference here. > > > > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email todiscuss-leave@lists.openscad.org -- This email has been checked for viruses by AVG antivirus software. www.avg.com
JB
Jordan Brown
Fri, Aug 8, 2025 12:30 PM

On 8/8/2025 4:36 AM, Jon Bondy wrote:

What is the community getting for this INCREDIBLE level of effort?

To be fair, a lot of the issues that I commented on were already there. 
I didn't try to distinguish, since much of my goal was to give my
opinions on what did and did not make good reference material.

  1. perhaps this should be controlled in a manner similar to the
    development of the software itself, with a GIT-like system of problem
    descriptions and resolutions.

Perhaps, but there's value to the fact that making small corrections is
very light-weight.

Probably the biggest thing is to write something that gives guidelines
for writing the documentation, e.g. in no particular order:

  • What belongs in the reference section, and what belongs in the
    tutorial section?
  • If you're thinking of a large change, talk to people first.
  • If you don't know the truth, ask for help.
  • What kinds of examples should you give, and how many?
  • Remember the interaction with cheat sheets, including cheat sheets
    for older releases.
  • What is the style for each section?  What does an entry for a
    function look like?
  • There should be an official glossary.
  • Where is transclusion appropriate?  When is it appropriate to split
    something off into a new page?

The documentation certainly could use work, but the first requirement
for any change is that it's right.

On 8/8/2025 4:36 AM, Jon Bondy wrote: > > What is the community getting for this INCREDIBLE level of effort? > To be fair, a lot of the issues that I commented on were already there.  I didn't try to distinguish, since much of my goal was to give my opinions on what did and did not make good reference material. > 4) perhaps this should be controlled in a manner similar to the > development of the software itself, with a GIT-like system of problem > descriptions and resolutions. > Perhaps, but there's value to the fact that making small corrections is very light-weight. Probably the biggest thing is to write something that gives guidelines for writing the documentation, e.g. in no particular order: * What belongs in the reference section, and what belongs in the tutorial section? * If you're thinking of a large change, talk to people first. * If you don't *know* the truth, ask for help. * What kinds of examples should you give, and how many? * Remember the interaction with cheat sheets, including cheat sheets for older releases. * What is the style for each section?  What does an entry for a function look like? * There should be an official glossary. * Where is transclusion appropriate?  When is it appropriate to split something off into a new page? The documentation certainly could use work, but the first requirement for any change is that it's right.
JJ
jon jonbondy.com
Fri, Aug 8, 2025 12:34 PM

Thank you, Jordan

Jon

On 8/8/2025 8:30 AM, Jordan Brown wrote:
On 8/8/2025 4:36 AM, Jon Bondy wrote:

What is the community getting for this INCREDIBLE level of effort?

To be fair, a lot of the issues that I commented on were already there.  I didn't try to distinguish, since much of my goal was to give my opinions on what did and did not make good reference material.

  1. perhaps this should be controlled in a manner similar to the development of the software itself, with a GIT-like system of problem descriptions and resolutions.

Perhaps, but there's value to the fact that making small corrections is very light-weight.

Probably the biggest thing is to write something that gives guidelines for writing the documentation, e.g. in no particular order:

  • What belongs in the reference section, and what belongs in the tutorial section?
  • If you're thinking of a large change, talk to people first.
  • If you don't know the truth, ask for help.
  • What kinds of examples should you give, and how many?
  • Remember the interaction with cheat sheets, including cheat sheets for older releases.
  • What is the style for each section?  What does an entry for a function look like?
  • There should be an official glossary.
  • Where is transclusion appropriate?  When is it appropriate to split something off into a new page?

The documentation certainly could use work, but the first requirement for any change is that it's right.

Thank you, Jordan Jon On 8/8/2025 8:30 AM, Jordan Brown wrote: On 8/8/2025 4:36 AM, Jon Bondy wrote: What is the community getting for this INCREDIBLE level of effort? To be fair, a lot of the issues that I commented on were already there. I didn't try to distinguish, since much of my goal was to give my opinions on what did and did not make good reference material. 4) perhaps this should be controlled in a manner similar to the development of the software itself, with a GIT-like system of problem descriptions and resolutions. Perhaps, but there's value to the fact that making small corrections is very light-weight. Probably the biggest thing is to write something that gives guidelines for writing the documentation, e.g. in no particular order: * What belongs in the reference section, and what belongs in the tutorial section? * If you're thinking of a large change, talk to people first. * If you don't *know* the truth, ask for help. * What kinds of examples should you give, and how many? * Remember the interaction with cheat sheets, including cheat sheets for older releases. * What is the style for each section? What does an entry for a function look like? * There should be an official glossary. * Where is transclusion appropriate? When is it appropriate to split something off into a new page? The documentation certainly could use work, but the first requirement for any change is that it's right.
JB
Jordan Brown
Fri, Aug 8, 2025 12:36 PM
  1. perhaps this should be controlled in a manner similar to the
    development of the software itself, with a GIT-like system of
    problem descriptions and resolutions.

By the way, it's entirely appropriate to use github issues to report
documentation issues, even though we don't use github to manage the
documentation.

>>> 4) perhaps this should be controlled in a manner similar to the >>> development of the software itself, with a GIT-like system of >>> problem descriptions and resolutions. >>> By the way, it's entirely appropriate to use github issues to report documentation issues, even though we don't use github to manage the documentation.
JJ
jon jonbondy.com
Fri, Aug 8, 2025 12:37 PM

Perhaps I can frame this differently.

Why would we want to exercise [rigid?] control over the software source code, and exercise no [explicit] control over the documentation?

What is the appropriate level of documentation control, and how should it be managed?

Jon

On 8/8/2025 8:30 AM, Jordan Brown wrote:
On 8/8/2025 4:36 AM, Jon Bondy wrote:

What is the community getting for this INCREDIBLE level of effort?

To be fair, a lot of the issues that I commented on were already there.  I didn't try to distinguish, since much of my goal was to give my opinions on what did and did not make good reference material.

  1. perhaps this should be controlled in a manner similar to the development of the software itself, with a GIT-like system of problem descriptions and resolutions.

Perhaps, but there's value to the fact that making small corrections is very light-weight.

Probably the biggest thing is to write something that gives guidelines for writing the documentation, e.g. in no particular order:

  • What belongs in the reference section, and what belongs in the tutorial section?
  • If you're thinking of a large change, talk to people first.
  • If you don't know the truth, ask for help.
  • What kinds of examples should you give, and how many?
  • Remember the interaction with cheat sheets, including cheat sheets for older releases.
  • What is the style for each section?  What does an entry for a function look like?
  • There should be an official glossary.
  • Where is transclusion appropriate?  When is it appropriate to split something off into a new page?

The documentation certainly could use work, but the first requirement for any change is that it's right.

Perhaps I can frame this differently. Why would we want to exercise [rigid?] control over the software source code, and exercise no [explicit] control over the documentation? What is the appropriate level of documentation control, and how should it be managed? Jon On 8/8/2025 8:30 AM, Jordan Brown wrote: On 8/8/2025 4:36 AM, Jon Bondy wrote: What is the community getting for this INCREDIBLE level of effort? To be fair, a lot of the issues that I commented on were already there. I didn't try to distinguish, since much of my goal was to give my opinions on what did and did not make good reference material. 4) perhaps this should be controlled in a manner similar to the development of the software itself, with a GIT-like system of problem descriptions and resolutions. Perhaps, but there's value to the fact that making small corrections is very light-weight. Probably the biggest thing is to write something that gives guidelines for writing the documentation, e.g. in no particular order: * What belongs in the reference section, and what belongs in the tutorial section? * If you're thinking of a large change, talk to people first. * If you don't *know* the truth, ask for help. * What kinds of examples should you give, and how many? * Remember the interaction with cheat sheets, including cheat sheets for older releases. * What is the style for each section? What does an entry for a function look like? * There should be an official glossary. * Where is transclusion appropriate? When is it appropriate to split something off into a new page? The documentation certainly could use work, but the first requirement for any change is that it's right.
JB
Jordan Brown
Fri, Aug 8, 2025 1:41 PM

Why would we want to exercise [rigid?] control over the software
source code, and exercise no [explicit] control over the documentation?

Because the blast radius is larger when mistakes are made modifying the
source code.

If you make a typo in the documentation, it's ... a typo.  If you make a
typo in the source, the program doesn't build, or crashes, or quietly
misbehaves.

If you add a feature to the program that we later regret, it's hard to
back it out because people may have come to depend on it. It isn't
possible to depend on an erroneous comment in documentation.

What is the appropriate level of documentation control, and how should
it be managed?

That is a very good question.

I suspect that one aspect of the answer is that our source gatekeepers
(basically, Torsten and Marius; there are a few other authorized people
but they are rarely active) are fully loaded, and I don't think they
want to take over as documentation gatekeepers too.  We'd need several
documentation gatekeepers.

Another question that I don't know the answer to is what level of
control Wikibooks lets us have.

> Why would we want to exercise [rigid?] control over the software > source code, and exercise no [explicit] control over the documentation? > Because the blast radius is larger when mistakes are made modifying the source code. If you make a typo in the documentation, it's ... a typo.  If you make a typo in the source, the program doesn't build, or crashes, or quietly misbehaves. If you add a feature to the program that we later regret, it's hard to back it out because people may have come to depend on it. It isn't possible to depend on an erroneous comment in documentation. > What is the appropriate level of documentation control, and how should > it be managed? > That is a very good question. I suspect that one aspect of the answer is that our source gatekeepers (basically, Torsten and Marius; there are a few other authorized people but they are rarely active) are fully loaded, and I don't think they want to take over as documentation gatekeepers too.  We'd need several documentation gatekeepers. Another question that I don't know the answer to is what level of control Wikibooks lets us have.
RW
Raymond West
Fri, Aug 8, 2025 2:07 PM

If it ain't broke, work on until it is.😉

The attraction of openscad is it's relatively small set of functions.
I've done everything I need with raw openscad (with the help from a few
folk on here). Bosl2 is there for those who want an easier answer. It
seems that some folk are wanting it to do things that were never
designed into openscad functionality. For those folk, learn fusion,
blender, whatever.

The terminology in parts is a tad incorrect, cubes are more than
squares, cylinders are more than cylinders, and you will never see a
true circle on any digital display. Also, the language is initially
awkward, and the solids can often have unwanted holes, but if you spend
the time and effort you get used to it.

My comment is related to openscad as a whole, not specific to 2d, but as
nothing in the real world is 2d...

Best wishes,

Ray

On 08/08/2025 12:36, Jon Bondy via Discuss wrote:

What is the community getting for this INCREDIBLE level of effort?

I think we should

  1. revert the documentation back to prior to when Vulcan started
    changing things

  2. make a list of problems with the documentation (an explicit,
    reviewable requirements list from which we can make controlled changes
    to the documentation)

  3. make small, localized changes that can be validated with minimal
    effort.

  4. perhaps this should be controlled in a manner similar to the
    development of the software itself, with a GIT-like system of problem
    descriptions and resolutions.

The people who really contribute to OpenSCAD are few, perhaps less
than half a dozen.  To force them to spend their time working on a
project THAT DOES NOT NEED TO BE DONE, and is not going well, will
slow down development and bug fixes that DO need to be done.

It is clear to me that having an OpenSCAD novice working on the
documentation is not a great idea.   Good intentions but bad results.

Vulcan: if you REALLY want to help this community, use OpenSCAD
actively (every day) for a year, making complex designs, and then come
back.

Is there anyone (or any group) that is in control of the documentation
Wiki?  If not, we need such an entity.  If so, someone needs to take
control of this project.

Again, if I'm wrong, I apologize.  But I have been getting private
messages agreeing with me.

Jon

On 8/8/2025 4:08 AM, Jordan Brown via Discuss wrote:

[ I'll spend the effort to fix up this laptop configuration, again,
sorry for the duplicates. ]

Two Dimensional Modelling

0% developed  as of November 17, 2009
https://en.wikibooks.org/wiki/Help:Development_stages2D
Primitives
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/2D_Primitives

All 2D primitives can be transformed with 3D transformations.

Really bad place to start.  Yes, you can transform them with 3D
transforms, but if you do then the results can be weird. It should be
discouraged; you should almost always work with 2D transforms when
working with a 2D subassembly.

Also, maybe we should talk about the primitives before we talk about
what you can do with them.

 They are usually used as part of a 3D extrusion.

Yeah, eventually.  But again this doesn't seem appropriate for a "2D
primitives" section.  Maybe for an overview section above that.

 Although they are infinitely thin, they are rendered with a 1-unit
thickness.

Again, maybe in an overview section.

Note: Trying to subtract with|difference()|from 3D object will
lead to unexpected results in final rendering.

The real rule is "don't mix 2D objects with 3D objects and 3D
operations".  It isn't necessary or appropriate to say very much
about what will happen if you do.  Some cases will yield errors,
while others will do something weird.  We don't want the
documentation to nail down any particular behavior, because there are
reasons that we might want to change the behavior in these cases.

Ref, e.g., OEP 7 "Mixed Dimension Geometry Support"
https://github.com/openscad/openscad/wiki/OEP7%3A-Mixed-Dimension-Geometry-Support.

 Square Object Module

By default this module draws a unit square in the first quadrant,
(+X,+Y), starting at the origin [0,0]. Its four lines have no
thickness but the shape is drawn as a 1 unit high, filled plane.

The second sentence should probably just go away:

  • The first part "its four lines have no thickness" is both
    misleading - the lines have no independent existence - and
    incorrect; when rendered they do have thickness.
  • The second half (drawn as 1 unit high) restates something already
    said in above.

The module's arguments may be written in the order|<size>,
center=<bool>|without being named, but the names may be used as
shown in the examples:

There needs to be (but probably isn't) enough documentation
convention that this need not be said.

Parameters

size
has two forms:/single value/or/vector/
single - non-negative float, length of all four sides

Should use the word "number" rather than the word "float". OpenSCAD
does not have distinct floating point and integer types; it has only
numbers.

center
boolean, default false, to set the shape's position in the X-Y plane

CenterWhen|false|, as it is by default, the shape will be drawn
from its first point at (0,0) in the First Quadrant, (+X,+Y). With
center set to|true|the shape is drawn centered on the origin.

These two paragraphs should be merged.

 Circle Object Module

By default this module draws a unit circle centered on the origin
[0,0] as a pentagon with its starting point on the X-axis at X=1.
Its lines have no thickness but the shape is drawn as a 1 unit high,
filled plane.

The part of the first sentence starting "as a pentagon ..." should go
away.  It's true, but it really belongs as part of the description of
$fa/$fs.

Again, the second sentence should just go away.

Somewhere it should say "Circles are approximated as regular
polygons; see <reference to $fa/$fs/$fn> for the details of the
polygons generated."

The argument|radius|may be given without being named, but
the|r|and|d|arguments must be named.

There is no "radius" argument.  There are r and d.

Again, we should have a documentation convention so that we don't
have to repeat positional/named rules, but the behavior here is that
r can be supplied as the first argument, but d must be named.

(Technically, if you say "circle(undef, 10)" the 10 is the second  it
creates a 10-unit-diameter circle.  I would say that the fact that
this works is a minor bug.)

$fa
Special Variable
$fs
Special Variable
$fn
Special Variable

Theses should be described only to the extent of pointing at the
general description of $fa/$fs/$fn.

The default circle displays as a pentagram as that is the minimum
number of fragments used to approximate a curved shape calculated
from the default values for $fs and $fa. To have it draw as a smooth
shape increase the $fn value, the minimum number of fragments to
draw, to 20 or more (best $fn < 128).

This is just bad.  First, everything here should be covered in the
description of $fa/$fs/$fn.  Second, using $fn to control the
resolution of a circle is generally the wrong answer; you are better
off setting $fa and $fs.  Finally, specific advice on $fn values is a
bad idea, because the "looks smooth" value varies dramatically with
size.  A 20-gon is okay for a medium-small circle; a 72-gon is not
good enough for a 100-unit circle.

An alternative method to draw a very smooth circle scale is to scale
down a very large circle.

scale( 0.001 ) circle(200);

This should just go away; it confuses the issue.

Another way to solve the lack of a built-in module for regular
polygons is to write a custom one:module regular_polygon()
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/example_module_regular_polygon()

I wouldn't include this.  Using polygon() is harder than using
circle(), and anybody who's capable of using it should have little
trouble simulating circle().

convexity
Integer, default=1 - complex edge geometry may require a higher
value value to preview correctly.

Should include a link to a general discussion of convexity. Probably
should not even mention the default; that should be covered in the
general discussion.

Points ParameterA list of X-Y coordinates in this form:

[[1, 1], [1, 4], [3, 4], [3, 1], [1, 1]]

which defines four points and makes it explicit that the last one is
the same as the first.

Including the first point twice is not strictly necessary as this:

[[1, 1], [1, 4], [3, 4], [3, 1]]

gives the same result.

This seems like it should be simplified.  In the absence of a paths
parameter, the last point always connects to the first, because
polygons are always closed.

Paths Parameter

This optional parameter is a nested vector of paths.

A "path" is a list of index values that reference points in
the|points|vector. It can explicitly describe a closed loop by its
last index being the same as its first, as in:

[1, 2, 3, 4, 1]

but this is equivalent to:

[1, 2, 3, 4]

Again, this seems like unnecessary complexity; the last point always
connects to the first.

Notice that the points vector is simple list,

No, it's a list of lists.

 while each path is a separate vector.

Yes... points and paths are the same order. They are both lists of lists.

 This means that paths, that are lists of references to points, have
to "know" which points it needs to include.

While it's true that paths need to "know" the indexes they connect, I
don't see how that follows from the previous sentences.

 This can be an issue if the polygon is assembled from a number of
shapes at run time as the order of adding shapes affects their
point's index values.

It's true that this is something that you must handle, but I don't
think that a reference manual needs to discuss it.

 .Convexity

Formatting error:  this title is merged with the previous paragraph.
(But should be deleted, see below.)

Shapes with a lot of detail in their edges may need the convexity
parameter increased to preview correctly. See Convexity

Already discussed, should be deleted.

Example With Multiple Holes

[Note:Requires version2015.03] (for use of|concat()|)

https://en.wikibooks.org/wiki/File:OpenSCAD_romboid_with_holes.jpg

We are using "a" for the point lists and "b" for their paths:

a0 = [[0,0],[100,0],[130,50],[30,50]];    // outer boundary
b0 = [1,0,3,2];
a1 = [[20,20],[40,20],[30,30]];            // hole 1
b1 = [4,5,6];
a2 = [[50,20],[60,20],[40,30]];            // hole 2
b2 = [7,8,9];
a3 = [[65,10],[80,10],[80,40],[65,40]];    // hole 3
b3 = [10,11,12,13];
a4 = [[98,10],[115,40],[85,40],[85,10]];  // hole 4
b4 = [14,15,16,17];
a  = concat( a0,a1,a2,a3,a4 ); // merge all points into "a"
b  = [b0,b1,b2,b3,b4]; // place all paths into a vector
polygon(a,b);
//alternate
polygon(a,[b0,b1,b2,b3,b4]);

The "alternate" at the end of the example seems unnecessary - of
course you can use either a particular expression or a variable that
has been set to that expression.

2D to 3D by Extrusion

A polygon may be the basis for an extrusion, just as any of the 2D
primitives can. Thisexample script
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/example_module_2D_to_3D_extrusionmay
be used to draw the shape in this image:

Yes, a polygon can be used as the basis for extrusion, just as any of
the 2D primitives can.  That means that you do not need a specific
example of that case.

 Import a 2D Shape From a DXF

[Deprecated:import_dxf() will be removed in a future release. Use
Useimport() Object Module
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/The_OpenSCAD_Language#importinstead.
instead*]*

As a deprecated feature, this should be pushed to the bottom.

Read a DXF file and create a 2D shape.

Example

linear_extrude(height = 5, center = true)
import_dxf(file = "example009.dxf", layer = "plate");

Example with Import()

linear_extrude(height = 5, center = true)
import(file = "example009.dxf", layer = "plate");

The second should perhaps be titled "Replacement example with
import()".  Note also that since OpenSCAD is case sensitive the word
"import" should not be capitalized.

Text is a big enough topic that it should probably have its own page,
with just a brief mention and cross-reference here.

I see that it has its own page and is transcluded here.  It should
not be transcluded, because that makes it harder to just read everything.

Text in OpenSCAD

Being able to use text objects as a part of a model is valuable in a
lot of design solutions.

Delete this sentence.  This is reference material, not sales
material.  The user already knows whether or not it's valuable to them.

The fontsavailable to use in a script
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Text#Fonts_in_OpenSCADare
from the system that OpenSCAD is running in with the addition of
those explicitly added by the script itself.

And OpenSCAD includes several.  (And this duplicates a more extensive
discussion below.)

 text() Object Module

The|text()|object module draws a single string of text as a 2D
geometric object, using fonts installed on the local system or
provided as separate font file.

provided as +a+ separate font file

The shape starts at the origin and is drawn along the positive X axis.

By default, ...

(because halign and valign change things)

text
String. A single line ofany character allowed
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Characters_Strings#Characters.*Limitation:*non-printable
ASCII characters like newline and tab rendered as placeholders

Delete the second sentence.  If it's a string, it's allowed. As for
being a single line and treatment of non-printable characters, need
to phrase that as a current restriction, not as a permanent behavior

  • it would be good if we could eventually provide more support there,
    and we wouldn't want to be prevented from adding that support by
    compatibility concerns.  Ref
    https://github.com/openscad/openscad/issues/5018 for the desire for
    multi-line text.

font
aformatted string
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Text#Parameterswith
default font of "Liberation Sans:style=Regular"

"formatted string" is a poor phrase there.  Better would be something
like "String.  A font specification with ...".

Also I see that this is a link over to a separate Text page. A
separate Text page is good, as discussed above, but it shouldn't be
duplicated here.

size
non-negative decimal, default=10. The generated text has a
height above the baseline of approximately this value, varying
for different fonts but typically being slightly smaller.

The "decimal" part should be "number".  (It isn't even sensible to
talk about a base.)

I don't feel the need for the "non-negative" part.  (It should
probably also be non-zero.)  Unless we have a special meaning for a
negative size, we should be able to let people figure out for
themselves that if they make a silly request they will get a silly
answer.

Current behavior is ... interesting... though when you think about it
unsurprising:  the text is mirrored in X and Y, leading to it being
effectively rotated 180 degrees.  Unless we really want to keep that
behavior, we should probably make it be an error instead.  Until and
unless we decide that we want to keep that behavior, we should not
document it.

There needs to be a footnote about size.  Because of an arithmetic
error in the implementation (issue #4304
https://github.com/openscad/openscad/issues/4304), the "size"
parameter does not correspond to a typical font size specification. 
It is a coincidence that the arithmetic error approximately cancels
out the usual ratio between the specified font size and the size of a
capital letter, making "size" approximately specify the size of a
capital letter in a typical Western font.  However, since the result
is useful, and the error has been in place since the beginning, we
really can't fix it.  Maybe at some point we can introduce an
alternative parameter that specifies a more conventional font size,
eg PR#4306 https://github.com/openscad/openscad/pull/4306.

spacing
float, default=1. Multiplicative factor that increases or
decreases spacing between characters.

"float" should be "number".

language
String. The language of the text (e.g., "en", "ar", "ch").
Default is "en".
script
String, default="latin". The script of the text (e.g. "latin",
"arabic", "hani").

Somebody needs to figure out what these actually do.

$fn
higher values generate smoother curves (refer toSpecial
Variables
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Other_Language_Features#special_variables)

This should refer to $fa, $fs, and $fn... and really you shouldn't be
using $fn here.

   Font & Style Parameter

The "name" of a font is a string starting with its|logical font
name|and|variation|,

I don't see variation as a separate part of the specification.

Also, use of the "typewriter" font here is inappropriate; neither of
these is a language keyword or language component. Either use plain
text or perhaps italics.

 optionally followed by a colon (":") separated list of font
specifications like a|style|selection, and a set of zero or
more|features|.

We should include a list of the name=value specifications supported,
or refer to external (fontconfig?) documentation.

Again, "features" is not a keyword and should not be in typewriter font.

The common variations in a font family are|sans|and|serif|though
many others will be seen in the list of fonts available. Each font
variation can be drawn with a/style/to support textual emphasis.

I think those are part of the font name, and that there they are
usually capitalized.  I'm a bit torn on whether they should be in
typewriter font.

The default, upright appearance is usually called "Regular" with
"Bold", "Italic", and "Bold Italic" being the other three styles
commonly included in a font. In general the styles offered by a font
may only be known by using the platform's font configuration tools
or theOpenSCAD font list dialog
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Text#Fonts_in_Openscad.

This should explicitly tie to the "style=" parameter.

The fontfeatures property is appended to the|font name|after the

"fontfeatures" should be in typewriter font because it is a keyword.

"font name" should not be in typewriter font because it is not a
keyword.

optional style parameter. Its value is a semi-colon separated list
of feature codes, each prefixed by a plus, "+", to indicate that it
is being added,

Should end with a colon, not a comma.

font = "Linux Libertine G:style=Regular:fontfeatures=+smcp;+onum");

Size Parameter

Text size is normally given in points, and a point is 1/72 of an
inch high. The formula to convert thesizevalue to "points" is|pt =
size/3.937|, so asizeargument of 3.05 is about 12 points.

This is incorrect, because OpenSCAD is unitless.  "size" specifies
some dimension of the font, in OpenSCAD units.  See the discussion
above about exactly what dimension it measures. (OpenSCAD units are
typically interpreted as millimeters, but that's up to the user and
the consuming program; it is not part of OpenSCAD's definitions.)

There should be no reference to "points" except perhaps to disclaim
that anything is measured in points.

Note: Character size the distance from ascent to descent, not from
ascent to baseline.

Ref the arithmetic error mentioned above and the long discussion in
issue #4304, this is incorrect.  "size" should have measured
approximately the font ascent plus descent, but instead measures
(even more approximately) the font ascent.

One of these four names must be given as a string to
the|valign|parameter.

Since the valign parameter itself is optional, the word "must" seems
inappropriate.  Perhaps "The valign parameter may be set to one of
these four words".

top
The text is aligned so the top of the tallest character in your
text is at the given Y coordinate.

There is no "given Y coordinate".  The top of the tallest character
in your text is at the X axis, Y=0.

center
The text is aligned with the center of the bounding box at the
given Y coordinate.

Again, at Y=0.

baseline
The text is aligned with the font baseline at the given Y
coordinate.

Again, at Y=0.

bottom
The text is aligned so the bottom of the lowest-reaching
character in your text is at the given Y coordinate.

Again, at Y=0.

Note: only the "baseline" vertical alignment option will ensure
correct alignment of texts that use mix of fonts and sizes.

This overlaps a lot with the last sentence of the definition of
"baseline" and should probably be merged with it.

One of these three names must be given as a string to
the|halign|parameter.

Again, the word "must" seems inappropriate.

left
The text is aligned with the left side of the bounding box at
the given X coordinate.
center
The text is aligned with the center of the bounding box at the
given X coordinate.
right
The text is aligned with the right of the bounding box at the
given X coordinate.

None of these are correct.  The alignment is based on spacing, not on
the bounding box.  For most letters, "left" will position the ink
slightly to the right of X=0.  (For a size=10 M in Liberation Sans,
it's about 1.1 units right of X=0.)  I'd need to do more research to
figure out the exactly correct wording.

And for all of them, there is no "given [XY] coordinate". Positioning
is relative to the origin.

Spacing Parameter

Characters in a text element have the size dictated by their glyph
in the font being used. As such their size in X and Y is fixed. Each
glyph also has fixed|advance|values (it is a vector [a,b],
seetextmetrics
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Text#textmetrics)
for the offset to the origin of the next character. The position of
each following character is the|advance.x|value multiplied by
the|space|value. Obviously letters in the string can be stretched
out when the factor is greater than 1, and can be made to overlap
when|space|is a fraction closer to zero, but interestingly, using a
negative value spaces each letter in the opposite of
the|direction|parameter.

This is more or less correct, but what it doesn't say is that
"spacing" is almost completely useless for a proportionally spaced
font, for two reasons.  Ref
https://github.com/openscad/openscad/issues/3859 .

  • It does not take ligatures into account; it spaces a ligature as
    a single glyph, yielding text that looks like "d i ffi c u l t".
  • Because it's a multiplier on the advance value, and because the
    advance value is larger for a wide glyph than it is for a narrow
    glyph, spacing between narrow glyphs and wide glyphs is radically
    different.  "IIIMMM" demonstrates this problem.

The "spacing" parameter should probably be downplayed, and should
probably be deprecated.

   Text Examples

Simulating Formatted Text

Needs to define what it means by "formatted".

When text needs to be drawn as if it was formatted it is possible to
use translate() to space lines of text vertically. Fonts that
descend below the baseline need to be spaced apart vertically by
about|1.4size|to not overlap. Some word processing programs use a
more generous spacing of|1.6
size|for "single spacing" and double
spacing can use|3.2*size|.

fontmetrics() can supply more correct values for the particular font.

But really this is advice, not reference material.

 Fonts in OpenSCAD

The fonts available for use in a script are thosed:

  • registered in the local system
  • included in the OpenSCAD installation
  • imported at run-time by a program

A call to fontmetrics() using only default settings shows the
installation's standard font and settings:

Any reference to fontmetrics() needs a "requires release XXX" note,
which at the moment is still "requires development snapshot".  But
really this should be at most a reference to the fontmetrics() section.

{
nominal = {
ascent = 12.5733;
descent = -2.9433;
};
max = {
ascent = 13.6109; descent = -4.2114;
};
interline = 15.9709;
font = {
family = "Liberation Sans";
style = "Regular";
};
}

Wherever this ends up, the indentation needs work.  It should match
the indentation style used in the examples.

None of the platforms OpenSCAD is available on include the
Liberation font family so having it as part of the app's
installation, and making it the default font, avoids problems of
font availability.

"None" is an awfully broad statement about a moving target. It would
be better to say "To avoid problems of font availability, OpenSCAD
includes the Liberation font family as part of its installation, and
has Liberation Sans as the default font.".

Note: It was previously noted in the docs that fonts may be added
to the installation by drag-and-drop of a font file into the editor
window, but as of version 2025 Snapshot this isnotthe case

That isn't what it said.  It said:

 You can drag a font in the font list, into the editor window to
 use in the text() statement.

I can't readily check a 2025 build at the moment, but as of Oct 2024
the it does exactly as described:  dragging a font from the OpenSCAD
font list into the editor window drops its name in the editor
window.  If that is no longer the case, it's a bug.

In general, don't say things like this.  If the documentation said X,
and you find that X is not true, then one of the following is true:

  • You didn't understand, and X is indeed true.  (And maybe the
    documentation needs to be clearer.)
  • X is false, and it's a bug.  (The bug should be fixed, not the
    documentation.)
  • X is false, and has always been false, and it was always a
    documentation error.  (And the documentation needs to be fixed.)
  • Indeed, X used to be true and is no longer true, and it's an
    intentional change, and nobody updated the documentation.  This
    is a very rare case, because it often means a compatibility
    problem or feature regression.

Regardless, the right answer is to file an issue to get the actual
answer.

In the following sample code a True Type Font, Andika, has been
added to the system fonts using its Font Management service.

We shouldn't talk about adding fonts to the system.  That's not our
problem.

But also, that's not what the sample does.  It adds a font to
OpenSCAD
, and has nothing to do with the platform font mechanisms.

Supported font file formats areTrueType
https://en.wikipedia.org/wiki/TrueTypefonts (.ttf) andOpenType
https://en.wikipedia.org/wiki/OpenTypefonts (
.otf). Once a file
is registered to the project the details of the fonts in it may be
seen in the font list dialog (see image) so that the logical font
names, variations, and their available styles are available for use
in the project.

This says "see image", but doesn't indicate which image.

And:  OpenSCAD doesn't have the notion of "projects" or "registered
to the project".

 3D Text by Extrusion

This is true of all 2D objects and so does not need to be mentioned. 
Delete.

position
a vector [X,Y], the origin of the first glyph, thus the
lower-left corner of the drawn text.

No, it's not the origin of the first glyph, or at least that's a
confusing phrase to use.  A glyph is usually positioned slightly to
the right of the origin, and if it's a descender then it's below the
origin, and some characters (e.g. quotes) are well above the origin. 
A more correct statement would be that it's the lower left corner of
the bounding box of the text.

If one is going to talk about the origin of a glyph, it should be the
point on the baseline to at the left edge of the advance... which
this isn't.

size
a vector [a,b], the size of the generated text.

Should be [x,y].  [a,b] doesn't tell you what "a" and "b" mean.

ascent
positive float, the amount that the text extends above the baseline.

Use the word "number" rather than "float".

It's not always positive; for a glyph entirely below the baseline
(like underscore in Liberation Sans) it's negative. (I'm not sure
that's truly the right definition, but it's the current behavior.)

descent
negative float, the amount that the text extends below the baseline.

Not always negative; for a glyph that is entirely above the baseline
(like apostrophe in Liberation Sans) it's positive. Again, I'm not
sure that's the right definition, but it's the current behavior.

offset
a vector default [0, 0], the lower-left corner of the box
containing the text, including inter-glyph spacing before the
first glyph.

There is no default; this is a value that's returned to you.

This is not the correct definition (and it wasn't correct in the
original that I wrote).  It's the position of the origin of the text,
after adjusting for halign and valign.  For normal LTR text, the X
coordinate is the X coordinate at the left edge of the first glyph's
advance, and the Y component is the Y coordinate of the baseline.

advance
a vector default [153.09, 0], amount of space to leave to any
following text.

There is no default (and certainly not that one!).

The original definition ("the "other end" of the text, the point at
which additional text should be positioned.") wasn't great, but was
more correct.  I would say "The point at which additional text should
be positioned, relative to the text's origin as reported by 'offset'.".

This example displays the text metrics for the default font used by
OpenSCAD:

"text metrics for ... font" is a non sequitur.  Text metrics measure
a particular string.  (And "used by OpenSCAD" is unnecessary; the
entire document is in that context.)

And it's incorrect; the default font is Liberation Sans and this
example uses Liberation Serif.

Better would be:

 This example displays the text metrics for "Hello, World!" for
 Liberation Serif with size=20:

https://en.wikibooks.org/wiki/File:OpenSCAD_textmetrics.pngUsing
textmetrics() to draw a box around text

s="Hello, World!";
size=20;
font="Liberation Serif";

translate([0,0,1])
text("Hello, World!",size=size,font=font);

Should use "s" instead of repeating the string.  (And this is in my
original, sigh.)

displays (formatted for readability):

The original "yields" is better, because it might or might not be
displayed.

ECHO:{
position=[0.7936,-4.2752];
size=[149.306,23.552];
ascent=19.2768;
descent=-4.2752;
offset=[0,0];
advance=[153.09,0];
}

The indentation should match the examples, with the close brace at
the left margin.

   fontmetrics()

size
Decimal, optional. The size of the font, as described above
for|text()|.

Replace "decimal" with "number".

0% developed  as of November 17, 2009
https://en.wikibooks.org/wiki/Help:Development_stages3D to 2D
Projection
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/3D_to_2D_Projection

Using the|projection()|function, you can create 2d drawings from 3d
models,

So far so good.

 and export them to the dxf format.

This part should be deleted.  There are any number of things you
might do with a 2D projection of a 3D object.  Exporting to DXF is
only one.

 It works by projecting a 3D model to the (x,y) plane, with z at 0.
If|cut=true|, only points with z=0 are considered (effectively
cutting the object), with|cut=false|(/the default/), points above
and below the plane are considered as well (creating a proper
projection).

Example: Consider example002.scad, that comes with OpenSCAD.

https://en.wikibooks.org/wiki/File:Openscad_projection_example_2x.png

Then you can do a 'cut' projection, which gives you the 'slice' of
the x-y plane with z=0.

Doing the non-default case as the first example seems wrong; I would
swap the two examples.

Another Example

You can also use projection to get a 'side view' of an object.

This example seems unnecessary for a reference manual.  It's a
straightforward combination of the features described.

Links:

Seems inappropriate for a reference manual.  Also, doesn't seem more
complicated at all.

0% developed  as of November 17, 2009
https://en.wikibooks.org/wiki/Help:Development_stages2D to 3D
Extrusion
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/2D_to_3D_Extrusion

Extrusion https://en.wikipedia.org/wiki/Extrusionis the process of
creating an object with a fixed cross-sectional profile. OpenSCAD
provides two commands

"Commands" isn't the right word.  "Modules" is more correct, but
"operations" is probably best.

Both extrusion methods work on a (possibly disjointed) 2D shape
normally drawn in the relevant plane (see below).

The old description of the behavior of extrusion for 2D objects that
have been moved off the Z=0 plane is an example of something that
should never have been documented.  It's not a particularly useful
behavior, and we might eventually want a different behavior.  At
most, it should have said "don't do that".

It should probably say "drawn on the Z=0 plane".

This child object is first projected onto the X-Y plane along the Z
axis to create the starting face of the extrusion.

Delete.  We shouldn't document that behavior.

The start face is duplicated at the Z position given by the height
parameter to create the extrusion's end face. The extrusion is then
formed by creating a surface that joins each point along the edges
of the two faces.

That's a seriously incomplete description, because it's only true
with all of the parameters at their defaults.

Or, in other words, the 2D shape may be ... a 2D shape.

Delete the whole sentence.

The 2D shape may have a Z value that moves it out of the X-Y plane,
and it may even be rotated out of parallel with it. As stated above,
the extrusion's starting face is the projection of the 2D shape onto
the X-Y plane, which, if it is rotated, will have the effect of
fore-shortening it normal to the axis of the rotation.

Delete.

Using a 3D object as the extrusion's child will cause a compile time
error.

Factually incorrect.  It's not a compile-time error; it's a run-time
error.

Also, we just said that the child must be a 2D shape.  Exact behavior
when that requirement is violated need not be (and probably should
not be) specified.

Delete.

Including a 3D object in a composition of 2D objects (formed using
boolean combinations on them) will be detected, the 3D object(s)
will be deleted from it and the remaining 2D objects will be the
basis for projecting their shape onto the X-Y plane.

We need not (and generally should not) specify the behavior in error
conditions.  Delete.

 Parameters For Linear Extrusion

There are no required parameters. The default operation is to
extrude the child by 100 units vertically from the X-Y Plane,
centered on the [0,0] origin.

"centered" is at best meaningless (because it's extruded wherever the
child is, without respect to the origin) and at worst incorrect
(because the default is to extrude into +Z, not to center in Z).
Delete that last phrase.

  1. height
    a non-negative integer, default 100, giving the length of the
    extrusion

Doesn't have to be an integer.

I don't know how strong a pattern we have for specifying parameters,
but they shouldn't be numbered.  (Except maybe if they are usable as
positional parameters - which don't match these numbers.)

  1. v - twist axis vector
    a vector of 3 signed decimal values, default [0,0,1], used as an
    eigen vector specifying the axis of rotation for the
    twist.[Note:Requires versionDevelopment snapshot]

I can't say that I truly understand eigenvectors, but I don't think
this is one.  The "signed" part is unnecessary, because all numbers
are signed, and the "decimal" part is meaningless because abstract
numbers have no base.

"v" is a vector of three numbers that controls the vector along which
the extrusion is done.

It has an interesting interaction with "height".  If both are
specified, height is used as the length of the extrusion, along the
direction that v points, and v's magnitude is ignored.  If only v is
specified, it is used to control both the direction and length of the
extrusion.

Saying that it's the axis of rotation for twist is sort of right, but
maybe needs more explanation.  Normally when you think of an axis of
rotation, you're rotating along the plane perpendicular to that
axis.  Here, though, it is perhaps more correct to say that it
controls the origin of the rotation. At each slice, the 2D shape is
rotated around Z, with the origin being the XY position of the
extrusion vector.

  1. center
    a boolean, default false, that, when true, causes the resulting
    solid to be vertically centered at the X-Y plane.

"at the Z=0 plane" would be a bit more obvious.

  1. convexity
    a non-negative integer, default 1, giving a measure of the
    complexity of the generated surface. See the Section on
    Convexity later on this page.

Should include a link... which should not be pointing at this page,
no matter which page we're talking about.

  1. twist
    a signed decimal,

a number

  180 degrees is a half twist, 360 is all the way around, and so on.

Unnecessary, delete.

  1. scale
    either : a non-negative, decimal value,

a non-negative number

 minimum 0.0,

Implied by "non-negative", delete.

  that specifies the factor by which the end face should be
 scaled up, or down, in size from that of the start face.

All scaling is either up or down.  Just "should be scaled".

 or : an [x,y] vector that scales the extrusion in the X and Y
 directions separately.

Delete the colon.

  1. slices
    a non-negative integer for the number of rows of polygons that
    the extr.

Needs help.

h
a named parameter, synonym to height

Just list it in the same block as height.

$fn $fs $fa
Special Parameters - given as named parameters.

They have standard special-variable semantics, which means they can
be specified in the context or in the call.  They should be
mentioned, but perhaps not as parameters per se.  I believe they only
affect twisted extrusions, so maybe they should be mentioned there.

   Center

This parameter affects only affects the vertical position or the
extrusion. Its X-Y position is always that of the projection that
sets its starting face.

"or" should be "of".

This is a nice comment, but doesn't say what the parameter does.

"When true, the extrusion is centered vertically around Z=0." seems
adequate to me, without any further comment, but a subsequent comment
about not affecting X and Y would be OK.

   Scale

This is multiplicative factor that affects the size of extrusion's
end face. As such 1.0 means no change, a value greater than one
expands the end face, and a value between 0.001 and less than 1
shrinks it.

"As such" is unnecessary.

I don't know where 0.001 came from.  I would say "a value less than 1
shrinks it".

 A value of 0.0 causes the end face to degenerate to a point,
turning the extrusion into a pyramid, cone, or complex pointy shape
according to what the starting shape is.

I'd say this is unnecessary.

Using the vector form sets the scale factor in the X and Y
directions separately

   Twist

Twist is applied, by default, as a rotation about the Z Axis.

As discussed above, twist is always around Z.  What v controls is the
origin of that rotation.

When the start face is at the origin a twist creates a spiral out of
any corners in the child shape. If the start face is translated away
from the origin the twist creates a spring shape.

I don't know if it's truly useful to try to describe the various
shapes that can result from twisting.

One thing that might be worth explicitly mentioning is that you can't
practically use linear_extrude to generate threads. You can come
temptingly close, but they won't be shaped right.  (It is actually
possible to get right, but requires an unobvious base shape.)

A positive twist rotates clockwise, negative twist the opposite.

Huh.  I basically never use twist, so I never noticed that it's
backwards from rotate.  That seems very wrong... and it's way too
late to fix it.  It might be worth mentioning this difference.

   Twist Axis Vector

The second parameter is an [x,y,z] eigen vector that specifies the
axis of rotation of the applied twist.

Suggest referring to it by name instead of by position.

 The ratios of the three dimensional values to their respective
coordinate axes specify the tilt away from the default axis,
[0,0,1], the Z-Axis. For instance, v=[cos(45),0,1] tilts the
extrusion at 45 degrees to the X axis.

It's actually a skew rather than a tilt.

The start and end faces are always normal to the Z-axis, even when
the twist axis is tilted. The extruded and twisted surfaces are thus
distorted from what might be expected in an extruded shape. The more
expected result may be achieved by applying a rotation to then
twisted extrusion on the Z Axis to tilt it into the desired position.

It's best not to make assumptions about what the user expects. 
Describe the operation, and describe it carefully. Do not describe
how to do things that are straightforward combinations of operations.


Note that the documentation does not discuss which happens first: 
twist or scale.  I don't believe it matters when using the same
scaling for X and Y, but matters a great deal with using different
scaling on the two axes.  It twists and then scales, which can mean
(for instance) that a shape that started out rectangular turns into a
parallelogram.  There's an argument that this is not the useful
behavior, and that scale-and-then-twist is more useful since it
retains the general shape throughout the extrusion.  I've started a
discussion a few times about maybe changing this, but I don't think
it ever came to a conclusion.  It might be best not to document this
without that conclusion.

   $fn, $fa, $fs Special Parameters

The special variables must be given as named parameters and are
applied to the extrusion, overriding the global setting. When the
same special variables are set on the base shape its values override
their use as parameters on the extrusion.

None of this is really accurate.

The special variables have standard special-variable behavior, which
means that you can specify them in the context or in the particular
call, and they apply to that context (including a specific call) and
everything that that is called from that context.  There is no
"global setting" that is special.

What matters for the linear_extrude (and in particular for twisted
extrusions) is the setting that it sees.

If the child 2D shape also uses these variables, what matters for
it is what it sees... which, absent an inner setting, will be the
same as what linear_extrude sees.

Thus, either:

 linear_extrude(height=10, twist=20, $fn=100) circle(10);

or

 $fn=100; linear_extrude(height=10, twist=20) circle(10);

will yield a high-resolution twist of a high-resolution circle.

On the other hand, either

 linear_extrude(height=10, twist=20, $fn=100) circle(10, $fn=3);

or

 $fn=100; linear_extrude(height=10, twist=20) circle(10, $fn=3);

will yield a high-resolution twist of a low-resolution circle - a
triangle.

   Extrusion From Imported DXF

Does not need to be discussed.  You can linear_extrude any 2D shape,
and an import of a DXF yields a 2D shape.

     A Unit Circle with No Twist

I don't think all of these examples are necessary.

Generate an extrusion from a circle 2 units along the X Axis from
the origin,

unit circle

centered vertically on the X-Y plane, with no twist. The extrusion
appears to have a pentagonal cross-section because the extrusion's
child is a 2D circle with the default value for $fn.

It doesn't appear to have a pentagonal cross-section.  It does
have a pentagonal cross-section.

The same circle, but made into a spiral by 500 degrees of
counter-clockwise twist.

If you look carefully, this example demonstrates why you can't make
threads.  As you twist it more, it becomes thinner and thinner in Z. 
The problem is that the cross-section of a thread is a strange shape.

     Mesh Refinement

The slices parameter defines the number of intermediate points along
the Z axis of the extrusion.

I am not sure of the exactly right way to describe this, because of
fence post errors.

"slices" controls the number of 3D "chunks" that make up the
extrusion.  The total number of instances of the original 2D object
is slices+1.

Its default increases with the value of twist.

It's some function of that and $fa/$fs/$fn.  I don't know what the
function is or exactly how to describe it.

Additional the segments parameter

Addition -> Additionally

Segments need to be a multiple of the polygon's fragments to have an
effect (6 or 9.. for a circle($fn=3), 8,12.. for a square() ).

I don't know what the actual behavior is, but that's not it. For more
complex shapes (I experimented with a right triangle) intermediate
values do have an effect.

Thespecial variables
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Other_Language_Features$fn,
$fs and $fa can also be used to improve the output. If slices is not
defined, its value is taken from the defined $fn value.

Again, I don't know what the behavior is, but that's not it.
Increasing $fn does increase the number of slices, but it isn't
simply used as the number of slices.

$fa/$fs/$fn seem to control both slices and segments.

   Using with imported SVG

Does not need to be separately discussed.

 rotate_extrude() Operator Module

Rotational extrusion spins a 2D shape around the Z-axis to form a
solid which has rotational symmetry. One way to think of this
operation is to imagine a Potter's wheel placed on the X-Y plane
with its axis of rotation pointing up towards +Z. Then place the
to-be-made object on this virtual Potter's wheel (possibly extending
down below the X-Y plane towards -Z). The to-be-made object is the
cross-section of the object on the X-Y plane (keeping only the right
half, X >= 0). That is the 2D shape that will be fed to
rotate_extrude() as the child in order to generate this solid. Note
that the object started on the X-Y plane but is tilted up (rotated
+90 degrees about the X-axis) to extrude.

I'm not sure that this is the best possible explanation.

Since a 2D shape is rendered by OpenSCAD on the X-Y plane, an
alternative way to think of this operation is as follows: spins a 2D
shape around the Y-axis to form a solid. The resultant solid is
placed so that its axis of rotation lies along the Z-axis.

That's the way that I always think of it, though I mentally rotate it
to vertical before spinning it.

Just like the linear_extrude, the extrusion is always performed on
the projection of the 2D polygon to the XY plane.

Again, we should not document this behavior.

Transformations like rotate, translate, etc. applied to the 2D
polygon before extrusion modify the projection of the 2D polygon to
the XY plane and therefore also modify the appearance of the final
3D object.

  • A translation in Z of the 2D polygon has no effect on the result
    (as also the projection is not affected).
  • A translation in X increases the diameter of the final object.
  • A translation in Y results in a shift of the final object in Z
    direction.
  • A rotation about the X or Y axis distorts the cross section of
    the final object, as also the projection to the XY plane is
    distorted.

This is perhaps good stuff, if the part about projecting is removed.

Don't get confused, as OpenSCAD displays 2D polygons with a certain
height in the Z direction, so the 2D object (with its height)
appears to have a bigger projection to the XY plane. But for the
projection to the XY plane and also for the later extrusion only the
base polygon without height is used.

Once you get rid of the part about projecting this goes away too.

You cannot use rotate_extrude to produce a helix or screw thread.
Doing this properly can be difficult, so it's best to find a thread
library to make them for you.

This kind of comment can be valuable, but I'm not sure it belongs in
a reference manual.  If it is in a reference manual, it should be
in a clear and separate section (of the description of the particular
feature) marked "Application Notes" or something like that, to make
it clear that it's not part of the description of the feature.

If the shape spans the X axis a warning appears in the console
windows and the rotate_extrude() is ignored.

Don't talk about what window something appears in, because not
everybody uses the OpenSCAD GUI.

Don't talk about what happens "after" the error.

Just say that it's an error, period.

(And, BTW, this particular one is something that I think should not
be an error; I think that the result should be as if you split the 2D
shape in half, rotationally extruded both, and unioned them.  That
is, take the shape, sweep it 360 degrees, and anything it sweeps
through (whether once or twice) is part of the result.)

 If the 2D shape touches the Y axis, i.e. at x=0, itmustbe a line
that touches, not a point, as a point results in a zero thickness 3D
object, which is invalid and results in a CGAL error.

This may have been addressed with Manifold.

 *convexity* : If the extrusion fails for a non-trival 2D shape,
 try setting the convexity parameter (the default is not 10, but
 10 is a "good" value to try). See explanation further down.

Just point at the general discussion of convexity.  (Which should not
be on this page.)

And the extrusion does not "fail".  In fact, the artifacts may be
quite subtle.

 *start*[Note:Requires versionDevelopment snapshot] : Defaults to
 0 if*angle*is specified, and 180 if not. Specifies the starting
 angle of the extrusion, counter-clockwise from the positive X axis.

start was part of an effort to align rotational extrusion behavior
with the behavior of other round things.  I don't remember all of the
details, but there are few reasons why it isn't equivalent to
rotating the result.

 *$fa* : minimum angle (in degrees) of each fragment.
 *$fs* : minimum circumferential length of each fragment.
 *$fn* :*fixed*number of fragments in 360 degrees. Values of 3 or
 more override $fa and $fs

     $fa, $fs and $fn must be named parameters.click here for
     more details,
     <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Other_Language_Features>.

Do not describe these in detail here.  Refer to a general description
of them elsewhere.

Do not ever, ever, say "click here".  Any text that would not make
sense when printed is wrong.

   Rotate Extrude on Imported DXF

Delete.

Increasing the number of fragments composing the 2D shape improves
the quality of the mesh, but takes longer to render.

Unnecessary.

rotate_extrude(convexity = 10)
translate([2, 0, 0])
circle(r = 1, $fn = 100);

This example is unnecessary; this is a description of rotate_extrude,
not circle()

The number of fragments used by the extrusion can also be increased.

rotate_extrude(convexity = 10, $fn = 100)
translate([2, 0, 0])
circle(r = 1, $fn = 100);

Use $fs and $fa here.  In fact, supply them at the top level.  And
this case doesn't require specifying convexity (though I'm not sure
why not).  Also, for circles this small high resolution is not
practical; make them bigger to make the example more real. Thus:

 $fa = 1;
 $fs = 1;
 rotate_extrude()
      translate([20, 0, 0])
          circle(r = 10);

That's really the best practice.  You almost never want to use $fn if
your intent is to create a circle.

(Minor exception that is itself something of a bug:  if you're trying
to force the number of sides to be a multiple of 4.  But that
shouldn't be discussed here.)

Using the parameter angle (with OpenSCAD versions 2016.xx), a hook
can be modeled .

https://en.wikibooks.org/wiki/File:Hook.pngOpenSCAD - a hook

eps = 0.01;
translate([eps, 60, 0])
rotate_extrude(angle=270, convexity=10)
translate([40, 0]) circle(10);
rotate_extrude(angle=90, convexity=10)
translate([20, 0]) circle(10);
translate([20, eps, 0])
rotate([90, 0, 0]) cylinder(r=10, h=80+eps);

Delete.

     Extruding a Polygon

Delete.

   Description of extrude parameters

Why are we repeating these here?  Don't, especially because there is
little commonality between linear_extrude and rotate_extrude.

 0% developed  as of November 17, 2009
 <https://en.wikibooks.org/wiki/Help:Development_stages>DXF
 Extrusion
 <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/DXF_Extrusion>

Delete.

This should get more content.  At the current state of things it can
probably all go on the 2D page, but if it gets much more complex it
might want its own page with a brief summary and reference here.


OpenSCAD mailing list
To unsubscribe send an email todiscuss-leave@lists.openscad.org


OpenSCAD mailing list
To unsubscribe send an email todiscuss-leave@lists.openscad.org

If it ain't broke, work on until it is.😉 The attraction of openscad is it's relatively small set of functions. I've done everything I need with raw openscad (with the help from a few folk on here). Bosl2 is there for those who want an easier answer. It seems that some folk are wanting it to do things that were never designed into openscad functionality. For those folk, learn fusion, blender, whatever. The terminology in parts is a tad incorrect, cubes are more than squares, cylinders are more than cylinders, and you will never see a true circle on any digital display. Also, the language is initially awkward, and the solids can often have unwanted holes, but if you spend the time and effort you get used to it. My comment is related to openscad as a whole, not specific to 2d, but as nothing in the real world is 2d... Best wishes, Ray On 08/08/2025 12:36, Jon Bondy via Discuss wrote: > > What is the community getting for this INCREDIBLE level of effort? > > I think we should > > 1) revert the documentation back to prior to when Vulcan started > changing things > > 2) make a list of problems with the documentation (an explicit, > reviewable requirements list from which we can make controlled changes > to the documentation) > > 3) make small, localized changes that can be validated with minimal > effort. > > 4) perhaps this should be controlled in a manner similar to the > development of the software itself, with a GIT-like system of problem > descriptions and resolutions. > > The people who really contribute to OpenSCAD are few, perhaps less > than half a dozen.  To force them to spend their time working on a > project THAT DOES NOT NEED TO BE DONE, and is not going well, will > slow down development and bug fixes that DO need to be done. > > It is clear to me that having an OpenSCAD novice working on the > documentation is not a great idea.   Good intentions but bad results. > > Vulcan: if you REALLY want to help this community, use OpenSCAD > actively (every day) for a year, making complex designs, and then come > back. > > Is there anyone (or any group) that is in control of the documentation > Wiki?  If not, we need such an entity.  If so, someone needs to take > control of this project. > > Again, if I'm wrong, I apologize.  But I have been getting private > messages agreeing with me. > > Jon > > > On 8/8/2025 4:08 AM, Jordan Brown via Discuss wrote: >> >> [ I'll spend the effort to fix up this laptop configuration, again, >> sorry for the duplicates. ] >> >> >>> Two Dimensional Modelling >>> >>> >>> 0% developed  as of November 17, 2009 >>> <https://en.wikibooks.org/wiki/Help:Development_stages>2D >>> Primitives >>> <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/2D_Primitives> >>> >>> All 2D primitives can be transformed with 3D transformations. >>> >> >> Really bad place to start.  Yes, you can transform them with 3D >> transforms, but if you do then the results can be weird. It should be >> discouraged; you should almost always work with 2D transforms when >> working with a 2D subassembly. >> >> Also, maybe we should talk about the primitives before we talk about >> what you can do with them. >> >> >>>  They are usually used as part of a 3D extrusion. >>> >> >> Yeah, eventually.  But again this doesn't seem appropriate for a "2D >> primitives" section.  Maybe for an overview section *above* that. >> >> >>>  Although they are infinitely thin, they are rendered with a 1-unit >>> thickness. >>> >> >> Again, maybe in an overview section. >> >> >>> *Note*: Trying to subtract with|difference()|from 3D object will >>> lead to unexpected results in final rendering. >>> >> >> The real rule is "don't mix 2D objects with 3D objects and 3D >> operations".  It isn't necessary or appropriate to say very much >> about what will happen if you do.  Some cases will yield errors, >> while others will do something weird.  We don't want the >> documentation to nail down any particular behavior, because there are >> reasons that we might want to change the behavior in these cases. >> >> Ref, e.g., OEP 7 "Mixed Dimension Geometry Support" >> <https://github.com/openscad/openscad/wiki/OEP7%3A-Mixed-Dimension-Geometry-Support>. >> >> >>> Square Object Module >>> >>> By default this module draws a unit square in the first quadrant, >>> (+X,+Y), starting at the origin [0,0]. Its four lines have no >>> thickness but the shape is drawn as a 1 unit high, filled plane. >>> >> >> The second sentence should probably just go away: >> >> * The first part "its four lines have no thickness" is both >> misleading - the lines have no independent existence - and >> incorrect; when rendered they *do* have thickness. >> * The second half (drawn as 1 unit high) restates something already >> said in above. >> >> >>> The module's arguments may be written in the order|<size>, >>> center=<bool>|without being named, but the names may be used as >>> shown in the examples: >>> >> >> There needs to be (but probably isn't) enough documentation >> convention that this need not be said. >> >> >>> *Parameters* >>> >>> size >>> has two forms:/single value/or/vector/ >>> single - non-negative float, length of all four sides >>> >> Should use the word "number" rather than the word "float". OpenSCAD >> does not have distinct floating point and integer types; it has only >> numbers. >> >> >>> center >>> boolean, default false, to set the shape's position in the X-Y plane >>> >>> *Center*When|false|, as it is by default, the shape will be drawn >>> from its first point at (0,0) in the First Quadrant, (+X,+Y). With >>> center set to|true|the shape is drawn centered on the origin. >>> >> >> These two paragraphs should be merged. >> >> >>> Circle Object Module >>> >>> By default this module draws a unit circle centered on the origin >>> [0,0] as a pentagon with its starting point on the X-axis at X=1. >>> Its lines have no thickness but the shape is drawn as a 1 unit high, >>> filled plane. >>> >> The part of the first sentence starting "as a pentagon ..." should go >> away.  It's true, but it really belongs as part of the description of >> $fa/$fs. >> >> Again, the second sentence should just go away. >> >> Somewhere it should say "Circles are approximated as regular >> polygons; see <reference to $fa/$fs/$fn> for the details of the >> polygons generated." >> >> >>> The argument|radius|may be given without being named, but >>> the|r|and|d|arguments must be named. >>> >> There is no "radius" argument.  There are r and d. >> >> Again, we should have a documentation convention so that we don't >> have to repeat positional/named rules, but the behavior here is that >> r can be supplied as the first argument, but d must be named. >> >> (Technically, if you say "circle(undef, 10)" the 10 is the second  it >> creates a 10-unit-diameter circle.  I would say that the fact that >> this works is a minor bug.) >> >> >>> $fa >>> Special Variable >>> $fs >>> Special Variable >>> $fn >>> Special Variable >>> >> Theses should be described only to the extent of pointing at the >> general description of $fa/$fs/$fn. >> >>> The default circle displays as a pentagram as that is the minimum >>> number of fragments used to approximate a curved shape calculated >>> from the default values for $fs and $fa. To have it draw as a smooth >>> shape increase the $fn value, the minimum number of fragments to >>> draw, to 20 or more (best $fn < 128). >>> >> This is just bad.  First, everything here should be covered in the >> description of $fa/$fs/$fn.  Second, using $fn to control the >> resolution of a circle is generally the wrong answer; you are better >> off setting $fa and $fs.  Finally, specific advice on $fn values is a >> bad idea, because the "looks smooth" value varies dramatically with >> size.  A 20-gon is okay for a medium-small circle; a 72-gon is not >> good enough for a 100-unit circle. >> >>> An alternative method to draw a very smooth circle scale is to scale >>> down a very large circle. >>> >>> scale( 0.001 ) circle(200); >> >> This should just go away; it confuses the issue. >> >> >>> Another way to solve the lack of a built-in module for regular >>> polygons is to write a custom one:module regular_polygon() >>> <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/example_module_regular_polygon()> >>> >> I wouldn't include this.  Using polygon() is harder than using >> circle(), and anybody who's capable of using it should have little >> trouble simulating circle(). >> >> >>> convexity >>> Integer, default=1 - complex edge geometry may require a higher >>> value value to preview correctly. >>> >> >> Should include a link to a general discussion of convexity. Probably >> should not even mention the default; that should be covered in the >> general discussion. >> >> >>> *Points Parameter*A list of X-Y coordinates in this form: >>> >>> [[1, 1], [1, 4], [3, 4], [3, 1], [1, 1]] >>> >>> which defines four points and makes it explicit that the last one is >>> the same as the first. >>> >>> Including the first point twice is not strictly necessary as this: >>> >>> [[1, 1], [1, 4], [3, 4], [3, 1]] >>> >>> gives the same result. >>> >> >> This seems like it should be simplified.  In the absence of a paths >> parameter, the last point always connects to the first, because >> polygons are always closed. >> >> >>> *Paths Parameter* >>> >>> This optional parameter is a nested vector of paths. >>> >>> A "path" is a list of index values that reference points in >>> the|points|vector. It can explicitly describe a closed loop by its >>> last index being the same as its first, as in: >>> >>> [1, 2, 3, 4, 1] >>> >>> but this is equivalent to: >>> >>> [1, 2, 3, 4] >> >> >> Again, this seems like unnecessary complexity; the last point always >> connects to the first. >> >> >>> Notice that the points vector is simple list, >>> >> No, it's a list of lists. >> >>>  while each path is a separate vector. >>> >> Yes... points and paths are the same order. They are both lists of lists. >> >>>  This means that paths, that are lists of references to points, have >>> to "know" which points it needs to include. >>> >> While it's true that paths need to "know" the indexes they connect, I >> don't see how that follows from the previous sentences. >> >>>  This can be an issue if the polygon is assembled from a number of >>> shapes at run time as the order of adding shapes affects their >>> point's index values. >>> >> It's true that this is something that you must handle, but I don't >> think that a reference manual needs to discuss it. >> >> >>>  .*Convexity* >>> >> >> Formatting error:  this title is merged with the previous paragraph. >> (But should be deleted, see below.) >> >> >>> Shapes with a lot of detail in their edges may need the convexity >>> parameter increased to preview correctly. See Convexity >>> >> Already discussed, should be deleted. >> >>> *Example With Multiple Holes* >>> >>> [Note:Requires version2015.03] (for use of|concat()|) >>> >>> <https://en.wikibooks.org/wiki/File:OpenSCAD_romboid_with_holes.jpg> >>> >>> We are using "a" for the point lists and "b" for their paths: >>> >>> a0 = [[0,0],[100,0],[130,50],[30,50]]; // outer boundary >>> b0 = [1,0,3,2]; >>> a1 = [[20,20],[40,20],[30,30]]; // hole 1 >>> b1 = [4,5,6]; >>> a2 = [[50,20],[60,20],[40,30]]; // hole 2 >>> b2 = [7,8,9]; >>> a3 = [[65,10],[80,10],[80,40],[65,40]]; // hole 3 >>> b3 = [10,11,12,13]; >>> a4 = [[98,10],[115,40],[85,40],[85,10]]; // hole 4 >>> b4 = [14,15,16,17]; >>> a = concat( a0,a1,a2,a3,a4 ); // merge all points into "a" >>> b = [b0,b1,b2,b3,b4]; // place all paths into a vector >>> polygon(a,b); >>> //alternate >>> polygon(a,[b0,b1,b2,b3,b4]); >> >> >> The "alternate" at the end of the example seems unnecessary - of >> course you can use either a particular expression or a variable that >> has been set to that expression. >> >> >>> *2D to 3D by Extrusion* >>> >>> A polygon may be the basis for an extrusion, just as any of the 2D >>> primitives can. Thisexample script >>> <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/example_module_2D_to_3D_extrusion>may >>> be used to draw the shape in this image: >>> >> >> Yes, a polygon can be used as the basis for extrusion, just as any of >> the 2D primitives can.  That means that you do *not* need a specific >> example of that case. >> >> >>> Import a 2D Shape From a DXF >>> >>> [Deprecated:import_dxf() will be removed in a future release. Use >>> Useimport() Object Module >>> <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/The_OpenSCAD_Language#import>instead. >>> instead*]* >>> >> As a deprecated feature, this should be pushed to the bottom. >> >>> Read a DXF file and create a 2D shape. >>> >>> *Example* >>> >>> linear_extrude(height = 5, center = true) >>> import_dxf(file = "example009.dxf", layer = "plate"); >>> >>> *Example with Import()* >>> >>> linear_extrude(height = 5, center = true) >>> import(file = "example009.dxf", layer = "plate"); >> >> >> The second should perhaps be titled "Replacement example with >> import()".  Note also that since OpenSCAD is case sensitive the word >> "import" should not be capitalized. >> >> >>> 0% developed  as of November 17, 2009 >>> <https://en.wikibooks.org/wiki/Help:Development_stages>Text >>> <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Text> >>> >> Text is a big enough topic that it should probably have its own page, >> with just a brief mention and cross-reference here. >> >> I see that it *has* its own page and is transcluded here.  It should >> not be transcluded, because that makes it harder to just read everything. >> >>> >>> Text in OpenSCAD >>> >>> Being able to use text objects as a part of a model is valuable in a >>> lot of design solutions. >>> >> Delete this sentence.  This is reference material, not sales >> material.  The user already knows whether or not it's valuable to them. >> >> >>> The fontsavailable to use in a script >>> <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Text#Fonts_in_OpenSCAD>are >>> from the system that OpenSCAD is running in with the addition of >>> those explicitly added by the script itself. >>> >> >> And OpenSCAD includes several.  (And this duplicates a more extensive >> discussion below.) >> >> >>> text() Object Module >>> >>> The|text()|object module draws a single string of text as a 2D >>> geometric object, using fonts installed on the local system or >>> provided as separate font file. >>> >> provided as +a+ separate font file >> >> >>> The shape starts at the origin and is drawn along the positive X axis. >>> >> >> By default, ... >> >> (because halign and valign change things) >> >> >>> text >>> String. A single line ofany character allowed >>> <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Characters_Strings#Characters>.*Limitation:*non-printable >>> ASCII characters like newline and tab rendered as placeholders >>> >> Delete the second sentence.  If it's a string, it's allowed. As for >> being a single line and treatment of non-printable characters, need >> to phrase that as a current restriction, not as a permanent behavior >> - it would be good if we could eventually provide more support there, >> and we wouldn't want to be prevented from adding that support by >> compatibility concerns.  Ref >> https://github.com/openscad/openscad/issues/5018 for the desire for >> multi-line text. >> >>> font >>> aformatted string >>> <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Text#Parameters>with >>> default font of "Liberation Sans:style=Regular" >>> >> >> "formatted string" is a poor phrase there.  Better would be something >> like "String.  A font specification with ...". >> >> Also I see that this is a link over to a separate Text page. A >> separate Text page is good, as discussed above, but it shouldn't be >> duplicated here. >> >> >>> size >>> non-negative decimal, default=10. The generated text has a >>> height above the baseline of approximately this value, varying >>> for different fonts but typically being slightly smaller. >>> >> The "decimal" part should be "number".  (It isn't even sensible to >> talk about a base.) >> >> I don't feel the need for the "non-negative" part.  (It should >> probably also be non-zero.)  Unless we have a special meaning for a >> negative size, we should be able to let people figure out for >> themselves that if they make a silly request they will get a silly >> answer. >> >> Current behavior is ... interesting... though when you think about it >> unsurprising:  the text is mirrored in X and Y, leading to it being >> effectively rotated 180 degrees.  Unless we really want to keep that >> behavior, we should probably make it be an error instead.  Until and >> unless we decide that we want to keep that behavior, we should *not* >> document it. >> >> There needs to be a footnote about size.  Because of an arithmetic >> error in the implementation (issue #4304 >> <https://github.com/openscad/openscad/issues/4304>), the "size" >> parameter does not correspond to a typical font size specification.  >> It is a coincidence that the arithmetic error approximately cancels >> out the usual ratio between the specified font size and the size of a >> capital letter, making "size" approximately specify the size of a >> capital letter in a typical Western font.  However, since the result >> *is* useful, and the error has been in place since the beginning, we >> really can't fix it.  Maybe at some point we can introduce an >> alternative parameter that specifies a more conventional font size, >> eg PR#4306 <https://github.com/openscad/openscad/pull/4306>. >> >> >>> spacing >>> float, default=1. Multiplicative factor that increases or >>> decreases spacing between characters. >>> >> "float" should be "number". >> >>> language >>> String. The language of the text (e.g., "en", "ar", "ch"). >>> Default is "en". >>> script >>> String, default="latin". The script of the text (e.g. "latin", >>> "arabic", "hani"). >>> >> >> Somebody needs to figure out what these actually do. >> >> >>> $fn >>> higher values generate smoother curves (refer toSpecial >>> Variables >>> <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Other_Language_Features#special_variables>) >>> >> >> This should refer to $fa, $fs, and $fn... and really you shouldn't be >> using $fn here. >> >> >>> Font & Style Parameter >>> >>> The "name" of a font is a string starting with its|logical font >>> name|and|variation|, >>> >> I don't see variation as a separate part of the specification. >> >> Also, use of the "typewriter" font here is inappropriate; neither of >> these is a language keyword or language component. Either use plain >> text or perhaps italics. >> >> >>>  optionally followed by a colon (":") separated list of font >>> specifications like a|style|selection, and a set of zero or >>> more|features|. >>> >> >> We should include a list of the name=value specifications supported, >> or refer to external (fontconfig?) documentation. >> >> Again, "features" is not a keyword and should not be in typewriter font. >> >> >>> The common variations in a font family are|sans|and|serif|though >>> many others will be seen in the list of fonts available. Each font >>> variation can be drawn with a/style/to support textual emphasis. >>> >> >> I think those are part of the font name, and that there they are >> usually capitalized.  I'm a bit torn on whether they should be in >> typewriter font. >> >> >>> The default, upright appearance is usually called "Regular" with >>> "Bold", "Italic", and "Bold Italic" being the other three styles >>> commonly included in a font. In general the styles offered by a font >>> may only be known by using the platform's font configuration tools >>> or theOpenSCAD font list dialog >>> <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Text#Fonts_in_Openscad>. >>> >> >> This should explicitly tie to the "style=" parameter. >> >> >>> The fontfeatures property is appended to the|font name|after the >>> >> >> "fontfeatures" should be in typewriter font because it is a keyword. >> >> "font name" should not be in typewriter font because it is *not* a >> keyword. >> >> >>> optional style parameter. Its value is a semi-colon separated list >>> of feature codes, each prefixed by a plus, "+", to indicate that it >>> is being added, >>> >> >> Should end with a colon, not a comma. >> >> >>> font = "Linux Libertine G:style=Regular:fontfeatures=+smcp;+onum"); >>> >>> *Size Parameter* >>> >>> Text size is normally given in points, and a point is 1/72 of an >>> inch high. The formula to convert the*size*value to "points" is|pt = >>> size/3.937|, so a*size*argument of 3.05 is about 12 points. >>> >> >> This is incorrect, because OpenSCAD is unitless.  "size" specifies >> some dimension of the font, in OpenSCAD units.  See the discussion >> above about exactly what dimension it measures. (OpenSCAD units are >> *typically* interpreted as millimeters, but that's up to the user and >> the consuming program; it is not part of OpenSCAD's definitions.) >> >> There should be no reference to "points" except perhaps to *disclaim* >> that anything is measured in points. >> >>> *Note*: Character size the distance from ascent to descent, not from >>> ascent to baseline. >>> >> Ref the arithmetic error mentioned above and the long discussion in >> issue #4304, this is incorrect.  "size" *should have* measured >> approximately the font ascent plus descent, but instead measures >> (even more approximately) the font ascent. >> >>> One of these four names must be given as a string to >>> the|valign|parameter. >>> >> Since the valign parameter itself is optional, the word "must" seems >> inappropriate.  Perhaps "The valign parameter may be set to one of >> these four words". >> >>> top >>> The text is aligned so the top of the tallest character in your >>> text is at the given Y coordinate. >>> >> >> There is no "given Y coordinate".  The top of the tallest character >> in your text is at the X axis, Y=0. >> >>> center >>> The text is aligned with the center of the bounding box at the >>> given Y coordinate. >>> >> >> Again, at Y=0. >> >> >>> baseline >>> The text is aligned with the font baseline at the given Y >>> coordinate. >>> >> Again, at Y=0. >>> >>> bottom >>> The text is aligned so the bottom of the lowest-reaching >>> character in your text is at the given Y coordinate. >>> >> >> Again, at Y=0. >> >> >>> *Note*: only the "baseline" vertical alignment option will ensure >>> correct alignment of texts that use mix of fonts and sizes. >>> >> This overlaps a lot with the last sentence of the definition of >> "baseline" and should probably be merged with it. >> >>> One of these three names must be given as a string to >>> the|halign|parameter. >>> >> >> Again, the word "must" seems inappropriate. >> >> >>> left >>> The text is aligned with the left side of the bounding box at >>> the given X coordinate. >>> center >>> The text is aligned with the center of the bounding box at the >>> given X coordinate. >>> right >>> The text is aligned with the right of the bounding box at the >>> given X coordinate. >>> >> >> None of these are correct.  The alignment is based on spacing, not on >> the bounding box.  For most letters, "left" will position the ink >> slightly to the right of X=0.  (For a size=10 M in Liberation Sans, >> it's about 1.1 units right of X=0.)  I'd need to do more research to >> figure out the exactly correct wording. >> >> And for all of them, there is no "given [XY] coordinate". Positioning >> is relative to the origin. >> >>> *Spacing Parameter* >>> >>> Characters in a text element have the size dictated by their glyph >>> in the font being used. As such their size in X and Y is fixed. Each >>> glyph also has fixed|advance|values (it is a vector [a,b], >>> seetextmetrics >>> <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Text#textmetrics>) >>> for the offset to the origin of the next character. The position of >>> each following character is the|advance.x|value multiplied by >>> the|space|value. Obviously letters in the string can be stretched >>> out when the factor is greater than 1, and can be made to overlap >>> when|space|is a fraction closer to zero, but interestingly, using a >>> negative value spaces each letter in the opposite of >>> the|direction|parameter. >>> >> >> This is more or less correct, but what it doesn't say is that >> "spacing" is almost completely useless for a proportionally spaced >> font, for two reasons.  Ref >> https://github.com/openscad/openscad/issues/3859 . >> >> * It does not take ligatures into account; it spaces a ligature as >> a single glyph, yielding text that looks like "d i ffi c u l t". >> * Because it's a multiplier on the advance value, and because the >> advance value is larger for a wide glyph than it is for a narrow >> glyph, spacing between narrow glyphs and wide glyphs is radically >> different.  "IIIMMM" demonstrates this problem. >> >> The "spacing" parameter should probably be downplayed, and should >> probably be deprecated. >> >>> >>> Text Examples >>> >>> *Simulating Formatted Text* >>> >> Needs to define what it means by "formatted". >>> >>> When text needs to be drawn as if it was formatted it is possible to >>> use translate() to space lines of text vertically. Fonts that >>> descend below the baseline need to be spaced apart vertically by >>> about|1.4*size|to not overlap. Some word processing programs use a >>> more generous spacing of|1.6*size|for "single spacing" and double >>> spacing can use|3.2*size|. >>> >> fontmetrics() can supply more correct values for the particular font. >> >> But really this is advice, not reference material. >> >> >>> Fonts in OpenSCAD >>> >>> The fonts available for use in a script are thosed: >>> >>> * registered in the local system >>> * included in the OpenSCAD installation >>> * imported at run-time by a program >>> >>> A call to fontmetrics() using only default settings shows the >>> installation's standard font and settings: >>> >> >> Any reference to fontmetrics() needs a "requires release XXX" note, >> which at the moment is still "requires development snapshot".  But >> really this should be at most a reference to the fontmetrics() section. >> >>> { >>> nominal = { >>> ascent = 12.5733; >>> descent = -2.9433; >>> }; >>> max = { >>> ascent = 13.6109; descent = -4.2114; >>> }; >>> interline = 15.9709; >>> font = { >>> family = "Liberation Sans"; >>> style = "Regular"; >>> }; >>> } >> >> Wherever this ends up, the indentation needs work.  It should match >> the indentation style used in the examples. >> >> >>> None of the platforms OpenSCAD is available on include the >>> Liberation font family so having it as part of the app's >>> installation, and making it the default font, avoids problems of >>> font availability. >>> >> "None" is an awfully broad statement about a moving target. It would >> be better to say "To avoid problems of font availability, OpenSCAD >> includes the Liberation font family as part of its installation, and >> has Liberation Sans as the default font.". >> >>> *Note*: It was previously noted in the docs that fonts may be added >>> to the installation by drag-and-drop of a font file into the editor >>> window, but as of version 2025 Snapshot this is*not*the case >>> >> >> That isn't what it said.  It said: >> >> You can drag a font in the font list, into the editor window to >> use in the text() statement. >> >> I can't readily check a 2025 build at the moment, but as of Oct 2024 >> the it does exactly as described:  dragging a font from the OpenSCAD >> font list into the editor window drops its name in the editor >> window.  If that is no longer the case, it's a bug. >> >> In general, don't say things like this.  If the documentation said X, >> and you find that X is not true, then one of the following is true: >> >> * You didn't understand, and X is indeed true.  (And maybe the >> documentation needs to be clearer.) >> * X is false, and it's a bug.  (The bug should be fixed, not the >> documentation.) >> * X is false, and has always been false, and it was always a >> documentation error.  (And the documentation needs to be fixed.) >> * Indeed, X used to be true and is no longer true, and it's an >> intentional change, and nobody updated the documentation.  This >> is a very rare case, because it often means a compatibility >> problem or feature regression. >> >> Regardless, the right answer is to file an issue to get the actual >> answer. >> >>> In the following sample code a True Type Font, Andika, has been >>> added to the system fonts using its Font Management service. >>> >> >> We shouldn't talk about adding fonts to the system.  That's not our >> problem. >> >> But also, that's not what the sample does.  It adds a font *to >> OpenSCAD*, and has nothing to do with the platform font mechanisms. >> >> >>> Supported font file formats areTrueType >>> <https://en.wikipedia.org/wiki/TrueType>fonts (*.ttf) andOpenType >>> <https://en.wikipedia.org/wiki/OpenType>fonts (*.otf). Once a file >>> is registered to the project the details of the fonts in it may be >>> seen in the font list dialog (see image) so that the logical font >>> names, variations, and their available styles are available for use >>> in the project. >>> >> This says "see image", but doesn't indicate *which* image. >> >> And:  OpenSCAD doesn't have the notion of "projects" or "registered >> to the project". >> >>> >>> 3D Text by Extrusion >>> >> >> This is true of all 2D objects and so does not need to be mentioned.  >> Delete. >> >> >>> position >>> a vector [X,Y], the origin of the first glyph, thus the >>> lower-left corner of the drawn text. >>> >> No, it's not the origin of the first glyph, or at least that's a >> confusing phrase to use.  A glyph is usually positioned slightly to >> the right of the origin, and if it's a descender then it's below the >> origin, and some characters (e.g. quotes) are well above the origin.  >> A more correct statement would be that it's the lower left corner of >> the bounding box of the text. >> >> If one is going to talk about the origin of a glyph, it should be the >> point on the baseline to at the left edge of the advance... which >> this isn't. >> >> >>> size >>> a vector [a,b], the size of the generated text. >>> >> Should be [x,y].  [a,b] doesn't tell you what "a" and "b" mean. >> >>> ascent >>> positive float, the amount that the text extends above the baseline. >>> >> Use the word "number" rather than "float". >> >> It's not always positive; for a glyph entirely below the baseline >> (like underscore in Liberation Sans) it's negative. (I'm not sure >> that's truly the right definition, but it's the current behavior.) >> >>> descent >>> negative float, the amount that the text extends below the baseline. >>> >> >> Not always negative; for a glyph that is entirely above the baseline >> (like apostrophe in Liberation Sans) it's positive. Again, I'm not >> sure that's the right definition, but it's the current behavior. >> >> >>> offset >>> a vector default [0, 0], the lower-left corner of the box >>> containing the text, including inter-glyph spacing before the >>> first glyph. >>> >> >> There is no default; this is a value that's returned to you. >> >> This is not the correct definition (and it wasn't correct in the >> original that I wrote).  It's the position of the origin of the text, >> after adjusting for halign and valign.  For normal LTR text, the X >> coordinate is the X coordinate at the left edge of the first glyph's >> advance, and the Y component is the Y coordinate of the baseline. >> >> >>> advance >>> a vector default [153.09, 0], amount of space to leave to any >>> following text. >>> >> There is no default (and certainly not that one!). >> >> The original definition ("the "other end" of the text, the point at >> which additional text should be positioned.") wasn't great, but was >> more correct.  I would say "The point at which additional text should >> be positioned, relative to the text's origin as reported by 'offset'.". >> >>> This example displays the text metrics for the default font used by >>> OpenSCAD: >>> >> "text metrics for ... font" is a non sequitur.  Text metrics measure >> a particular string.  (And "used by OpenSCAD" is unnecessary; the >> entire document is in that context.) >> >> And it's incorrect; the default font is Liberation Sans and this >> example uses Liberation Serif. >> >> Better would be: >> >> This example displays the text metrics for "Hello, World!" for >> Liberation Serif with size=20: >> >>> <https://en.wikibooks.org/wiki/File:OpenSCAD_textmetrics.png>Using >>> textmetrics() to draw a box around text >>> >>> s="Hello, World!"; >>> size=20; >>> font="Liberation Serif"; >> >>> translate([0,0,1]) >>> text("Hello, World!",size=size,font=font); >> >> >> Should use "s" instead of repeating the string.  (And this is in my >> original, sigh.) >> >> >>> displays (formatted for readability): >>> >> The original "yields" is better, because it might or might not be >> displayed. >> >>> ECHO:{ >>> position=[0.7936,-4.2752]; >>> size=[149.306,23.552]; >>> ascent=19.2768; >>> descent=-4.2752; >>> offset=[0,0]; >>> advance=[153.09,0]; >>> } >> >> The indentation should match the examples, with the close brace at >> the left margin. >> >>> >>> fontmetrics() >>> >> >>> size >>> Decimal, optional. The size of the font, as described above >>> for|text()|. >>> >> Replace "decimal" with "number". >> >>> >>> 0% developed  as of November 17, 2009 >>> <https://en.wikibooks.org/wiki/Help:Development_stages>3D to 2D >>> Projection >>> <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/3D_to_2D_Projection> >>> >>> Using the|projection()|function, you can create 2d drawings from 3d >>> models, >>> >> So far so good. >>> >>>  and export them to the dxf format. >>> >> This part should be deleted.  There are any number of things you >> might do with a 2D projection of a 3D object.  Exporting to DXF is >> only one. >> >>>  It works by projecting a 3D model to the (x,y) plane, with z at 0. >>> If|cut=true|, only points with z=0 are considered (effectively >>> cutting the object), with|cut=false|(/the default/), points above >>> and below the plane are considered as well (creating a proper >>> projection). >>> >>> *Example*: Consider example002.scad, that comes with OpenSCAD. >>> >>> <https://en.wikibooks.org/wiki/File:Openscad_projection_example_2x.png> >>> >>> Then you can do a 'cut' projection, which gives you the 'slice' of >>> the x-y plane with z=0. >>> >> >> Doing the non-default case as the first example seems wrong; I would >> swap the two examples. >> >>> *Another Example* >>> >>> You can also use projection to get a 'side view' of an object. >>> >> This example seems unnecessary for a reference manual.  It's a >> straightforward combination of the features described. >> >>> Links: >>> >>> * More complicated example >>> <http://www.gilesbathgate.com/2010/06/extracting-2d-mendel-outlines-using-openscad/>from >>> Giles Bathgate's blog >>> >> >> Seems inappropriate for a reference manual.  Also, doesn't seem more >> complicated at all. >> >> >>> 0% developed  as of November 17, 2009 >>> <https://en.wikibooks.org/wiki/Help:Development_stages>2D to 3D >>> Extrusion >>> <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/2D_to_3D_Extrusion> >>> >>> Extrusion <https://en.wikipedia.org/wiki/Extrusion>is the process of >>> creating an object with a fixed cross-sectional profile. OpenSCAD >>> provides two commands >>> >> >> "Commands" isn't the right word.  "Modules" is more correct, but >> "operations" is probably best. >> >> >>> Both extrusion methods work on a (possibly disjointed) 2D shape >>> normally drawn in the relevant plane (see below). >>> >> >> The old description of the behavior of extrusion for 2D objects that >> have been moved off the Z=0 plane is an example of something that >> should never have been documented.  It's not a particularly useful >> behavior, and we might eventually want a different behavior.  At >> most, it should have said "don't do that". >> >> It should probably say "drawn on the Z=0 plane". >> >> >>> This child object is first projected onto the X-Y plane along the Z >>> axis to create the starting face of the extrusion. >>> >> >> Delete.  We shouldn't document that behavior. >> >> >>> The start face is duplicated at the Z position given by the height >>> parameter to create the extrusion's end face. The extrusion is then >>> formed by creating a surface that joins each point along the edges >>> of the two faces. >>> >> >> That's a seriously incomplete description, because it's only true >> with all of the parameters at their defaults. >> >> >>> The 2D shape may be any2D primitive shape >>> <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/2D_Primitives>, >>> a2d polygon >>> <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/2D_Primitives#Polygon>, >>> animported 2D drawing >>> <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/2D_Primitives#Importing_a_2D_Drawing>, >>> or aboolean combination >>> <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/CSG_Modelling>of >>> them. >>> >> Or, in other words, the 2D shape may be ... a 2D shape. >> >> Delete the whole sentence. >> >> >>> The 2D shape may have a Z value that moves it out of the X-Y plane, >>> and it may even be rotated out of parallel with it. As stated above, >>> the extrusion's starting face is the projection of the 2D shape onto >>> the X-Y plane, which, if it is rotated, will have the effect of >>> fore-shortening it normal to the axis of the rotation. >>> >> >> Delete. >> >> >>> Using a 3D object as the extrusion's child will cause a compile time >>> error. >>> >> >> Factually incorrect.  It's not a compile-time error; it's a run-time >> error. >> >> Also, we just said that the child must be a 2D shape.  Exact behavior >> when that requirement is violated need not be (and probably should >> not be) specified. >> >> Delete. >> >>> Including a 3D object in a composition of 2D objects (formed using >>> boolean combinations on them) will be detected, the 3D object(s) >>> will be deleted from it and the remaining 2D objects will be the >>> basis for projecting their shape onto the X-Y plane. >>> >> We need not (and generally should not) specify the behavior in error >> conditions.  Delete. >> >> >>> Parameters For Linear Extrusion >>> >>> There are no required parameters. The default operation is to >>> extrude the child by 100 units vertically from the X-Y Plane, >>> centered on the [0,0] origin. >>> >> "centered" is at best meaningless (because it's extruded wherever the >> child is, without respect to the origin) and at worst incorrect >> (because the default is to extrude into +Z, not to center in Z). >> Delete that last phrase. >> >>> 1) height >>> a non-negative integer, default 100, giving the length of the >>> extrusion >>> >> Doesn't have to be an integer. >> >> I don't know how strong a pattern we have for specifying parameters, >> but they shouldn't be numbered.  (Except maybe if they are usable as >> positional parameters - which don't match these numbers.) >> >> >>> 2) v - twist axis vector >>> a vector of 3 signed decimal values, default [0,0,1], used as an >>> eigen vector specifying the axis of rotation for the >>> twist.[Note:Requires versionDevelopment snapshot] >>> >> I can't say that I truly understand eigenvectors, but I don't think >> this is one.  The "signed" part is unnecessary, because all numbers >> are signed, and the "decimal" part is meaningless because abstract >> numbers have no base. >> >> "v" is a vector of three numbers that controls the vector along which >> the extrusion is done. >> >> It has an interesting interaction with "height".  If both are >> specified, height is used as the length of the extrusion, along the >> direction that v points, and v's magnitude is ignored.  If only v is >> specified, it is used to control both the direction and length of the >> extrusion. >> >> Saying that it's the axis of rotation for twist is sort of right, but >> maybe needs more explanation.  Normally when you think of an axis of >> rotation, you're rotating along the plane perpendicular to that >> axis.  Here, though, it is perhaps more correct to say that it >> controls the *origin* of the rotation. At each slice, the 2D shape is >> rotated around Z, with the origin being the XY position of the >> extrusion vector. >> >>> 3) center >>> a boolean, default false, that, when true, causes the resulting >>> solid to be vertically centered at the X-Y plane. >>> >> "at the Z=0 plane" would be a bit more obvious. >> >>> 4) convexity >>> a non-negative integer, default 1, giving a measure of the >>> complexity of the generated surface. See the Section on >>> Convexity later on this page. >>> >> Should include a link... which should not be pointing at this page, >> no matter which page we're talking about. >> >>> 5) twist >>> a signed decimal, >>> >> a number >> >> >>>  180 degrees is a half twist, 360 is all the way around, and so on. >>> >> Unnecessary, delete. >> >> >>> 6) scale >>> either : a non-negative, decimal value, >>> >> a non-negative number >> >>> minimum 0.0, >>> >> >> Implied by "non-negative", delete. >> >> >>>  that specifies the factor by which the end face should be >>> scaled up, or down, in size from that of the start face. >>> >> All scaling is either up or down.  Just "should be scaled". >> >> >>> or : an [x,y] vector that scales the extrusion in the X and Y >>> directions separately. >>> >> >> Delete the colon. >> >> >>> 7) slices >>> a non-negative integer for the number of rows of polygons that >>> the extr. >>> >> Needs help. >> >> >>> h >>> a named parameter, synonym to height >>> >> >> Just list it in the same block as height. >> >> >>> $fn $fs $fa >>> Special Parameters - given as named parameters. >>> >> >> They have standard special-variable semantics, which means they can >> be specified in the context or in the call.  They should be >> mentioned, but perhaps not as parameters per se.  I believe they only >> affect twisted extrusions, so maybe they should be mentioned there. >> >> >>> Center >>> >>> This parameter affects only affects the vertical position or the >>> extrusion. Its X-Y position is always that of the projection that >>> sets its starting face. >>> >> "or" should be "of". >> >> This is a nice comment, but doesn't say what the parameter *does*. >> >> "When true, the extrusion is centered vertically around Z=0." seems >> adequate to me, without any further comment, but a subsequent comment >> about not affecting X and Y would be OK. >> >> >>> Scale >>> >>> This is multiplicative factor that affects the size of extrusion's >>> end face. As such 1.0 means no change, a value greater than one >>> expands the end face, and a value between 0.001 and less than 1 >>> shrinks it. >>> >> "As such" is unnecessary. >> >> I don't know where 0.001 came from.  I would say "a value less than 1 >> shrinks it". >> >>>  A value of 0.0 causes the end face to degenerate to a point, >>> turning the extrusion into a pyramid, cone, or complex pointy shape >>> according to what the starting shape is. >>> >> I'd say this is unnecessary. >> >> >>> Using the vector form sets the scale factor in the X and Y >>> directions separately >>> >>> >>> Twist >>> >>> Twist is applied, by default, as a rotation about the Z Axis. >>> >> As discussed above, twist is always around Z.  What v controls is the >> origin of that rotation. >> >> >>> When the start face is at the origin a twist creates a spiral out of >>> any corners in the child shape. If the start face is translated away >>> from the origin the twist creates a spring shape. >>> >> I don't know if it's truly useful to try to describe the various >> shapes that can result from twisting. >> >> One thing that might be worth explicitly mentioning is that you can't >> practically use linear_extrude to generate threads. You can come >> temptingly close, but they won't be shaped right.  (It is actually >> possible to get right, but requires an unobvious base shape.) >> >> >>> A positive twist rotates clockwise, negative twist the opposite. >>> >> >> Huh.  I basically never use twist, so I never noticed that it's >> backwards from rotate.  That seems very wrong... and it's way too >> late to fix it.  It might be worth mentioning this difference. >> >> >>> Twist Axis Vector >>> >>> The second parameter is an [x,y,z] eigen vector that specifies the >>> axis of rotation of the applied twist. >>> >> >> Suggest referring to it by name instead of by position. >> >> >>>  The ratios of the three dimensional values to their respective >>> coordinate axes specify the tilt away from the default axis, >>> [0,0,1], the Z-Axis. For instance, v=[cos(45),0,1] tilts the >>> extrusion at 45 degrees to the X axis. >>> >> >> It's actually a skew rather than a tilt. >> >> >>> The start and end faces are always normal to the Z-axis, even when >>> the twist axis is tilted. The extruded and twisted surfaces are thus >>> distorted from what might be expected in an extruded shape. The more >>> expected result may be achieved by applying a rotation to then >>> twisted extrusion on the Z Axis to tilt it into the desired position. >>> >> It's best not to make assumptions about what the user expects.  >> Describe the operation, and describe it carefully. Do not describe >> how to do things that are straightforward combinations of operations. >> >> --- >> >> Note that the documentation does not discuss which happens first:  >> twist or scale.  I don't believe it matters when using the same >> scaling for X and Y, but matters a great deal with using different >> scaling on the two axes.  It twists and then scales, which can mean >> (for instance) that a shape that started out rectangular turns into a >> parallelogram.  There's an argument that this is *not* the useful >> behavior, and that scale-and-then-twist is more useful since it >> retains the general shape throughout the extrusion.  I've started a >> discussion a few times about maybe changing this, but I don't think >> it ever came to a conclusion.  It might be best not to document this >> without that conclusion. >> >> >>> $fn, $fa, $fs Special Parameters >>> >>> The special variables must be given as named parameters and are >>> applied to the extrusion, overriding the global setting. When the >>> same special variables are set on the base shape its values override >>> their use as parameters on the extrusion. >>> >> None of this is really accurate. >> >> The special variables have standard special-variable behavior, which >> means that you can specify them in the context or in the particular >> call, and they apply to that context (including a specific call) and >> everything that that is called from that context.  There is no >> "global setting" that is special. >> >> What matters for the linear_extrude (and in particular for twisted >> extrusions) is the setting that *it* sees. >> >> If the child 2D shape *also* uses these variables, what matters for >> it is what *it* sees... which, absent an inner setting, will be the >> same as what linear_extrude sees. >> >> Thus, either: >> >> linear_extrude(height=10, twist=20, $fn=100) circle(10); >> >> or >> >> $fn=100; linear_extrude(height=10, twist=20) circle(10); >> >> will yield a high-resolution twist of a high-resolution circle. >> >> On the other hand, either >> >> linear_extrude(height=10, twist=20, $fn=100) circle(10, $fn=3); >> >> or >> >> $fn=100; linear_extrude(height=10, twist=20) circle(10, $fn=3); >> >> will yield a high-resolution twist of a low-resolution circle - a >> triangle. >> >>> >>> Extrusion From Imported DXF >>> >> Does not need to be discussed.  You can linear_extrude any 2D shape, >> and an import of a DXF yields a 2D shape. >> >>> >>> A Unit Circle with No Twist >>> >> >> I don't think all of these examples are necessary. >> >> >>> Generate an extrusion from a circle 2 units along the X Axis from >>> the origin, >>> >> unit circle >> >>> centered vertically on the X-Y plane, with no twist. The extrusion >>> appears to have a pentagonal cross-section because the extrusion's >>> child is a 2D circle with the default value for $fn. >>> >> >> It doesn't *appear* to have a pentagonal cross-section.  It *does* >> have a pentagonal cross-section. >> >>> The same circle, but made into a spiral by 500 degrees of >>> counter-clockwise twist. >>> >> >> If you look carefully, this example demonstrates why you can't make >> threads.  As you twist it more, it becomes thinner and thinner in Z.  >> The problem is that the cross-section of a thread is a strange shape. >> >> >>> Mesh Refinement >>> >>> The slices parameter defines the number of intermediate points along >>> the Z axis of the extrusion. >>> >> >> I am not sure of the exactly right way to describe this, because of >> fence post errors. >> >> "slices" controls the number of 3D "chunks" that make up the >> extrusion.  The total number of instances of the original 2D object >> is slices+1. >> >>> Its default increases with the value of twist. >>> >> >> It's some function of that and $fa/$fs/$fn.  I don't know what the >> function is or exactly how to describe it. >> >> >>> Additional the segments parameter >>> >> Addition -> Additionally >> >> >>> Segments need to be a multiple of the polygon's fragments to have an >>> effect (6 or 9.. for a circle($fn=3), 8,12.. for a square() ). >>> >> >> I don't know what the actual behavior is, but that's not it. For more >> complex shapes (I experimented with a right triangle) intermediate >> values do have an effect. >> >> >>> Thespecial variables >>> <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Other_Language_Features>$fn, >>> $fs and $fa can also be used to improve the output. If slices is not >>> defined, its value is taken from the defined $fn value. >>> >> >> Again, I don't know what the behavior is, but that's not it. >> Increasing $fn does increase the number of slices, but it isn't >> simply used as the number of slices. >> >> $fa/$fs/$fn seem to control both slices and segments. >> >>> >>> Using with imported SVG >>> >> >> Does not need to be separately discussed. >> >> >>> rotate_extrude() Operator Module >>> >>> Rotational extrusion spins a 2D shape around the Z-axis to form a >>> solid which has rotational symmetry. One way to think of this >>> operation is to imagine a Potter's wheel placed on the X-Y plane >>> with its axis of rotation pointing up towards +Z. Then place the >>> to-be-made object on this virtual Potter's wheel (possibly extending >>> down below the X-Y plane towards -Z). The to-be-made object is the >>> cross-section of the object on the X-Y plane (keeping only the right >>> half, X >= 0). That is the 2D shape that will be fed to >>> rotate_extrude() as the child in order to generate this solid. Note >>> that the object started on the X-Y plane but is tilted up (rotated >>> +90 degrees about the X-axis) to extrude. >>> >> >> I'm not sure that this is the best possible explanation. >> >> >>> Since a 2D shape is rendered by OpenSCAD on the X-Y plane, an >>> alternative way to think of this operation is as follows: spins a 2D >>> shape around the Y-axis to form a solid. The resultant solid is >>> placed so that its axis of rotation lies along the Z-axis. >>> >> >> That's the way that I always think of it, though I mentally rotate it >> to vertical before spinning it. >> >> >>> Just like the linear_extrude, the extrusion is always performed on >>> the projection of the 2D polygon to the XY plane. >>> >> >> Again, we should not document this behavior. >> >> >>> Transformations like rotate, translate, etc. applied to the 2D >>> polygon before extrusion modify the projection of the 2D polygon to >>> the XY plane and therefore also modify the appearance of the final >>> 3D object. >>> >>> * A translation in Z of the 2D polygon has no effect on the result >>> (as also the projection is not affected). >>> * A translation in X increases the diameter of the final object. >>> * A translation in Y results in a shift of the final object in Z >>> direction. >>> * A rotation about the X or Y axis distorts the cross section of >>> the final object, as also the projection to the XY plane is >>> distorted. >>> >> >> This is perhaps good stuff, if the part about projecting is removed. >> >> >>> Don't get confused, as OpenSCAD displays 2D polygons with a certain >>> height in the Z direction, so the 2D object (with its height) >>> appears to have a bigger projection to the XY plane. But for the >>> projection to the XY plane and also for the later extrusion only the >>> base polygon without height is used. >>> >> >> Once you get rid of the part about projecting this goes away too. >> >> >>> You cannot use rotate_extrude to produce a helix or screw thread. >>> Doing this properly can be difficult, so it's best to find a thread >>> library to make them for you. >>> >> >> This kind of comment can be valuable, but I'm not sure it belongs in >> a reference manual.  If it *is* in a reference manual, it should be >> in a clear and separate section (of the description of the particular >> feature) marked "Application Notes" or something like that, to make >> it clear that it's *not* part of the description of the feature. >> >> >>> If the shape spans the X axis a warning appears in the console >>> windows and the rotate_extrude() is ignored. >>> >> Don't talk about what window something appears in, because not >> everybody uses the OpenSCAD GUI. >> >> Don't talk about what happens "after" the error. >> >> Just say that it's an error, period. >> >> (And, BTW, this particular one is something that I think should not >> be an error; I think that the result should be as if you split the 2D >> shape in half, rotationally extruded both, and unioned them.  That >> is, take the shape, sweep it 360 degrees, and anything it sweeps >> through (whether once or twice) is part of the result.) >> >> >>>  If the 2D shape touches the Y axis, i.e. at x=0, it*must*be a line >>> that touches, not a point, as a point results in a zero thickness 3D >>> object, which is invalid and results in a CGAL error. >>> >> >> This may have been addressed with Manifold. >> >> >>> *convexity* : If the extrusion fails for a non-trival 2D shape, >>> try setting the convexity parameter (the default is not 10, but >>> 10 is a "good" value to try). See explanation further down. >>> >> >> Just point at the general discussion of convexity.  (Which should not >> be on this page.) >> >> And the extrusion does not "fail".  In fact, the artifacts may be >> quite subtle. >> >> >>> *start*[Note:Requires versionDevelopment snapshot] : Defaults to >>> 0 if*angle*is specified, and 180 if not. Specifies the starting >>> angle of the extrusion, counter-clockwise from the positive X axis. >>> >> >> start was part of an effort to align rotational extrusion behavior >> with the behavior of other round things.  I don't remember all of the >> details, but there are few reasons why it isn't equivalent to >> rotating the result. >> >> >>> *$fa* : minimum angle (in degrees) of each fragment. >>> *$fs* : minimum circumferential length of each fragment. >>> *$fn* :*fixed*number of fragments in 360 degrees. Values of 3 or >>> more override $fa and $fs >>> >>> $fa, $fs and $fn must be named parameters.click here for >>> more details, >>> <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Other_Language_Features>. >>> >> Do not describe these in detail here.  Refer to a general description >> of them elsewhere. >> >> Do not ever, ever, say "click here".  Any text that would not make >> sense when printed is wrong. >> >> >>> Rotate Extrude on Imported DXF >>> >> >> Delete. >> >> >>> Increasing the number of fragments composing the 2D shape improves >>> the quality of the mesh, but takes longer to render. >>> >> >> Unnecessary. >> >> >>> rotate_extrude(convexity = 10) >>> translate([2, 0, 0]) >>> circle(r = 1, $fn = 100); >> >> This example is unnecessary; this is a description of rotate_extrude, >> not circle() >> >>> The number of fragments used by the extrusion can also be increased. >>> >>> rotate_extrude(convexity = 10, $fn = 100) >>> translate([2, 0, 0]) >>> circle(r = 1, $fn = 100); >> >> >> Use $fs and $fa here.  In fact, supply them at the top level.  And >> this case doesn't require specifying convexity (though I'm not sure >> why not).  Also, for circles this small high resolution is not >> practical; make them bigger to make the example more real. Thus: >> >> $fa = 1; >> $fs = 1; >> rotate_extrude() >> translate([20, 0, 0]) >> circle(r = 10); >> >> That's really the best practice.  You almost never want to use $fn if >> your intent is to create a circle. >> >> (Minor exception that is itself something of a bug:  if you're trying >> to force the number of sides to be a multiple of 4.  But that >> shouldn't be discussed here.) >> >> >>> Using the parameter angle (with OpenSCAD versions 2016.xx), a hook >>> can be modeled . >>> >>> <https://en.wikibooks.org/wiki/File:Hook.png>OpenSCAD - a hook >>> >>> eps = 0.01; >>> translate([eps, 60, 0]) >>> rotate_extrude(angle=270, convexity=10) >>> translate([40, 0]) circle(10); >>> rotate_extrude(angle=90, convexity=10) >>> translate([20, 0]) circle(10); >>> translate([20, eps, 0]) >>> rotate([90, 0, 0]) cylinder(r=10, h=80+eps); >> >> >> Delete. >> >> >>> Extruding a Polygon >>> >> >> Delete. >> >> >>> Description of extrude parameters >>> >> >> Why are we repeating these here?  Don't, especially because there is >> little commonality between linear_extrude and rotate_extrude. >> >> >>> 0% developed  as of November 17, 2009 >>> <https://en.wikibooks.org/wiki/Help:Development_stages>DXF >>> Extrusion >>> <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/DXF_Extrusion> >>> >> >> Delete. >> >>> >>> Import 2D >>> >>> Import 2D Shapes >>> <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Import_2D> >>> >> >> This should get more content.  At the current state of things it can >> probably all go on the 2D page, but if it gets much more complex it >> might want its own page with a brief summary and reference here. >> >> >> >> _______________________________________________ >> OpenSCAD mailing list >> To unsubscribe send an email todiscuss-leave@lists.openscad.org > > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email todiscuss-leave@lists.openscad.org
JB
Jordan Brown
Fri, Aug 8, 2025 6:55 PM

On 8/8/2025 1:08 AM, Jordan Brown via Discuss wrote:

Note: It was previously noted in the docs that fonts may be added
to the installation by drag-and-drop of a font file into the editor
window, but as of version 2025 Snapshot this isnotthe case

That isn't what it said.  It said:

 You can drag a font in the font list, into the editor window to
 use in the text() statement.

I can't readily check a 2025 build at the moment, but as of Oct 2024
the it does exactly as described:  dragging a font from the OpenSCAD
font list into the editor window drops its name in the editor window. 
If that is no longer the case, it's a bug.

Confirmed working in a build today on Windows.  If it doesn't work, it's
a bug.

On 8/8/2025 1:08 AM, Jordan Brown via Discuss wrote: >> >> *Note*: It was previously noted in the docs that fonts may be added >> to the installation by drag-and-drop of a font file into the editor >> window, but as of version 2025 Snapshot this is*not*the case >> > That isn't what it said.  It said: > > You can drag a font in the font list, into the editor window to > use in the text() statement. > > I can't readily check a 2025 build at the moment, but as of Oct 2024 > the it does exactly as described:  dragging a font from the OpenSCAD > font list into the editor window drops its name in the editor window.  > If that is no longer the case, it's a bug. > Confirmed working in a build today on Windows.  If it doesn't work, it's a bug.
V
vulcan_@mac.com
Sat, Aug 9, 2025 1:02 AM

Jon Bondy wrote:

I, for one, find what Vulcan is doing to be terrifying.  And I do not
have the patience to read all of the new documentation, over and over
again, trying to figure out what else has been broken.

Terrifying?  Really?  it is a wiki with version control. How can anything i might do be terrifying?
I might misunderstand a thing and write something misleading .. which someone would eventually notice and fix .. that is the absolute worst situation that i could create.

Repeating  … it is a wiki with version control .. just revert my work out and your docs are back under your control, ‘cause i will never contribute again.

and given the communities difficulty with a newcomer trying to contribute maybe that is what i should do

I don't doubt that Vulcan's intentions are good, but I wonder if there
really is a problem that needs solving. 

There were problems .. lots of them. When i started exploring scad i found that pretty much every module and function I wanted to use was under documented, even confusing in places .. I am a good tech writer and i like to contribute where i can .. so once my examples and test scripts showed me how to improve things in the docs  i thought to contribute my insights back to the community

I also wonder whether the
community would be better off with an experienced OpenSCAD programmer
making the changes.

that would be the community’s choice to make .. but my impression is that the experienced OpenSCAD programmers are quite busy with new features and maintenance so documentation is well down the priority list. But okay, if newcomers are not welcome then lock down the permissions so only the Chosen Few can update the docs and again, the issue is solved.

I understand that the documentation should be accessible to an OpenSCAD
newbie, but I am not sure that these changes will produce the best product.

As stated .. all i need is to be able to READ the docs .. i don’t need to contribute, and i don’t need to be on the wrong side of a turf war

There are other tool sets i can do my 3D printing with

Jon Bondy wrote: > > > I, for one, find what Vulcan is doing to be terrifying.  And I do not > have the patience to read all of the new documentation, over and over > again, trying to figure out what else has been broken. Terrifying? Really? it is a wiki with version control. How can anything i might do be terrifying?\ I might misunderstand a thing and write something misleading .. which someone would eventually notice and fix .. that is the absolute worst situation that i could create. Repeating … it *is a wiki with version control* .. just revert my work out and your docs are back under your control, ‘cause i will never contribute again. and given the communities difficulty with a newcomer trying to contribute maybe that is what i should do > I don't doubt that Vulcan's intentions are good, but I wonder if there > really is a problem that needs solving.  There were problems .. lots of them. When i started exploring scad i found that pretty much every module and function I wanted to use was under documented, even confusing in places .. I am a good tech writer and i like to contribute where i can .. so once my examples and test scripts showed me how to improve things in the docs i thought to contribute my insights back to the community > I also wonder whether the > community would be better off with an experienced OpenSCAD programmer > making the changes. that would be the community’s choice to make .. but my impression is that the experienced OpenSCAD programmers are quite busy with new features and maintenance so documentation is well down the priority list. But okay, if newcomers are not welcome then lock down the permissions so only the Chosen Few can update the docs and again, the issue is solved. > I understand that the documentation should be accessible to an OpenSCAD > newbie, but I am not sure that these changes will produce the best product. As stated .. all i *need* is to be able to READ the docs .. i don’t *need* to contribute, and i don’t *need* to be on the wrong side of a turf war There are other tool sets i can do my 3D printing with
V
vulcan_@mac.com
Sat, Aug 9, 2025 1:04 AM

Jon Bondy wrote:

What is the community getting for this INCREDIBLE level of effort?

I think we should

  1. revert the documentation back to prior to when Vulcan started
    changing things

good .. you do that .. i am out

Jon Bondy wrote: > What is the community getting for this INCREDIBLE level of effort? > > I think we should > > 1. revert the documentation back to prior to when Vulcan started > changing things good .. you do that .. i am out
V
vulcan_@mac.com
Sat, Aug 9, 2025 1:07 AM

Jordan, thanks for your patient help and feedback .. i have learned a lot about functional language programming .. a sort of programming that i knew nothing about before coming to OpenSCAD

Jeff Hayes

Jordan, thanks for your patient help and feedback .. i have learned a lot about functional language programming .. a sort of programming that i knew nothing about before coming to OpenSCAD — Jeff Hayes
JB
Jon Bondy
Sat, Aug 9, 2025 1:10 AM

I did not find the documentation to be confusing.

Experienced OpenSCAD programmers are spending their time responding and
reacting to the content you are creating.  I am not convinced that this
is the best use of their time.

This is not a turf war.  This is about how to get quality documentation
with the minimum of effort from all involved.

Perhaps others should comment.  I have had my say.  If I am all alone,
then I will not comment further.

Jon

On 8/8/2025 9:02 PM, vulcan_--- via Discuss wrote:

Jon Bondy wrote:

 I, for one, find what Vulcan is doing to be terrifying.  And I do
 not have the patience to read all of the new documentation, over
 and over again, trying to figure out what else has been broken.

Terrifying? Really? it is a wiki with version control. How can
anything i might do be terrifying?
I might misunderstand a thing and write something misleading .. which
someone would eventually notice and fix .. that is the absolute worst
situation that i could create.

Repeating … it /is a wiki with version control/ .. just revert my work
out and your docs are back under your control, ‘cause i will never
contribute again.

and given the communities difficulty with a newcomer trying to
contribute maybe that is what i should do

 I don't doubt that Vulcan's intentions are good, but I wonder if
 there really is a problem that needs solving.

There were problems .. lots of them. When i started exploring scad i
found that pretty much every module and function I wanted to use was
under documented, even confusing in places .. I am a good tech writer
and i like to contribute where i can .. so once my examples and test
scripts showed me how to improve things in the docs i thought to
contribute my insights back to the community

 I also wonder whether the community would be better off with an
 experienced OpenSCAD programmer making the changes.

that would be the community’s choice to make .. but my impression is
that the experienced OpenSCAD programmers are quite busy with new
features and maintenance so documentation is well down the priority
list. But okay, if newcomers are not welcome then lock down the
permissions so only the Chosen Few can update the docs and again, the
issue is solved.

 I understand that the documentation should be accessible to an
 OpenSCAD newbie, but I am not sure that these changes will produce
 the best product.

As stated .. all i /need/ is to be able to READ the docs .. i don’t
/need/ to contribute, and i don’t /need/ to be on the wrong side of a
turf war

There are other tool sets i can do my 3D printing with


OpenSCAD mailing list
To unsubscribe send an email todiscuss-leave@lists.openscad.org

--
This email has been checked for viruses by AVG antivirus software.
www.avg.com

I did not find the documentation to be confusing. Experienced OpenSCAD programmers are spending their time responding and reacting to the content you are creating.  I am not convinced that this is the best use of their time. This is not a turf war.  This is about how to get quality documentation with the minimum of effort from all involved. Perhaps others should comment.  I have had my say.  If I am all alone, then I will not comment further. Jon On 8/8/2025 9:02 PM, vulcan_--- via Discuss wrote: > > Jon Bondy wrote: > > > > I, for one, find what Vulcan is doing to be terrifying.  And I do > not have the patience to read all of the new documentation, over > and over again, trying to figure out what else has been broken. > > Terrifying? Really? it is a wiki with version control. How can > anything i might do be terrifying? > I might misunderstand a thing and write something misleading .. which > someone would eventually notice and fix .. that is the absolute worst > situation that i could create. > > Repeating … it /is a wiki with version control/ .. just revert my work > out and your docs are back under your control, ‘cause i will never > contribute again. > > and given the communities difficulty with a newcomer trying to > contribute maybe that is what i should do > > I don't doubt that Vulcan's intentions are good, but I wonder if > there really is a problem that needs solving. > > There were problems .. lots of them. When i started exploring scad i > found that pretty much every module and function I wanted to use was > under documented, even confusing in places .. I am a good tech writer > and i like to contribute where i can .. so once my examples and test > scripts showed me how to improve things in the docs i thought to > contribute my insights back to the community > > I also wonder whether the community would be better off with an > experienced OpenSCAD programmer making the changes. > > that would be the community’s choice to make .. but my impression is > that the experienced OpenSCAD programmers are quite busy with new > features and maintenance so documentation is well down the priority > list. But okay, if newcomers are not welcome then lock down the > permissions so only the Chosen Few can update the docs and again, the > issue is solved. > > I understand that the documentation should be accessible to an > OpenSCAD newbie, but I am not sure that these changes will produce > the best product. > > As stated .. all i /need/ is to be able to READ the docs .. i don’t > /need/ to contribute, and i don’t /need/ to be on the wrong side of a > turf war > > There are other tool sets i can do my 3D printing with > > > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email todiscuss-leave@lists.openscad.org -- This email has been checked for viruses by AVG antivirus software. www.avg.com
FH
Father Horton
Sat, Aug 9, 2025 3:01 AM

OpenSCAD can undoubtedly being confusing, particularly to someone who
doesn't have much (or any) background with functional programming. I, too,
don't see the need for a complete documentation rewrite. I do think an
introduction to the OpenSCAD way of thinking would be helpful.

A lot of documentation is written from what I call the "ground-up"
perspective: I'll give you all the details, and you assemble the picture. I
work better with "top-down" documentation: Here's the idea, and here's how
you implement it. Come to think of it, that's probably why I can't get my
mind around BOSL2's documentation of things like attachment.

On Fri, Aug 8, 2025 at 8:10 PM Jon Bondy via Discuss <
discuss@lists.openscad.org> wrote:

I did not find the documentation to be confusing.

Experienced OpenSCAD programmers are spending their time responding and
reacting to the content you are creating.  I am not convinced that this is
the best use of their time.

This is not a turf war.  This is about how to get quality documentation
with the minimum of effort from all involved.

Perhaps others should comment.  I have had my say.  If I am all alone,
then I will not comment further.

Jon

On 8/8/2025 9:02 PM, vulcan_--- via Discuss wrote:

Jon Bondy wrote:

I, for one, find what Vulcan is doing to be terrifying.  And I do not have
the patience to read all of the new documentation, over and over again,
trying to figure out what else has been broken.

Terrifying? Really? it is a wiki with version control. How can anything i
might do be terrifying?
I might misunderstand a thing and write something misleading .. which
someone would eventually notice and fix .. that is the absolute worst
situation that i could create.

Repeating … it is a wiki with version control .. just revert my work
out and your docs are back under your control, ‘cause i will never
contribute again.

and given the communities difficulty with a newcomer trying to contribute
maybe that is what i should do

I don't doubt that Vulcan's intentions are good, but I wonder if there
really is a problem that needs solving.

There were problems .. lots of them. When i started exploring scad i found
that pretty much every module and function I wanted to use was under
documented, even confusing in places .. I am a good tech writer and i like
to contribute where i can .. so once my examples and test scripts showed me
how to improve things in the docs i thought to contribute my insights back
to the community

I also wonder whether the community would be better off with an
experienced OpenSCAD programmer making the changes.

that would be the community’s choice to make .. but my impression is that
the experienced OpenSCAD programmers are quite busy with new features and
maintenance so documentation is well down the priority list. But okay, if
newcomers are not welcome then lock down the permissions so only the Chosen
Few can update the docs and again, the issue is solved.

I understand that the documentation should be accessible to an OpenSCAD
newbie, but I am not sure that these changes will produce the best product.

As stated .. all i need is to be able to READ the docs .. i don’t need
to contribute, and i don’t need to be on the wrong side of a turf war

There are other tool sets i can do my 3D printing with


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=emailclient
Virus-free.www.avg.com
http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=emailclient
<#m_4840886636887567490_DAB4FAD8-2DD7-40BB-A1B8-4E2AA1F9FDF2>


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

OpenSCAD can undoubtedly being confusing, particularly to someone who doesn't have much (or any) background with functional programming. I, too, don't see the need for a complete documentation rewrite. I do think an introduction to the OpenSCAD way of thinking would be helpful. A lot of documentation is written from what I call the "ground-up" perspective: I'll give you all the details, and you assemble the picture. I work better with "top-down" documentation: Here's the idea, and here's how you implement it. Come to think of it, that's probably why I can't get my mind around BOSL2's documentation of things like attachment. On Fri, Aug 8, 2025 at 8:10 PM Jon Bondy via Discuss < discuss@lists.openscad.org> wrote: > I did not find the documentation to be confusing. > > Experienced OpenSCAD programmers are spending their time responding and > reacting to the content you are creating. I am not convinced that this is > the best use of their time. > > This is not a turf war. This is about how to get quality documentation > with the minimum of effort from all involved. > > Perhaps others should comment. I have had my say. If I am all alone, > then I will not comment further. > > Jon > > > On 8/8/2025 9:02 PM, vulcan_--- via Discuss wrote: > > Jon Bondy wrote: > > > > I, for one, find what Vulcan is doing to be terrifying. And I do not have > the patience to read all of the new documentation, over and over again, > trying to figure out what else has been broken. > > Terrifying? Really? it is a wiki with version control. How can anything i > might do be terrifying? > I might misunderstand a thing and write something misleading .. which > someone would eventually notice and fix .. that is the absolute worst > situation that i could create. > > Repeating … it *is a wiki with version control* .. just revert my work > out and your docs are back under your control, ‘cause i will never > contribute again. > > and given the communities difficulty with a newcomer trying to contribute > maybe that is what i should do > > I don't doubt that Vulcan's intentions are good, but I wonder if there > really is a problem that needs solving. > > There were problems .. lots of them. When i started exploring scad i found > that pretty much every module and function I wanted to use was under > documented, even confusing in places .. I am a good tech writer and i like > to contribute where i can .. so once my examples and test scripts showed me > how to improve things in the docs i thought to contribute my insights back > to the community > > I also wonder whether the community would be better off with an > experienced OpenSCAD programmer making the changes. > > that would be the community’s choice to make .. but my impression is that > the experienced OpenSCAD programmers are quite busy with new features and > maintenance so documentation is well down the priority list. But okay, if > newcomers are not welcome then lock down the permissions so only the Chosen > Few can update the docs and again, the issue is solved. > > I understand that the documentation should be accessible to an OpenSCAD > newbie, but I am not sure that these changes will produce the best product. > > As stated .. all i *need* is to be able to READ the docs .. i don’t *need* > to contribute, and i don’t *need* to be on the wrong side of a turf war > > There are other tool sets i can do my 3D printing with > > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org > > > > <http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=emailclient> > Virus-free.www.avg.com > <http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=emailclient> > <#m_4840886636887567490_DAB4FAD8-2DD7-40BB-A1B8-4E2AA1F9FDF2> > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org >
LM
Leonard Martin Struttmann
Sat, Aug 9, 2025 3:17 AM

Father Horton: Regarding BOSL2: Yes! You have hit upon the key! When I was
still a corporate minion, I would write documentation based upon "Here's
what you do to produce this result." Not, "this parameter does that.".

On Fri, Aug 8, 2025 at 10:02 PM Father Horton via Discuss <
discuss@lists.openscad.org> wrote:

OpenSCAD can undoubtedly being confusing, particularly to someone who
doesn't have much (or any) background with functional programming. I, too,
don't see the need for a complete documentation rewrite. I do think an
introduction to the OpenSCAD way of thinking would be helpful.

A lot of documentation is written from what I call the "ground-up"
perspective: I'll give you all the details, and you assemble the picture. I
work better with "top-down" documentation: Here's the idea, and here's how
you implement it. Come to think of it, that's probably why I can't get my
mind around BOSL2's documentation of things like attachment.

On Fri, Aug 8, 2025 at 8:10 PM Jon Bondy via Discuss <
discuss@lists.openscad.org> wrote:

I did not find the documentation to be confusing.

Experienced OpenSCAD programmers are spending their time responding and
reacting to the content you are creating.  I am not convinced that this is
the best use of their time.

This is not a turf war.  This is about how to get quality documentation
with the minimum of effort from all involved.

Perhaps others should comment.  I have had my say.  If I am all alone,
then I will not comment further.

Jon

On 8/8/2025 9:02 PM, vulcan_--- via Discuss wrote:

Jon Bondy wrote:

I, for one, find what Vulcan is doing to be terrifying.  And I do not
have the patience to read all of the new documentation, over and over
again, trying to figure out what else has been broken.

Terrifying? Really? it is a wiki with version control. How can anything i
might do be terrifying?
I might misunderstand a thing and write something misleading .. which
someone would eventually notice and fix .. that is the absolute worst
situation that i could create.

Repeating … it is a wiki with version control .. just revert my work
out and your docs are back under your control, ‘cause i will never
contribute again.

and given the communities difficulty with a newcomer trying to contribute
maybe that is what i should do

I don't doubt that Vulcan's intentions are good, but I wonder if there
really is a problem that needs solving.

There were problems .. lots of them. When i started exploring scad i
found that pretty much every module and function I wanted to use was under
documented, even confusing in places .. I am a good tech writer and i like
to contribute where i can .. so once my examples and test scripts showed me
how to improve things in the docs i thought to contribute my insights back
to the community

I also wonder whether the community would be better off with an
experienced OpenSCAD programmer making the changes.

that would be the community’s choice to make .. but my impression is that
the experienced OpenSCAD programmers are quite busy with new features and
maintenance so documentation is well down the priority list. But okay, if
newcomers are not welcome then lock down the permissions so only the Chosen
Few can update the docs and again, the issue is solved.

I understand that the documentation should be accessible to an OpenSCAD
newbie, but I am not sure that these changes will produce the best product.

As stated .. all i need is to be able to READ the docs .. i don’t
need to contribute, and i don’t need to be on the wrong side of a
turf war

There are other tool sets i can do my 3D printing with


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=emailclient
Virus-free.www.avg.com
http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=emailclient
<#m_-2042511425043668043_m_4840886636887567490_DAB4FAD8-2DD7-40BB-A1B8-4E2AA1F9FDF2>


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

Father Horton: Regarding BOSL2: Yes! You have hit upon the key! When I was still a corporate minion, I would write documentation based upon "Here's what you do to produce this result." Not, "this parameter does that.". On Fri, Aug 8, 2025 at 10:02 PM Father Horton via Discuss < discuss@lists.openscad.org> wrote: > OpenSCAD can undoubtedly being confusing, particularly to someone who > doesn't have much (or any) background with functional programming. I, too, > don't see the need for a complete documentation rewrite. I do think an > introduction to the OpenSCAD way of thinking would be helpful. > > A lot of documentation is written from what I call the "ground-up" > perspective: I'll give you all the details, and you assemble the picture. I > work better with "top-down" documentation: Here's the idea, and here's how > you implement it. Come to think of it, that's probably why I can't get my > mind around BOSL2's documentation of things like attachment. > > On Fri, Aug 8, 2025 at 8:10 PM Jon Bondy via Discuss < > discuss@lists.openscad.org> wrote: > >> I did not find the documentation to be confusing. >> >> Experienced OpenSCAD programmers are spending their time responding and >> reacting to the content you are creating. I am not convinced that this is >> the best use of their time. >> >> This is not a turf war. This is about how to get quality documentation >> with the minimum of effort from all involved. >> >> Perhaps others should comment. I have had my say. If I am all alone, >> then I will not comment further. >> >> Jon >> >> >> On 8/8/2025 9:02 PM, vulcan_--- via Discuss wrote: >> >> Jon Bondy wrote: >> >> >> >> I, for one, find what Vulcan is doing to be terrifying. And I do not >> have the patience to read all of the new documentation, over and over >> again, trying to figure out what else has been broken. >> >> Terrifying? Really? it is a wiki with version control. How can anything i >> might do be terrifying? >> I might misunderstand a thing and write something misleading .. which >> someone would eventually notice and fix .. that is the absolute worst >> situation that i could create. >> >> Repeating … it *is a wiki with version control* .. just revert my work >> out and your docs are back under your control, ‘cause i will never >> contribute again. >> >> and given the communities difficulty with a newcomer trying to contribute >> maybe that is what i should do >> >> I don't doubt that Vulcan's intentions are good, but I wonder if there >> really is a problem that needs solving. >> >> There were problems .. lots of them. When i started exploring scad i >> found that pretty much every module and function I wanted to use was under >> documented, even confusing in places .. I am a good tech writer and i like >> to contribute where i can .. so once my examples and test scripts showed me >> how to improve things in the docs i thought to contribute my insights back >> to the community >> >> I also wonder whether the community would be better off with an >> experienced OpenSCAD programmer making the changes. >> >> that would be the community’s choice to make .. but my impression is that >> the experienced OpenSCAD programmers are quite busy with new features and >> maintenance so documentation is well down the priority list. But okay, if >> newcomers are not welcome then lock down the permissions so only the Chosen >> Few can update the docs and again, the issue is solved. >> >> I understand that the documentation should be accessible to an OpenSCAD >> newbie, but I am not sure that these changes will produce the best product. >> >> As stated .. all i *need* is to be able to READ the docs .. i don’t >> *need* to contribute, and i don’t *need* to be on the wrong side of a >> turf war >> >> There are other tool sets i can do my 3D printing with >> >> _______________________________________________ >> OpenSCAD mailing list >> To unsubscribe send an email to discuss-leave@lists.openscad.org >> >> >> >> <http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=emailclient> >> Virus-free.www.avg.com >> <http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=emailclient> >> <#m_-2042511425043668043_m_4840886636887567490_DAB4FAD8-2DD7-40BB-A1B8-4E2AA1F9FDF2> >> _______________________________________________ >> OpenSCAD mailing list >> To unsubscribe send an email to discuss-leave@lists.openscad.org >> > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org >
AM
Adrian Mariano
Sat, Aug 9, 2025 3:26 AM

The main BOSL2 manual is a reference manual, but I think the tutorials are
supposed to do what you are asking.  How does, for example, the Attachments
tutorial fail for you?

On Fri, Aug 8, 2025 at 11:17 PM Leonard Martin Struttmann via Discuss <
discuss@lists.openscad.org> wrote:

Father Horton: Regarding BOSL2: Yes! You have hit upon the key! When I was
still a corporate minion, I would write documentation based upon "Here's
what you do to produce this result." Not, "this parameter does that.".

On Fri, Aug 8, 2025 at 10:02 PM Father Horton via Discuss <
discuss@lists.openscad.org> wrote:

OpenSCAD can undoubtedly being confusing, particularly to someone who
doesn't have much (or any) background with functional programming. I, too,
don't see the need for a complete documentation rewrite. I do think an
introduction to the OpenSCAD way of thinking would be helpful.

A lot of documentation is written from what I call the "ground-up"
perspective: I'll give you all the details, and you assemble the picture. I
work better with "top-down" documentation: Here's the idea, and here's how
you implement it. Come to think of it, that's probably why I can't get my
mind around BOSL2's documentation of things like attachment.

On Fri, Aug 8, 2025 at 8:10 PM Jon Bondy via Discuss <
discuss@lists.openscad.org> wrote:

I did not find the documentation to be confusing.

Experienced OpenSCAD programmers are spending their time responding and
reacting to the content you are creating.  I am not convinced that this is
the best use of their time.

This is not a turf war.  This is about how to get quality documentation
with the minimum of effort from all involved.

Perhaps others should comment.  I have had my say.  If I am all alone,
then I will not comment further.

Jon

On 8/8/2025 9:02 PM, vulcan_--- via Discuss wrote:

Jon Bondy wrote:

I, for one, find what Vulcan is doing to be terrifying.  And I do not
have the patience to read all of the new documentation, over and over
again, trying to figure out what else has been broken.

Terrifying? Really? it is a wiki with version control. How can anything
i might do be terrifying?
I might misunderstand a thing and write something misleading .. which
someone would eventually notice and fix .. that is the absolute worst
situation that i could create.

Repeating … it is a wiki with version control .. just revert my work
out and your docs are back under your control, ‘cause i will never
contribute again.

and given the communities difficulty with a newcomer trying to
contribute maybe that is what i should do

I don't doubt that Vulcan's intentions are good, but I wonder if there
really is a problem that needs solving.

There were problems .. lots of them. When i started exploring scad i
found that pretty much every module and function I wanted to use was under
documented, even confusing in places .. I am a good tech writer and i like
to contribute where i can .. so once my examples and test scripts showed me
how to improve things in the docs i thought to contribute my insights back
to the community

I also wonder whether the community would be better off with an
experienced OpenSCAD programmer making the changes.

that would be the community’s choice to make .. but my impression is
that the experienced OpenSCAD programmers are quite busy with new features
and maintenance so documentation is well down the priority list. But okay,
if newcomers are not welcome then lock down the permissions so only the
Chosen Few can update the docs and again, the issue is solved.

I understand that the documentation should be accessible to an OpenSCAD
newbie, but I am not sure that these changes will produce the best product.

As stated .. all i need is to be able to READ the docs .. i don’t
need to contribute, and i don’t need to be on the wrong side of a
turf war

There are other tool sets i can do my 3D printing with


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=emailclient
Virus-free.www.avg.com
http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=emailclient
<#m_-8556697312187192025_m_-2042511425043668043_m_4840886636887567490_DAB4FAD8-2DD7-40BB-A1B8-4E2AA1F9FDF2>


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

The main BOSL2 manual is a reference manual, but I think the tutorials are supposed to do what you are asking. How does, for example, the Attachments tutorial fail for you? On Fri, Aug 8, 2025 at 11:17 PM Leonard Martin Struttmann via Discuss < discuss@lists.openscad.org> wrote: > Father Horton: Regarding BOSL2: Yes! You have hit upon the key! When I was > still a corporate minion, I would write documentation based upon "Here's > what you do to produce this result." Not, "this parameter does that.". > > On Fri, Aug 8, 2025 at 10:02 PM Father Horton via Discuss < > discuss@lists.openscad.org> wrote: > >> OpenSCAD can undoubtedly being confusing, particularly to someone who >> doesn't have much (or any) background with functional programming. I, too, >> don't see the need for a complete documentation rewrite. I do think an >> introduction to the OpenSCAD way of thinking would be helpful. >> >> A lot of documentation is written from what I call the "ground-up" >> perspective: I'll give you all the details, and you assemble the picture. I >> work better with "top-down" documentation: Here's the idea, and here's how >> you implement it. Come to think of it, that's probably why I can't get my >> mind around BOSL2's documentation of things like attachment. >> >> On Fri, Aug 8, 2025 at 8:10 PM Jon Bondy via Discuss < >> discuss@lists.openscad.org> wrote: >> >>> I did not find the documentation to be confusing. >>> >>> Experienced OpenSCAD programmers are spending their time responding and >>> reacting to the content you are creating. I am not convinced that this is >>> the best use of their time. >>> >>> This is not a turf war. This is about how to get quality documentation >>> with the minimum of effort from all involved. >>> >>> Perhaps others should comment. I have had my say. If I am all alone, >>> then I will not comment further. >>> >>> Jon >>> >>> >>> On 8/8/2025 9:02 PM, vulcan_--- via Discuss wrote: >>> >>> Jon Bondy wrote: >>> >>> >>> >>> I, for one, find what Vulcan is doing to be terrifying. And I do not >>> have the patience to read all of the new documentation, over and over >>> again, trying to figure out what else has been broken. >>> >>> Terrifying? Really? it is a wiki with version control. How can anything >>> i might do be terrifying? >>> I might misunderstand a thing and write something misleading .. which >>> someone would eventually notice and fix .. that is the absolute worst >>> situation that i could create. >>> >>> Repeating … it *is a wiki with version control* .. just revert my work >>> out and your docs are back under your control, ‘cause i will never >>> contribute again. >>> >>> and given the communities difficulty with a newcomer trying to >>> contribute maybe that is what i should do >>> >>> I don't doubt that Vulcan's intentions are good, but I wonder if there >>> really is a problem that needs solving. >>> >>> There were problems .. lots of them. When i started exploring scad i >>> found that pretty much every module and function I wanted to use was under >>> documented, even confusing in places .. I am a good tech writer and i like >>> to contribute where i can .. so once my examples and test scripts showed me >>> how to improve things in the docs i thought to contribute my insights back >>> to the community >>> >>> I also wonder whether the community would be better off with an >>> experienced OpenSCAD programmer making the changes. >>> >>> that would be the community’s choice to make .. but my impression is >>> that the experienced OpenSCAD programmers are quite busy with new features >>> and maintenance so documentation is well down the priority list. But okay, >>> if newcomers are not welcome then lock down the permissions so only the >>> Chosen Few can update the docs and again, the issue is solved. >>> >>> I understand that the documentation should be accessible to an OpenSCAD >>> newbie, but I am not sure that these changes will produce the best product. >>> >>> As stated .. all i *need* is to be able to READ the docs .. i don’t >>> *need* to contribute, and i don’t *need* to be on the wrong side of a >>> turf war >>> >>> There are other tool sets i can do my 3D printing with >>> >>> _______________________________________________ >>> OpenSCAD mailing list >>> To unsubscribe send an email to discuss-leave@lists.openscad.org >>> >>> >>> >>> <http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=emailclient> >>> Virus-free.www.avg.com >>> <http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=emailclient> >>> <#m_-8556697312187192025_m_-2042511425043668043_m_4840886636887567490_DAB4FAD8-2DD7-40BB-A1B8-4E2AA1F9FDF2> >>> _______________________________________________ >>> OpenSCAD mailing list >>> To unsubscribe send an email to discuss-leave@lists.openscad.org >>> >> _______________________________________________ >> OpenSCAD mailing list >> To unsubscribe send an email to discuss-leave@lists.openscad.org >> > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org >
JB
Jon Bondy
Sat, Aug 9, 2025 10:50 AM

I agree about BOSL2, but find the extensive examples sufficient for me
to pick a path and make it work.

On 8/8/2025 11:17 PM, Leonard Martin Struttmann via Discuss wrote:

Father Horton: Regarding BOSL2: Yes! You have hit upon the key! When I
was still a corporate minion, I would write documentation based upon
"Here's what you do to produce this result." Not, "this parameter
does that.".

On Fri, Aug 8, 2025 at 10:02 PM Father Horton via Discuss
discuss@lists.openscad.org wrote:

 OpenSCAD can undoubtedly being confusing, particularly to someone
 who doesn't have much (or any) background with functional
 programming. I, too, don't see the need for a complete
 documentation rewrite. I do think an introduction to the OpenSCAD
 way of thinking would be helpful.

 A lot of documentation is written from what I call the "ground-up"
 perspective: I'll give you all the details, and you assemble the
 picture. I work better with "top-down" documentation: Here's the
 idea, and here's how you implement it. Come to think of it, that's
 probably why I can't get my mind around BOSL2's documentation of
 things like attachment.

--
This email has been checked for viruses by AVG antivirus software.
www.avg.com

I agree about BOSL2, but find the extensive examples sufficient for me to pick a path and make it work. On 8/8/2025 11:17 PM, Leonard Martin Struttmann via Discuss wrote: > Father Horton: Regarding BOSL2: Yes! You have hit upon the key! When I > was still a corporate minion, I would write documentation based upon > "Here's what you do to produce this result." Not, "this parameter > does that.". > > On Fri, Aug 8, 2025 at 10:02 PM Father Horton via Discuss > <discuss@lists.openscad.org> wrote: > > OpenSCAD can undoubtedly being confusing, particularly to someone > who doesn't have much (or any) background with functional > programming. I, too, don't see the need for a complete > documentation rewrite. I do think an introduction to the OpenSCAD > way of thinking would be helpful. > > A lot of documentation is written from what I call the "ground-up" > perspective: I'll give you all the details, and you assemble the > picture. I work better with "top-down" documentation: Here's the > idea, and here's how you implement it. Come to think of it, that's > probably why I can't get my mind around BOSL2's documentation of > things like attachment. > -- This email has been checked for viruses by AVG antivirus software. www.avg.com
TA
Todd Allen
Sat, Aug 9, 2025 5:55 PM

I think BOSL2's documentation is excellent.  It is both a convenient quick
reference and the examples and tutorials provide helpful introductions to
its rich features.  I don't think there is anything particularly wrong with
OpenSCAD's documentation.  I went through it thoroughly when I first
started using OpenSCAD and it got me going fairly quickly.  But it wasn't
until I started using BOSL2 that I was able to see OpenSCAD is
sufficiently powerful to do most of what I want to do in CAD.

My biggest issue with BOSL2 is keeping up with the changes.  It's not a
problem such that I have any worry about my old scripts being broken by
updates to BOSL2.  It's rare I have to fix my old code and when I do it is
mostly because of mistakes or mistaken assumptions on my part.  But rather
I discover new features in a haphazard way sometimes long after they have
been available.  I don't blame BOSL2 for this.  I could more closely
follow the progress on github but mostly I don't as it isn't necessary.
Just sometimes I kick myself for being slow to discover there are better
ways of doing the things I have been doing.

On Sat, Aug 9, 2025 at 5:50 AM Jon Bondy via Discuss <
discuss@lists.openscad.org> wrote:

I agree about BOSL2, but find the extensive examples sufficient for me to
pick a path and make it work.

On 8/8/2025 11:17 PM, Leonard Martin Struttmann via Discuss wrote:

Father Horton: Regarding BOSL2: Yes! You have hit upon the key! When I was
still a corporate minion, I would write documentation based upon "Here's
what you do to produce this result." Not, "this parameter does that.".

On Fri, Aug 8, 2025 at 10:02 PM Father Horton via Discuss <
discuss@lists.openscad.org> wrote:

OpenSCAD can undoubtedly being confusing, particularly to someone who
doesn't have much (or any) background with functional programming. I, too,
don't see the need for a complete documentation rewrite. I do think an
introduction to the OpenSCAD way of thinking would be helpful.

A lot of documentation is written from what I call the "ground-up"
perspective: I'll give you all the details, and you assemble the picture. I
work better with "top-down" documentation: Here's the idea, and here's how
you implement it. Come to think of it, that's probably why I can't get my
mind around BOSL2's documentation of things like attachment.

I think BOSL2's documentation is excellent. It is both a convenient quick reference and the examples and tutorials provide helpful introductions to its rich features. I don't think there is anything particularly wrong with OpenSCAD's documentation. I went through it thoroughly when I first started using OpenSCAD and it got me going fairly quickly. But it wasn't until I started using BOSL2 that I was able to see OpenSCAD is sufficiently powerful to do most of what I want to do in CAD. My biggest issue with BOSL2 is keeping up with the changes. It's not a problem such that I have any worry about my old scripts being broken by updates to BOSL2. It's rare I have to fix my old code and when I do it is mostly because of mistakes or mistaken assumptions on my part. But rather I discover new features in a haphazard way sometimes long after they have been available. I don't blame BOSL2 for this. I could more closely follow the progress on github but mostly I don't as it isn't necessary. Just sometimes I kick myself for being slow to discover there are better ways of doing the things I have been doing. On Sat, Aug 9, 2025 at 5:50 AM Jon Bondy via Discuss < discuss@lists.openscad.org> wrote: > I agree about BOSL2, but find the extensive examples sufficient for me to > pick a path and make it work. > > > On 8/8/2025 11:17 PM, Leonard Martin Struttmann via Discuss wrote: > > Father Horton: Regarding BOSL2: Yes! You have hit upon the key! When I was > still a corporate minion, I would write documentation based upon "Here's > what you do to produce this result." Not, "this parameter does that.". > > On Fri, Aug 8, 2025 at 10:02 PM Father Horton via Discuss < > discuss@lists.openscad.org> wrote: > >> OpenSCAD can undoubtedly being confusing, particularly to someone who >> doesn't have much (or any) background with functional programming. I, too, >> don't see the need for a complete documentation rewrite. I do think an >> introduction to the OpenSCAD way of thinking would be helpful. >> >> A lot of documentation is written from what I call the "ground-up" >> perspective: I'll give you all the details, and you assemble the picture. I >> work better with "top-down" documentation: Here's the idea, and here's how >> you implement it. Come to think of it, that's probably why I can't get my >> mind around BOSL2's documentation of things like attachment. >> >> > > <http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=emailclient> > Virus-free.www.avg.com > <http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=emailclient> > <#m_3411324327893666859_DAB4FAD8-2DD7-40BB-A1B8-4E2AA1F9FDF2> > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org >
TA
Todd Allen
Sat, Aug 9, 2025 6:20 PM

That's absolutely true, but we have an active discussion going on about
whether we should ensure that the documentation allows for a future
where (absent $fn) it does create a true circle.

That's exciting although it would be most useful to create a true circle if
we also have true arcs and they at least sometimes survive extrusion,
transformations, booleans, hull(), minkowski(), etc. and propagate through
to an exported file.  And the next steps in our tool chain such as slicer
or CAM and the firmwares in our devices can use them.  All of which I
expect is possible but I have no sense of how hard it will be or how long
it might take.

On Fri, Aug 8, 2025 at 2:48 AM Jordan Brown openscad@jordan.maileater.net
wrote:

On 8/6/2025 4:20 PM, Todd Allen via Discuss wrote:

[ circle() ] NEVER makes a circle.  It isn't just drawn as a polygon.
It makes a polygon with the number of sides determined by the value of
special variables such as $fn or $fs and $fa.

That's absolutely true, but we have an active discussion going on about
whether we should ensure that the documentation allows for a future
where (absent $fn) it does create a true circle.

That's absolutely true, but we have an active discussion going on about whether we should ensure that the documentation allows for a future where (absent $fn) it *does* create a true circle. That's exciting although it would be most useful to create a true circle if we also have true arcs and they at least sometimes survive extrusion, transformations, booleans, hull(), minkowski(), etc. and propagate through to an exported file. And the next steps in our tool chain such as slicer or CAM and the firmwares in our devices can use them. All of which I expect is possible but I have no sense of how hard it will be or how long it might take. On Fri, Aug 8, 2025 at 2:48 AM Jordan Brown <openscad@jordan.maileater.net> wrote: > On 8/6/2025 4:20 PM, Todd Allen via Discuss wrote: > > [ circle() ] NEVER makes a circle. It isn't just drawn as a polygon. > > It makes a polygon with the number of sides determined by the value of > > special variables such as $fn or $fs and $fa. > > That's absolutely true, but we have an active discussion going on about > whether we should ensure that the documentation allows for a future > where (absent $fn) it *does* create a true circle. > >
P
pca006132
Sun, Aug 10, 2025 3:16 AM

That will be OpenCascade.

On Sun, Aug 10, 2025, 02:20 Todd Allen via Discuss <
discuss@lists.openscad.org> wrote:

That's absolutely true, but we have an active discussion going on about
whether we should ensure that the documentation allows for a future
where (absent $fn) it does create a true circle.

That's exciting although it would be most useful to create a true circle
if we also have true arcs and they at least sometimes survive extrusion,
transformations, booleans, hull(), minkowski(), etc. and propagate through
to an exported file.  And the next steps in our tool chain such as slicer
or CAM and the firmwares in our devices can use them.  All of which I
expect is possible but I have no sense of how hard it will be or how long
it might take.

On Fri, Aug 8, 2025 at 2:48 AM Jordan Brown openscad@jordan.maileater.net
wrote:

On 8/6/2025 4:20 PM, Todd Allen via Discuss wrote:

[ circle() ] NEVER makes a circle.  It isn't just drawn as a polygon.
It makes a polygon with the number of sides determined by the value of
special variables such as $fn or $fs and $fa.

That's absolutely true, but we have an active discussion going on about
whether we should ensure that the documentation allows for a future
where (absent $fn) it does create a true circle.


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

That will be OpenCascade. On Sun, Aug 10, 2025, 02:20 Todd Allen via Discuss < discuss@lists.openscad.org> wrote: > That's absolutely true, but we have an active discussion going on about > whether we should ensure that the documentation allows for a future > where (absent $fn) it *does* create a true circle. > > > That's exciting although it would be most useful to create a true circle > if we also have true arcs and they at least sometimes survive extrusion, > transformations, booleans, hull(), minkowski(), etc. and propagate through > to an exported file. And the next steps in our tool chain such as slicer > or CAM and the firmwares in our devices can use them. All of which I > expect is possible but I have no sense of how hard it will be or how long > it might take. > > On Fri, Aug 8, 2025 at 2:48 AM Jordan Brown <openscad@jordan.maileater.net> > wrote: > >> On 8/6/2025 4:20 PM, Todd Allen via Discuss wrote: >> > [ circle() ] NEVER makes a circle. It isn't just drawn as a polygon. >> > It makes a polygon with the number of sides determined by the value of >> > special variables such as $fn or $fs and $fa. >> >> That's absolutely true, but we have an active discussion going on about >> whether we should ensure that the documentation allows for a future >> where (absent $fn) it *does* create a true circle. >> >> _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org >
JB
Jordan Brown
Mon, Aug 11, 2025 5:01 PM

On 8/9/2025 1:07 AM, vulcan_--- via Discuss wrote:

Jordan, thanks for your patient help and feedback .. i have learned a
lot about functional language programming .. a sort of programming
that i knew nothing about before coming to OpenSCAD

You are welcome.

It's up to you, of course, but what I'd recommend is:

  • Continue to use OpenSCAD.  For all its faults, it really is a nearly
    unique  and powerful tool.  If you understand and accept the risks,
    and can accept a more technical installation process, consider the
    PythonSCAD https://pythonscad.org/ semi-fork.  It lets you
    construct models using OpenSCAD-like constructs, but with Python as
    the base language.
  • Hang around, only lurking if you like.  Ask questions when you have
    them - privately if you prefer.  Read the tutorial matter; there is
    no expectation that somebody can learn the language simply from the
    reference material.  The language is very different from most other
    languages, but can look deceptively similar.
  • Don't be offended if your changes get backed out. Unfortunately, you
    did introduce some errors, and your changes are so extensive that
    reviewing them requires reading every single page from zero, rather
    than just inspecting changes. Remember that, as you said, it's a
    wiki... once your OpenSCAD is stronger, you can pluck that work out
    and reuse it.
  • When you're ready to start contributing again, do it a bit more
    slowly, and do it with an eye toward reviewability.  For instance,
    if you want to split a page in half and you want to update the text,
    do it in two distinct steps.  The first step might be the split,
    without changing anything substantive about the content, while the
    second is the substantive changes (or the other way around).  That
    allows a reviewer to look only at the changes, and not be forced to
    review an entire page that was created anew.  Perhaps further split
    the substantive changes into wordsmithing and other changes that do
    not affect the meaning, and more technical changes.  Consider making
    the changes in a sandbox and ask somebody to review them before
    publishing them.  (Copy the original into the sandbox, save, then
    make changes on top of that, so that a reviewer can see the differences)
  • If you have to experiment to figure out how something works, by all
    means experiment... but do not write documentation based on your
    experiments until you talk to people about them.  Your experiments
    may not have revealed the underlying pattern, or you may have
    misinterpreted the results.
  • Similarly, if you think you've discovered an underlying pattern that
    is not discussed in the documentation, ask about it before writing
    documentation.  Maybe it's real, maybe it isn't.

Our discussions have been fun.  Take care.

PS:  I'm on a cruise and will soon be totally out of contact for the
next two to three days, so don't expect a response soon.

On 8/9/2025 1:07 AM, vulcan_--- via Discuss wrote: > > Jordan, thanks for your patient help and feedback .. i have learned a > lot about functional language programming .. a sort of programming > that i knew nothing about before coming to OpenSCAD > You are welcome. It's up to you, of course, but what I'd recommend is: * Continue to use OpenSCAD.  For all its faults, it really is a nearly unique  and powerful tool.  If you understand and accept the risks, and can accept a more technical installation process, consider the PythonSCAD <https://pythonscad.org/> semi-fork.  It lets you construct models using OpenSCAD-like constructs, but with Python as the base language. * Hang around, only lurking if you like.  Ask questions when you have them - privately if you prefer.  Read the tutorial matter; there is no expectation that somebody can learn the language simply from the reference material.  The language is very different from most other languages, but can *look* deceptively similar. * Don't be offended if your changes get backed out. Unfortunately, you did introduce some errors, and your changes are so extensive that reviewing them requires reading every single page from zero, rather than just inspecting changes. Remember that, as you said, it's a wiki... once your OpenSCAD is stronger, you can pluck that work out and reuse it. * When you're ready to start contributing again, do it a bit more slowly, and do it with an eye toward reviewability.  For instance, if you want to split a page in half and you want to update the text, do it in two distinct steps.  The first step might be the split, without changing anything substantive about the content, while the second is the substantive changes (or the other way around).  That allows a reviewer to look only at the changes, and not be forced to review an entire page that was created anew.  Perhaps further split the substantive changes into wordsmithing and other changes that do not affect the meaning, and more technical changes.  Consider making the changes in a sandbox and ask somebody to review them before publishing them.  (Copy the original into the sandbox, save, then make changes on top of that, so that a reviewer can see the differences) * If you have to experiment to figure out how something works, by all means experiment... but do not write documentation based on your experiments until you talk to people about them.  Your experiments may not have revealed the underlying pattern, or you may have misinterpreted the results. * Similarly, if you think you've discovered an underlying pattern that is not discussed in the documentation, ask about it before writing documentation.  Maybe it's real, maybe it isn't. Our discussions have been fun.  Take care. PS:  I'm on a cruise and will soon be totally out of contact for the next two to three days, so don't expect a response soon.
JB
Jordan Brown
Mon, Aug 11, 2025 5:01 PM

On 8/9/2025 6:20 PM, Todd Allen wrote:

 That's absolutely true, but we have an active discussion going on
 about
 whether we should ensure that the documentation allows for a future
 where (absent $fn) it *does* create a true circle.

That's exciting [...]

Don't get excited yet.  Nobody has stepped up to do the actual work.  I
just made a proposal to tweak the definition of the various curved
shapes so that if we eventually are able to process true curves, we
wouldn't be breaking our API commitments. (Of course, that would be by
partially backing off on them now, but that would let people have time
to adjust.)

The most aggressive things that I've considered in the short run are:

  • Having $fs and $fa default to undef or zero, and have circle() et al
    apply defaults at invocation time, so that the actual defaults used
    are less visible and so less possible to depend on.  And then set
    them to something much smaller so that you get decent circles by
    default.
  • Changing the $fa/$fs calculation so that it always rounds up to a
    multiple of 4, so that it always yields circles that touch the
    bounding box on all four sides.
  • Doing something to improve spheres.  At least make them touch their
    north and south poles, but preferably switch over to a different
    mesh entirely, e.g. via octahedral subdivision
    https://en.wikipedia.org/wiki/Geodesic_polyhedron.

although it would be most useful to create a true circle if we also
have true arcs and they at least sometimes survive extrusion,
transformations, booleans, hull(), minkowski(), etc.

Yes, that would be a requirement.

and propagate through to an exported file.

That would depend on the output format - STL is polygons-only - but yes,
that would be the goal.

And the next steps in our tool chain such as slicer or CAM and the
firmwares in our devices can use them.

Yes.  At least some devices can do gcode arcs in their firmware, which
is a good step, but I have no idea whether the slicers and CAM connect
those dots.

All of which I expect is possible but I have no sense of how hard it
will be or how long it might take.

Yes.  It's clearly theoretically possible... and equally clearly well
beyond me.

Looking at drawing programs, it looks like those operations are more or
less solved for 2D.  One of the things I have wondered is whether we
could do our 2D with true curves, and only switch to polygonal
approximations when extruding.  That would be a bit weird, but if the
defaults are fairly good circles then the difference between the true
circles and the approximations wouldn't be much.

(And of course when you explicitly set $fn you will forever get exactly
what you ask for.)

On 8/9/2025 6:20 PM, Todd Allen wrote: > > That's absolutely true, but we have an active discussion going on > about > whether we should ensure that the documentation allows for a future > where (absent $fn) it *does* create a true circle. > > > That's exciting [...] Don't get excited yet.  Nobody has stepped up to do the actual work.  I just made a proposal to tweak the definition of the various curved shapes so that if we eventually *are* able to process true curves, we wouldn't be breaking our API commitments. (Of course, that would be by partially backing off on them now, but that would let people have time to adjust.) The most aggressive things that I've considered in the short run are: * Having $fs and $fa default to undef or zero, and have circle() et al apply defaults at invocation time, so that the actual defaults used are less visible and so less possible to depend on.  And then set them to something much smaller so that you get decent circles by default. * Changing the $fa/$fs calculation so that it always rounds up to a multiple of 4, so that it always yields circles that touch the bounding box on all four sides. * Doing something to improve spheres.  At least make them touch their north and south poles, but preferably switch over to a different mesh entirely, e.g. via octahedral subdivision <https://en.wikipedia.org/wiki/Geodesic_polyhedron>. > although it would be most useful to create a true circle if we also > have true arcs and they at least sometimes survive extrusion, > transformations, booleans, hull(), minkowski(), etc. Yes, that would be a requirement. > and propagate through to an exported file. That would depend on the output format - STL is polygons-only - but yes, that would be the goal. > And the next steps in our tool chain such as slicer or CAM and the > firmwares in our devices can use them. Yes.  At least some devices can do gcode arcs in their firmware, which is a good step, but I have no idea whether the slicers and CAM connect those dots. > All of which I expect is possible but I have no sense of how hard it > will be or how long it might take. Yes.  It's clearly theoretically possible... and equally clearly well beyond me. Looking at drawing programs, it looks like those operations are more or less solved for 2D.  One of the things I have wondered is whether we could do our 2D with true curves, and only switch to polygonal approximations when extruding.  That would be a bit weird, but if the defaults are fairly good circles then the difference between the true circles and the approximations wouldn't be much. (And of course when you explicitly set $fn you will forever get exactly what you ask for.)
RW
Rogier Wolff
Mon, Aug 11, 2025 5:44 PM

On Sun, Aug 10, 2025 at 03:39:42PM +0000, Jordan Brown via Discuss wrote:

Yes.  At least some devices can do gcode arcs in their firmware, which is a
good step, but I have no idea whether the slicers and CAM connect those
dots.

Yes. I made a 2D foam cutting machine. I bought a "standard"
3D-printer-mainboard in china, installed octoprint on an orange pi
zero, and wrote the GCODE by hand (all 113 lines). I use the machine
for one specific job, so this is way easier than writing a whole
toolchain. There is one curve in the final product. Two products from
one sheet, so there are two arc commands in my GCODE and that works.

I'm using the marlin firmware that the manufacturer put in the
mainboard, so marlin already supports those arcs.

To get openscad to support curves, I'd personally recommend following
Prof. Jim Blinn's advice to just use 3rd degree splines/beziers
everywhere (one or the other: make a choice. Transform the one that
you're not natively supporting). The approximation of a circle and
sphere are then "very good", and by eye you cannot see that they are
not real circles and spheres.

What I don't remember from his class was: Is the curve you get by
intersecting two 3rd degree spline patches also a 3rd degree spline? I
suspect it is not. So that complicates things: intersecting say a
sphere and a cylinder would require you to match a bunch of new 3rd
degree splines with the 6th degree intersection curve (which is hard
to algorithmically find anyway).

Differencing a cylinder along one of the axes with a sphere of the
same radius is going to give predictable results. But rotate the
cylinder off-axis, and you might get "ugly" results, where if say the
sphere is a tiny bit larger than the cylinder, you get ugly edges
(i.e. not a circle).

For openscad the "small steps" road to this support would start with
generalizing the "triangle" between 3 points to supporting bezier/spline
patches between 4 points.

Postpone the difficult parts: When things get messy you can downgrade
the patch to triangles, e.g. to find the intersection.

If we can then export the curves when they haven't been "downgraded",
slicers can already be provided test-data for processing curves.

Roger.

--
** R.E.Wolff@BitWizard.nl ** https://www.BitWizard.nl/ ** +31-15-2049110 **
** Verl. Spiegelmakerstraat 37 2645 LZ  Delfgauw, The Netherlands.
** KVK: 27239233    **
f equals m times a. When your f is steady, and your m is going down
your a** is going up.  -- Chris Hadfield about flying up the space shuttle.
**  'a' for accelleration.

On Sun, Aug 10, 2025 at 03:39:42PM +0000, Jordan Brown via Discuss wrote: > Yes.  At least some devices can do gcode arcs in their firmware, which is a > good step, but I have no idea whether the slicers and CAM connect those > dots. Yes. I made a 2D foam cutting machine. I bought a "standard" 3D-printer-mainboard in china, installed octoprint on an orange pi zero, and wrote the GCODE by hand (all 113 lines). I use the machine for one specific job, so this is way easier than writing a whole toolchain. There is one curve in the final product. Two products from one sheet, so there are two arc commands in my GCODE and that works. I'm using the marlin firmware that the manufacturer put in the mainboard, so marlin already supports those arcs. To get openscad to support curves, I'd personally recommend following Prof. Jim Blinn's advice to just use 3rd degree splines/beziers everywhere (one or the other: make a choice. Transform the one that you're not natively supporting). The approximation of a circle and sphere are then "very good", and by eye you cannot see that they are not real circles and spheres. What I don't remember from his class was: Is the curve you get by intersecting two 3rd degree spline patches also a 3rd degree spline? I suspect it is not. So that complicates things: intersecting say a sphere and a cylinder would require you to match a bunch of new 3rd degree splines with the 6th degree intersection curve (which is hard to algorithmically find anyway). Differencing a cylinder along one of the axes with a sphere of the same radius is going to give predictable results. But rotate the cylinder off-axis, and you might get "ugly" results, where if say the sphere is a tiny bit larger than the cylinder, you get ugly edges (i.e. not a circle). For openscad the "small steps" road to this support would start with generalizing the "triangle" between 3 points to supporting bezier/spline patches between 4 points. Postpone the difficult parts: When things get messy you can downgrade the patch to triangles, e.g. to find the intersection. If we can then export the curves when they haven't been "downgraded", slicers can already be provided test-data for processing curves. Roger. -- ** R.E.Wolff@BitWizard.nl ** https://www.BitWizard.nl/ ** +31-15-2049110 ** ** Verl. Spiegelmakerstraat 37 2645 LZ Delfgauw, The Netherlands. ** KVK: 27239233 ** f equals m times a. When your f is steady, and your m is going down your a** is going up. -- Chris Hadfield about flying up the space shuttle. ** 'a' for accelleration.
V
vulcan_@mac.com
Tue, Aug 12, 2025 12:45 PM

Jordan Brown wrote:

On 8/9/2025 1:07 AM, vulcan_--- via Discuss wrote:

Jordan, thanks for your patient help and feedback .. i have learned a

You are welcome.

It's up to you, of course, but what I'd recommend is:

  • Continue to use OpenSCAD.  For all its faults,

i am not a fan of python and have little practice with it, and trying to use a functional language implemented in a procedural one?? .. naahh .. I am going to explore the use BOSL2 and NopSCADlib and possibly others .. my tinkering with the relativity.scad library is what got me into scad

  • Hang around, only lurking if you like.  Ask questions when you have
    them - privately if you prefer.  Read the tutorial matter; there is
    no expectation that somebody can learn the language simply from the
    reference material. 

here we differ. i absolutely expect just that .. if the reference for the language is not enough to completely understand and use it, the documentation has failed its purpose.

  • The language is very different from most other
    languages, but can look deceptively similar.

And all those potential misunderstandings should be noted on every page where experience has revealed them.

  • Don't be offended if your changes get backed out.

I would have welcomed any and all input from anyone building on my work .. and would not been “miffed” seeing my mistakes reverted.
My experience with teamwork is varied and extensive .. i am well able to work collaboratively, which is to say I
know how to contribute without exerting ownership and without investing my ego in my work product.

What I won’t do is be where i am not welcome nor with people who are rude and possessive.

I did contribute in an overly aggressive manner, now obvious in hindsight .. but some people, your kind self, amatulicm, Kintel and a few others .. provided constructive feedback and allowed me to fix what i had broken .. but the rest of the group have made it clear they don’t play well with newcomers and i am not about to try pushing on a rope.

  • When you're ready to start contributing again,

That wont be happening

Your tips on Way of Work are good ones and i have preserved them in my notes on documentation practice.

Our discussions have been fun.  Take care.

And I have enjoyed them too .. i will reach out privately when you are returned from your cruise

many thanks

Jeff

Jordan Brown wrote: > On 8/9/2025 1:07 AM, vulcan_--- via Discuss wrote: > > > Jordan, thanks for your patient help and feedback .. i have learned a > > > > You are welcome. > > It's up to you, of course, but what I'd recommend is: > > * Continue to use OpenSCAD.  For all its faults, i am not a fan of python and have little practice with it, and trying to use a functional language implemented in a procedural one?? .. naahh .. I am going to explore the use BOSL2 and NopSCADlib and possibly others .. my tinkering with the relativity.scad library is what got me into scad > * Hang around, only lurking if you like.  Ask questions when you have > them - privately if you prefer.  Read the tutorial matter; there is > no expectation that somebody can learn the language simply from the > reference material.  here we differ. i *absolutely* expect just that .. if the *reference* for the language is not enough to completely understand and use it, the documentation has failed its purpose. > * The language is very different from most other > languages, but can *look* deceptively similar. And all those potential misunderstandings should be noted on every page where experience has revealed them. > * Don't be offended if your changes get backed out. I would have welcomed any and all input from anyone building on my work .. and would not been “miffed” seeing my mistakes reverted.\ My experience with teamwork is varied and extensive .. i am well able to work collaboratively, which is to say I \ know how to contribute without exerting ownership and without investing my ego in my work product. What I won’t do is be where i am not welcome nor with people who are rude and possessive. I did contribute in an overly aggressive manner, now obvious in hindsight .. but some people, your kind self, amatulicm, Kintel and a few others .. provided constructive feedback and allowed me to fix what i had broken .. but the rest of the group have made it clear they don’t play well with newcomers and i am not about to try pushing on a rope. > * When you're ready to start contributing again, That wont be happening Your tips on Way of Work are good ones and i have preserved them in my notes on documentation practice. > Our discussions have been fun.  Take care. And I have enjoyed them too .. i will reach out privately when you are returned from your cruise many thanks Jeff
NH
nop head
Tue, Aug 12, 2025 1:13 PM

I don't think a language reference should be used for learning a language.
That is for tutorials and books. Marius has written a book about OpenSCAD.

The reference is for looking up exact details about a module or function
when one can't remember the name or arguments.

On Tue, 12 Aug 2025, 13:45 vulcan_--- via Discuss, <
discuss@lists.openscad.org> wrote:

Jordan Brown wrote:

On 8/9/2025 1:07 AM, vulcan_--- via Discuss wrote:

Jordan, thanks for your patient help and feedback .. i have learned a

You are welcome.

It's up to you, of course, but what I'd recommend is:

-

Continue to use OpenSCAD.  For all its faults,

i am not a fan of python and have little practice with it, and trying to
use a functional language implemented in a procedural one?? .. naahh .. I
am going to explore the use BOSL2 and NopSCADlib and possibly others .. my
tinkering with the relativity.scad library is what got me into scad

-

Hang around, only lurking if you like.  Ask questions when you have
them - privately if you prefer.  Read the tutorial matter; there is no
expectation that somebody can learn the language simply from the reference
material.

here we differ. i absolutely expect just that .. if the reference for
the language is not enough to completely understand and use it, the
documentation has failed its purpose.

-

The language is very different from most other languages, but can
*look* deceptively similar.

And all those potential misunderstandings should be noted on every page
where experience has revealed them.

-

Don't be offended if your changes get backed out.

I would have welcomed any and all input from anyone building on my work ..
and would not been “miffed” seeing my mistakes reverted.
My experience with teamwork is varied and extensive .. i am well able to
work collaboratively, which is to say I
know how to contribute without exerting ownership and without investing my
ego in my work product.

What I won’t do is be where i am not welcome nor with people who are rude
and possessive.

I did contribute in an overly aggressive manner, now obvious in hindsight
.. but some people, your kind self, amatulicm, Kintel and a few others ..
provided constructive feedback and allowed me to fix what i had broken ..
but the rest of the group have made it clear they don’t play well with
newcomers and i am not about to try pushing on a rope.

-

When you're ready to start contributing again,

That wont be happening

Your tips on Way of Work are good ones and i have preserved them in my
notes on documentation practice.

Our discussions have been fun.  Take care.

And I have enjoyed them too .. i will reach out privately when you are
returned from your cruise

many thanks

Jeff


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

I don't think a language reference should be used for learning a language. That is for tutorials and books. Marius has written a book about OpenSCAD. The reference is for looking up exact details about a module or function when one can't remember the name or arguments. On Tue, 12 Aug 2025, 13:45 vulcan_--- via Discuss, < discuss@lists.openscad.org> wrote: > Jordan Brown wrote: > > On 8/9/2025 1:07 AM, vulcan_--- via Discuss wrote: > > Jordan, thanks for your patient help and feedback .. i have learned a > > You are welcome. > > It's up to you, of course, but what I'd recommend is: > > - > > Continue to use OpenSCAD. For all its faults, > > i am not a fan of python and have little practice with it, and trying to > use a functional language implemented in a procedural one?? .. naahh .. I > am going to explore the use BOSL2 and NopSCADlib and possibly others .. my > tinkering with the relativity.scad library is what got me into scad > > > - > > Hang around, only lurking if you like. Ask questions when you have > them - privately if you prefer. Read the tutorial matter; there is no > expectation that somebody can learn the language simply from the reference > material. > > here we differ. i *absolutely* expect just that .. if the *reference* for > the language is not enough to completely understand and use it, the > documentation has failed its purpose. > > > - > > The language is very different from most other languages, but can > *look* deceptively similar. > > And all those potential misunderstandings should be noted on every page > where experience has revealed them. > > > - > > Don't be offended if your changes get backed out. > > I would have welcomed any and all input from anyone building on my work .. > and would not been “miffed” seeing my mistakes reverted. > My experience with teamwork is varied and extensive .. i am well able to > work collaboratively, which is to say I > know how to contribute without exerting ownership and without investing my > ego in my work product. > > What I won’t do is be where i am not welcome nor with people who are rude > and possessive. > > I did contribute in an overly aggressive manner, now obvious in hindsight > .. but some people, your kind self, amatulicm, Kintel and a few others .. > provided constructive feedback and allowed me to fix what i had broken .. > but the rest of the group have made it clear they don’t play well with > newcomers and i am not about to try pushing on a rope. > > > - > > When you're ready to start contributing again, > > That wont be happening > > Your tips on Way of Work are good ones and i have preserved them in my > notes on documentation practice. > > Our discussions have been fun. Take care. > > And I have enjoyed them too .. i will reach out privately when you are > returned from your cruise > > many thanks > > Jeff > > > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org >
WF
William F. Adams
Tue, Aug 12, 2025 1:58 PM

On Tuesday, August 12, 2025 at 09:14:44 AM EDT, nop head via Discuss discuss@lists.openscad.org wrote:

I don't think a language reference should be used for learning a language. That is for tutorials and books. Marius has written a book about OpenSCAD.

The reference is for looking up exact details about a module or function when one can't remember the name or arguments.

There is an interesting tension on that and one which programming systems seem to have a difficult time balancing.

One site which discusses this is: https://diataxis.fr/ which divides documentation between:

 - Tutorials/Learning
 - How-to Guides/Goals
 - Explanation/Understanding
 - Reference/Information

and working out how each differing need will be addressed is a hurdle which any successful project needs to clear.

For OpenSCAD, this difficulty is even more mired in a fundamental set of divisions:

 - OpenSCAD makes modeling designs using rectangles, cylinders and spheres using mathematically calculated placements and distortions and arrangements simple
 - the usage of OpenSCAD is strongly bounded by the user's knowledge of mathematics, their fluency with the programming constructs which which OpenSCAD affords, and their ability to find modules/libraries/existing projects w/ Customization options which meet their needs
 - the functional programming methodology places some hard limits on modifying state for projects where such a division would be helpful
 
That last is neatly addressed by either programming in a second language and generating OpenSCAD code, or using a second language w/in OpenSCAD as is done by (Open)PythonSCAD: https://pythonscad.org/ with a simply amazing example of this being:

https://old.reddit.com/r/OpenPythonSCAD/comments/1mn2nrd/cool_mech_kinematics_script_in_pythonscad/

which shows the potential of moving beyond OpenSCAD.

I will note that in addition to Marius' wonderful book: https://nostarch.com/programmingopenscad (I've bought multiple copies for the children of co-workers, and just bought the Kindle version at full-price which I rarely purchase at) there is a series of books which looks at mathematics and uses OpenSCAD and 3D printing to enhance the lessons:

 - Geometry: https://www.goodreads.com/book/show/58059196-make
 - Trigonometry: https://www.goodreads.com/book/show/123127774-make
 - Calculus: https://www.goodreads.com/book/show/61739368-make

which I found very helpful and recommend highly. What other books are folks finding useful?

Since documentation is an aspect of my current project which I am still having difficulty with, I would be glad of further thoughts and comments on this.

William

On Tuesday, August 12, 2025 at 09:14:44 AM EDT, nop head via Discuss <discuss@lists.openscad.org> wrote: >I don't think a language reference should be used for learning a language. That is for tutorials and books. Marius has written a book about OpenSCAD. > >The reference is for looking up exact details about a module or function when one can't remember the name or arguments. There is an interesting tension on that and one which programming systems seem to have a difficult time balancing. One site which discusses this is: https://diataxis.fr/ which divides documentation between:  - Tutorials/Learning  - How-to Guides/Goals  - Explanation/Understanding  - Reference/Information and working out how each differing need will be addressed is a hurdle which any successful project needs to clear. For OpenSCAD, this difficulty is even more mired in a fundamental set of divisions:  - OpenSCAD makes modeling designs using rectangles, cylinders and spheres using mathematically calculated placements and distortions and arrangements simple  - the usage of OpenSCAD is strongly bounded by the user's knowledge of mathematics, their fluency with the programming constructs which which OpenSCAD affords, and their ability to find modules/libraries/existing projects w/ Customization options which meet their needs  - the functional programming methodology places some hard limits on modifying state for projects where such a division would be helpful   That last is neatly addressed by either programming in a second language and generating OpenSCAD code, or using a second language w/in OpenSCAD as is done by (Open)PythonSCAD: https://pythonscad.org/ with a simply amazing example of this being: https://old.reddit.com/r/OpenPythonSCAD/comments/1mn2nrd/cool_mech_kinematics_script_in_pythonscad/ which shows the potential of moving beyond OpenSCAD. I will note that in addition to Marius' wonderful book: https://nostarch.com/programmingopenscad (I've bought multiple copies for the children of co-workers, and just bought the Kindle version at full-price which I rarely purchase at) there is a series of books which looks at mathematics and uses OpenSCAD and 3D printing to enhance the lessons:  - Geometry: https://www.goodreads.com/book/show/58059196-make  - Trigonometry: https://www.goodreads.com/book/show/123127774-make  - Calculus: https://www.goodreads.com/book/show/61739368-make which I found very helpful and recommend highly. What other books are folks finding useful? Since documentation is an aspect of my current project which I am still having difficulty with, I would be glad of further thoughts and comments on this. William
SP
Sanjeev Prabhakar
Tue, Aug 12, 2025 4:46 PM

Seems to be some interesting reference books William.

It is always better retention if you learn by doing.

Documentation is a very difficult part, at least for me. I think if there
are some simple and good examples, it is easier to follow, rather than
reading too much text, but again it is a personal choice. Few people would
like to first understand the concept completely and clearly before trying.

Example you shared is interesting. I think this is done through pythonscad.

Python is definitely a much structured language and much more powerful
compared to openSCAD and I would recommend others to also try it.

Appeal of openSCAD is in its simplicity and is much better for starters.

But once things start getting complex ( which definitely will start after a
few days of using openscad) then the natural path would be migrating to
languages like python.

There is so much development done on python and with many libraries
available, it can do a lot more.

Regards
Sanjeev

On Tue, 12 Aug 2025 at 19:28, William F. Adams via Discuss <
discuss@lists.openscad.org> wrote:

On Tuesday, August 12, 2025 at 09:14:44 AM EDT, nop head via Discuss <
discuss@lists.openscad.org> wrote:

I don't think a language reference should be used for learning a

language. That is for tutorials and books. Marius has written a book about
OpenSCAD.

The reference is for looking up exact details about a module or function

when one can't remember the name or arguments.

There is an interesting tension on that and one which programming systems
seem to have a difficult time balancing.

One site which discusses this is: https://diataxis.fr/ which divides
documentation between:

  • Tutorials/Learning
  • How-to Guides/Goals
  • Explanation/Understanding
  • Reference/Information

and working out how each differing need will be addressed is a hurdle
which any successful project needs to clear.

For OpenSCAD, this difficulty is even more mired in a fundamental set of
divisions:

  • OpenSCAD makes modeling designs using rectangles, cylinders and spheres
    using mathematically calculated placements and distortions and arrangements
    simple
  • the usage of OpenSCAD is strongly bounded by the user's knowledge of
    mathematics, their fluency with the programming constructs which which
    OpenSCAD affords, and their ability to find modules/libraries/existing
    projects w/ Customization options which meet their needs
  • the functional programming methodology places some hard limits on
    modifying state for projects where such a division would be helpful

That last is neatly addressed by either programming in a second language
and generating OpenSCAD code, or using a second language w/in OpenSCAD as
is done by (Open)PythonSCAD: https://pythonscad.org/ with a simply
amazing example of this being:

https://old.reddit.com/r/OpenPythonSCAD/comments/1mn2nrd/cool_mech_kinematics_script_in_pythonscad/

which shows the potential of moving beyond OpenSCAD.

I will note that in addition to Marius' wonderful book:
https://nostarch.com/programmingopenscad (I've bought multiple copies for
the children of co-workers, and just bought the Kindle version at
full-price which I rarely purchase at) there is a series of books which
looks at mathematics and uses OpenSCAD and 3D printing to enhance the
lessons:

which I found very helpful and recommend highly. What other books are
folks finding useful?

Since documentation is an aspect of my current project which I am still
having difficulty with, I would be glad of further thoughts and comments on
this.

William


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

Seems to be some interesting reference books William. It is always better retention if you learn by doing. Documentation is a very difficult part, at least for me. I think if there are some simple and good examples, it is easier to follow, rather than reading too much text, but again it is a personal choice. Few people would like to first understand the concept completely and clearly before trying. Example you shared is interesting. I think this is done through pythonscad. Python is definitely a much structured language and much more powerful compared to openSCAD and I would recommend others to also try it. Appeal of openSCAD is in its simplicity and is much better for starters. But once things start getting complex ( which definitely will start after a few days of using openscad) then the natural path would be migrating to languages like python. There is so much development done on python and with many libraries available, it can do a lot more. Regards Sanjeev On Tue, 12 Aug 2025 at 19:28, William F. Adams via Discuss < discuss@lists.openscad.org> wrote: > On Tuesday, August 12, 2025 at 09:14:44 AM EDT, nop head via Discuss < > discuss@lists.openscad.org> wrote: > > >I don't think a language reference should be used for learning a > language. That is for tutorials and books. Marius has written a book about > OpenSCAD. > > > >The reference is for looking up exact details about a module or function > when one can't remember the name or arguments. > > > There is an interesting tension on that and one which programming systems > seem to have a difficult time balancing. > > One site which discusses this is: https://diataxis.fr/ which divides > documentation between: > > - Tutorials/Learning > - How-to Guides/Goals > - Explanation/Understanding > - Reference/Information > > and working out how each differing need will be addressed is a hurdle > which any successful project needs to clear. > > For OpenSCAD, this difficulty is even more mired in a fundamental set of > divisions: > > - OpenSCAD makes modeling designs using rectangles, cylinders and spheres > using mathematically calculated placements and distortions and arrangements > simple > - the usage of OpenSCAD is strongly bounded by the user's knowledge of > mathematics, their fluency with the programming constructs which which > OpenSCAD affords, and their ability to find modules/libraries/existing > projects w/ Customization options which meet their needs > - the functional programming methodology places some hard limits on > modifying state for projects where such a division would be helpful > > That last is neatly addressed by either programming in a second language > and generating OpenSCAD code, or using a second language w/in OpenSCAD as > is done by (Open)PythonSCAD: https://pythonscad.org/ with a simply > amazing example of this being: > > > https://old.reddit.com/r/OpenPythonSCAD/comments/1mn2nrd/cool_mech_kinematics_script_in_pythonscad/ > > which shows the potential of moving beyond OpenSCAD. > > I will note that in addition to Marius' wonderful book: > https://nostarch.com/programmingopenscad (I've bought multiple copies for > the children of co-workers, and just bought the Kindle version at > full-price which I rarely purchase at) there is a series of books which > looks at mathematics and uses OpenSCAD and 3D printing to enhance the > lessons: > > - Geometry: https://www.goodreads.com/book/show/58059196-make > - Trigonometry: https://www.goodreads.com/book/show/123127774-make > - Calculus: https://www.goodreads.com/book/show/61739368-make > > which I found very helpful and recommend highly. What other books are > folks finding useful? > > Since documentation is an aspect of my current project which I am still > having difficulty with, I would be glad of further thoughts and comments on > this. > > William > > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org >
V
vulcan_@mac.com
Tue, Aug 12, 2025 9:45 PM

nop head wrote:

I don't think a language reference should be used for learning a language.
That is for tutorials and books. Marius has written a book about OpenSCAD.

The reference is for looking up exact details about a module or function
when one can't remember the name or arguments.

When i started working with scad the lang ref was not completely useful for those purposes .. it was good in places, incomplete in others, and erroneous in a few. The argument list completion feature of the editor showed me that changes to some modules had not been documented. The list of math functions included str(), ord() and other non-math functions and the descriptions of the operators were sketchy.

The section on user-defined functions did not make clear that there is only one type of module .. the docs on the children() function do not say it can be used to give any module access to its children and the descriptions of the built-in modules separate them into shape creating modules and operators .. which mislead me completely. The descriptions of assert(), echo() and let() did not say they were also modules, but can also be used in expressions as if they were operators  .. and in fact that if-then-else and for-loop were modules too. In fact, the description of  if-then-else and for-loop presented them as if they were statements in a procedural language, to me at least.

just this last week it came clear to me that the syntax for the use of a module has two parts, parent and child:

parent_module( <arg list> ) child_module( <arg list> );

meaning that the call to a module is followed by an optional call to a child module. And then, the child_module, being a module, may then also have a child etc etc
OR, using braces can make a parent apply to a whole bunch of children, like this:

parent_module( <arg list> ) { child_module_1( <arg list> ); child_module_2( <arg list> ); … };

where each child_module_*() statement might have a whole hierarchy of shapes and transforms

None of which is explained in either the tutorials or the lang ref.
Or at least .. i did not see it .. it took several lengthy conversations with Jordan and a few others in these threads to make this all clear.

As for the tutorials .. There are explanations of language features that are ONLY in the tutorials and make use of features without explaining them .. for example .. the specials $fa and $fs .. they appear at the beginning of a lot of the code examples but their importance to making the circular objects look round is never connected.

The importance of recursion to functional programming as a replacement for looping in a procedural language is not covered in the tutorials at all .. but it is a heavily used technique in the relativity.scad library .. which is how i learned about it .. not by doing the tutorials, and not by reading the language reference

But then, i think i should be able to learn all about a language by reading about it in its reference document.

nop head wrote: > I don't think a language reference should be used for learning a language. > That is for tutorials and books. Marius has written a book about OpenSCAD. > > The reference is for looking up exact details about a module or function > when one can't remember the name or arguments. When i started working with scad the lang ref was not completely useful for those purposes .. it was good in places, incomplete in others, and erroneous in a few. The argument list completion feature of the editor showed me that changes to some modules had not been documented. The list of math functions included str(), ord() and other non-math functions and the descriptions of the operators were sketchy. The section on user-defined functions did not make clear that there is only *one* type of module .. the docs on the children() function do not say it can be used to give *any* module access to its children and the descriptions of the built-in modules separate them into shape creating modules and operators .. which mislead me completely. The descriptions of assert(), echo() and let() did not say they were *also* modules, but can also be used in expressions as if they were operators .. and in fact that if-then-else and for-loop were modules too. In fact, the description of if-then-else and for-loop presented them as if they were statements in a procedural language, to me at least. just this last week it came clear to me that the syntax for the use of a module has two parts, parent and child: parent_module( <arg list> ) child_module( <arg list> ); meaning that the call to a module is followed by an optional call to a child module. And then, the child_module, being a module, may then also have a child etc etc\ OR, using braces can make a parent apply to a whole bunch of children, like this: parent_module( <arg list> ) { child_module_1( <arg list> ); child_module_2( <arg list> ); … }; where each child_module_\*() statement might have a whole hierarchy of shapes and transforms None of which is explained in either the tutorials or the lang ref.\ Or at least .. i did not see it .. it took several lengthy conversations with Jordan and a few others in these threads to make this all clear. As for the tutorials .. There are explanations of language features that are ONLY in the tutorials and make use of features without explaining them .. for example .. the specials $fa and $fs .. they appear at the beginning of a lot of the code examples but their importance to making the circular objects look round is never connected. The importance of recursion to functional programming as a replacement for looping in a procedural language is not covered in the tutorials at all .. but it is a heavily used technique in the relativity.scad library .. which is how i learned about it .. not by doing the tutorials, and not by reading the language reference But then, i think i should be able to learn all about a language by reading about it in its reference document.
V
vulcan_@mac.com
Tue, Aug 12, 2025 9:45 PM

nop head wrote:

I don't think a language reference should be used for learning a language.
That is for tutorials and books. Marius has written a book about OpenSCAD.

The reference is for looking up exact details about a module or function
when one can't remember the name or arguments.

When i started working with scad the lang ref was not completely useful for those purposes .. it was good in places, incomplete in others, and erroneous in a few. The argument list completion feature of the editor showed me that changes to some modules had not been documented. The list of math functions included str(), ord() and other non-math functions and the descriptions of the operators were sketchy.

The section on user-defined functions did not make clear that there is only one type of module .. the docs on the children() function do not say it can be used to give any module access to its children and the descriptions of the built-in modules separate them into shape creating modules and operators .. which mislead me completely. The descriptions of assert(), echo() and let() did not say they were also modules, but can also be used in expressions as if they were operators  .. and in fact that if-then-else and for-loop were modules too. In fact, the description of  if-then-else and for-loop presented them as if they were statements in a procedural language, to me at least.

just this last week it came clear to me that the syntax for the use of a module has two parts, parent and child:

parent_module( <arg list> ) child_module( <arg list> );

meaning that the call to a module is followed by an optional call to a child module. And then, the child_module, being a module, may then also have a child etc etc
OR, using braces can make a parent apply to a whole bunch of children, like this:

parent_module( <arg list> ) { child_module_1( <arg list> ); child_module_2( <arg list> ); … };

where each child_module_*() statement might have a whole hierarchy of shapes and transforms

None of which is explained in either the tutorials or the lang ref.
Or at least .. i did not see it .. it took several lengthy conversations with Jordan and a few others in these threads to make this all clear.

As for the tutorials .. There are explanations of language features that are ONLY in the tutorials and make use of features without explaining them .. for example .. the specials $fa and $fs .. they appear at the beginning of a lot of the code examples but their importance to making the circular objects look round is never connected.

The importance of recursion to functional programming as a replacement for looping in a procedural language is not covered in the tutorials at all .. but it is a heavily used technique in the relativity.scad library .. which is how i learned about it .. not by doing the tutorials, and not by reading the language reference

But then, i think i should be able to learn all about a language by reading about it in its reference document.

nop head wrote: > I don't think a language reference should be used for learning a language. > That is for tutorials and books. Marius has written a book about OpenSCAD. > > The reference is for looking up exact details about a module or function > when one can't remember the name or arguments. When i started working with scad the lang ref was not completely useful for those purposes .. it was good in places, incomplete in others, and erroneous in a few. The argument list completion feature of the editor showed me that changes to some modules had not been documented. The list of math functions included str(), ord() and other non-math functions and the descriptions of the operators were sketchy. The section on user-defined functions did not make clear that there is only *one* type of module .. the docs on the children() function do not say it can be used to give *any* module access to its children and the descriptions of the built-in modules separate them into shape creating modules and operators .. which mislead me completely. The descriptions of assert(), echo() and let() did not say they were *also* modules, but can also be used in expressions as if they were operators .. and in fact that if-then-else and for-loop were modules too. In fact, the description of if-then-else and for-loop presented them as if they were statements in a procedural language, to me at least. just this last week it came clear to me that the syntax for the use of a module has two parts, parent and child: parent_module( <arg list> ) child_module( <arg list> ); meaning that the call to a module is followed by an optional call to a child module. And then, the child_module, being a module, may then also have a child etc etc\ OR, using braces can make a parent apply to a whole bunch of children, like this: parent_module( <arg list> ) { child_module_1( <arg list> ); child_module_2( <arg list> ); … }; where each child_module_\*() statement might have a whole hierarchy of shapes and transforms None of which is explained in either the tutorials or the lang ref.\ Or at least .. i did not see it .. it took several lengthy conversations with Jordan and a few others in these threads to make this all clear. As for the tutorials .. There are explanations of language features that are ONLY in the tutorials and make use of features without explaining them .. for example .. the specials $fa and $fs .. they appear at the beginning of a lot of the code examples but their importance to making the circular objects look round is never connected. The importance of recursion to functional programming as a replacement for looping in a procedural language is not covered in the tutorials at all .. but it is a heavily used technique in the relativity.scad library .. which is how i learned about it .. not by doing the tutorials, and not by reading the language reference But then, i think i should be able to learn all about a language by reading about it in its reference document.
V
vulcan_@mac.com
Tue, Aug 12, 2025 9:48 PM

now idea why my reply to Nop appears two times .. sorry for the spam

now idea why my reply to Nop appears two times .. sorry for the spam
SL
Steve Lelievre
Tue, Aug 12, 2025 10:26 PM

On 2025-08-12 2:45 p.m., vulcan_--- via Discuss wrote:

The section on user-defined functions did not make clear that there is
only /one/ type of module .. the docs on the children() function do
not say it can be used to give /any/ module access to its children

Maybe the comment is meant to relate only to the narrow context of
user-defined modules or maybe I've misunderstood where the discussion
has got to, but in the general sense is there really only one type of
module? In my simplistic world view, there are two: primitive modules
that create shapes, and modifier modules that do things to shapes. My
distinction arises because some (native) modules accept children, some
do not. For example OpenSCAD, sensibly, rejects:  cube(1) sphere(1);

Steve

On 2025-08-12 2:45 p.m., vulcan_--- via Discuss wrote: > > The section on user-defined functions did not make clear that there is > only /one/ type of module .. the docs on the children() function do > not say it can be used to give /any/ module access to its children > Maybe the comment is meant to relate only to the narrow context of user-defined modules or maybe I've misunderstood where the discussion has got to, but in the general sense is there really only one type of module? In my simplistic world view, there are two: primitive modules that create shapes, and modifier modules that do things to shapes. My distinction arises because some (native) modules accept children, some do not. For example OpenSCAD, sensibly, rejects:  cube(1) sphere(1); Steve
FH
Father Horton
Tue, Aug 12, 2025 10:35 PM

Few people would like to first understand the concept completely and
clearly before trying.

I might be one of the few people. I guess this would be my gripe with the

BOSL2 attachment documentation. I have a tough time building a mental model
into which the pieces fit.

Most programmers probably think differently.

> > Few people would like to first understand the concept completely and > clearly before trying. > > I might be one of the few people. I guess this would be my gripe with the BOSL2 attachment documentation. I have a tough time building a mental model into which the pieces fit. Most programmers probably think differently.
LM
Leonard Martin Struttmann
Wed, Aug 13, 2025 3:32 AM

I have a tough time building a mental model into which the pieces fit.

I agree, Father Horton. I've gone through the documentation and the
supplied examples several times. I think that I finally understand the
intent of attachments. However, I have yet to find a use-case in my
projects where attachments are easier than the native translate()/rotate()
OpenSCAD primitives.

Also, looking at the number of functions/modules that are documented as
part of attachments in the documentation at...
https://github.com/BelfrySCAD/BOSL2/wiki/attachments.scad
...just... overwhelms me.

On Tue, Aug 12, 2025 at 5:35 PM Father Horton via Discuss <
discuss@lists.openscad.org> wrote:

Few people would like to first understand the concept completely and

clearly before trying.

I might be one of the few people. I guess this would be my gripe with the

BOSL2 attachment documentation. I have a tough time building a mental model
into which the pieces fit.

Most programmers probably think differently.


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

*I have a tough time building a mental model into which the pieces fit.* I agree, Father Horton. I've gone through the documentation and the supplied examples several times. I think that I finally understand the intent of attachments. However, I have yet to find a use-case in my projects where attachments are easier than the native translate()/rotate() OpenSCAD primitives. Also, looking at the number of functions/modules that are documented as part of attachments in the documentation at... https://github.com/BelfrySCAD/BOSL2/wiki/attachments.scad ...just... overwhelms me. On Tue, Aug 12, 2025 at 5:35 PM Father Horton via Discuss < discuss@lists.openscad.org> wrote: > Few people would like to first understand the concept completely and >> clearly before trying. >> >> I might be one of the few people. I guess this would be my gripe with the > BOSL2 attachment documentation. I have a tough time building a mental model > into which the pieces fit. > > Most programmers probably think differently. > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org >
JB
Jordan Brown
Wed, Aug 13, 2025 7:21 AM

Sigh.  I HATE the way that the mailing list is configured, that it defeats the mail client “reply to sender” feature and tricks you into sending intended-to-be-private messages to the whole world.

My heartfelt apologies to Jeff for accidentally sending this to the mailing list.

Sigh. I HATE the way that the mailing list is configured, that it defeats the mail client “reply to sender” feature and tricks you into sending intended-to-be-private messages to the whole world. My heartfelt apologies to Jeff for accidentally sending this to the mailing list.
JB
Jon Bondy
Wed, Aug 13, 2025 10:19 AM

I agree.  I have been caught in this trap more than once.  The mailing
list is very frustrating.

On 8/13/2025 3:21 AM, Jordan Brown via Discuss wrote:

Sigh.  I HATE the way that the mailing list is configured, that it defeats the mail client “reply to sender” feature and tricks you into sending intended-to-be-private messages to the whole world.

My heartfelt apologies to Jeff for accidentally sending this to the mailing list.


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

--
This email has been checked for viruses by AVG antivirus software.
www.avg.com

I agree.  I have been caught in this trap more than once.  The mailing list is very frustrating. On 8/13/2025 3:21 AM, Jordan Brown via Discuss wrote: > Sigh. I HATE the way that the mailing list is configured, that it defeats the mail client “reply to sender” feature and tricks you into sending intended-to-be-private messages to the whole world. > > My heartfelt apologies to Jeff for accidentally sending this to the mailing list. > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org -- This email has been checked for viruses by AVG antivirus software. www.avg.com
JD
John David
Wed, Aug 13, 2025 12:16 PM

I have been caught in this as well.  I wonder if it can be reconfigured as
"reply" to send to the poster, and "reply all" to send to everyone.

On Wed, Aug 13, 2025 at 6:19 AM Jon Bondy via Discuss <
discuss@lists.openscad.org> wrote:

I agree.  I have been caught in this trap more than once.  The mailing
list is very frustrating.

On 8/13/2025 3:21 AM, Jordan Brown via Discuss wrote:

Sigh.  I HATE the way that the mailing list is configured, that it

defeats the mail client “reply to sender” feature and tricks you into
sending intended-to-be-private messages to the whole world.

My heartfelt apologies to Jeff for accidentally sending this to the

mailing list.


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

--
This email has been checked for viruses by AVG antivirus software.
www.avg.com


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

I have been caught in this as well. I wonder if it can be reconfigured as "reply" to send to the poster, and "reply all" to send to everyone. On Wed, Aug 13, 2025 at 6:19 AM Jon Bondy via Discuss < discuss@lists.openscad.org> wrote: > I agree. I have been caught in this trap more than once. The mailing > list is very frustrating. > > > On 8/13/2025 3:21 AM, Jordan Brown via Discuss wrote: > > Sigh. I HATE the way that the mailing list is configured, that it > defeats the mail client “reply to sender” feature and tricks you into > sending intended-to-be-private messages to the whole world. > > > > My heartfelt apologies to Jeff for accidentally sending this to the > mailing list. > > _______________________________________________ > > OpenSCAD mailing list > > To unsubscribe send an email to discuss-leave@lists.openscad.org > > -- > This email has been checked for viruses by AVG antivirus software. > www.avg.com > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org >
JB
Jordan Brown
Wed, Aug 13, 2025 12:46 PM

On 8/13/2025 1:16 PM, John David via Discuss wrote:

I have been caught in this as well.  I wonder if it can be
reconfigured as "reply" to send to the poster, and "reply all" to send
to everyone.

I'm pretty sure that it can be - it's a MailMan instance, and although I
am not familiar with MailMan 3 I used to administer a couple of MailMan
2 mailing lists, and it's a separate setting there.  (It's easy to think
that it's tied to the DMARC handling, which also rearranges the From
header, but it's not.  The good DMARC configuration is to set From to
the mailing list, so that providers don't think that the message is a
forgery, but set Reply-To to point to the sender.)

I've complained about it a couple of times, but so far I haven't been
able to convince the maintainer to change it.

On 8/13/2025 1:16 PM, John David via Discuss wrote: > I have been caught in this as well.  I wonder if it can be > reconfigured as "reply" to send to the poster, and "reply all" to send > to everyone. I'm pretty sure that it can be - it's a MailMan instance, and although I am not familiar with MailMan 3 I used to administer a couple of MailMan 2 mailing lists, and it's a separate setting there.  (It's easy to think that it's tied to the DMARC handling, which also rearranges the From header, but it's not.  The good DMARC configuration is to set From to the mailing list, so that providers don't think that the message is a forgery, but set Reply-To to point to the sender.) I've complained about it a couple of times, but so far I haven't been able to convince the maintainer to change it.
JD
John David
Wed, Aug 13, 2025 12:52 PM

Would it help for a group of us to request the change?

On Wed, Aug 13, 2025 at 8:46 AM Jordan Brown openscad@jordan.maileater.net
wrote:

On 8/13/2025 1:16 PM, John David via Discuss wrote:

I have been caught in this as well.  I wonder if it can be
reconfigured as "reply" to send to the poster, and "reply all" to send
to everyone.

I'm pretty sure that it can be - it's a MailMan instance, and although I
am not familiar with MailMan 3 I used to administer a couple of MailMan
2 mailing lists, and it's a separate setting there.  (It's easy to think
that it's tied to the DMARC handling, which also rearranges the From
header, but it's not.  The good DMARC configuration is to set From to
the mailing list, so that providers don't think that the message is a
forgery, but set Reply-To to point to the sender.)

I've complained about it a couple of times, but so far I haven't been
able to convince the maintainer to change it.

Would it help for a group of us to request the change? On Wed, Aug 13, 2025 at 8:46 AM Jordan Brown <openscad@jordan.maileater.net> wrote: > On 8/13/2025 1:16 PM, John David via Discuss wrote: > > I have been caught in this as well. I wonder if it can be > > reconfigured as "reply" to send to the poster, and "reply all" to send > > to everyone. > > I'm pretty sure that it can be - it's a MailMan instance, and although I > am not familiar with MailMan 3 I used to administer a couple of MailMan > 2 mailing lists, and it's a separate setting there. (It's easy to think > that it's tied to the DMARC handling, which also rearranges the From > header, but it's not. The good DMARC configuration is to set From to > the mailing list, so that providers don't think that the message is a > forgery, but set Reply-To to point to the sender.) > > I've complained about it a couple of times, but so far I haven't been > able to convince the maintainer to change it. > > >
RW
Rogier Wolff
Wed, Aug 13, 2025 1:02 PM

On Wed, Aug 13, 2025 at 08:52:31AM -0400, John David via Discuss wrote:

Would it help for a group of us to request the change?

My mail program (mutt) asks me if I want to reply tot the reply-to
address when it isn't the same. (It asks a yes-no question and does
not clearly state which will be yes, and what will be "no", so there
is still room for improvement.).

But the "reply-to" the list is generally what is usually preferable.
Otherwise many conversations would silently "go private" by accident.

But yes: I agree that the "a private message accidentally going
public" is a bad situation.

Roger. 

--
** R.E.Wolff@BitWizard.nl ** https://www.BitWizard.nl/ ** +31-15-2049110 **
** Verl. Spiegelmakerstraat 37 2645 LZ  Delfgauw, The Netherlands.
** KVK: 27239233    **
f equals m times a. When your f is steady, and your m is going down
your a** is going up.  -- Chris Hadfield about flying up the space shuttle.
**  'a' for accelleration.

On Wed, Aug 13, 2025 at 08:52:31AM -0400, John David via Discuss wrote: > Would it help for a group of us to request the change? My mail program (mutt) asks me if I want to reply tot the reply-to address when it isn't the same. (It asks a yes-no question and does not clearly state which will be yes, and what will be "no", so there is still room for improvement.). But the "reply-to" the list is generally what is usually preferable. Otherwise many conversations would silently "go private" by accident. But yes: I agree that the "a private message accidentally going public" is a bad situation. Roger. -- ** R.E.Wolff@BitWizard.nl ** https://www.BitWizard.nl/ ** +31-15-2049110 ** ** Verl. Spiegelmakerstraat 37 2645 LZ Delfgauw, The Netherlands. ** KVK: 27239233 ** f equals m times a. When your f is steady, and your m is going down your a** is going up. -- Chris Hadfield about flying up the space shuttle. ** 'a' for accelleration.
JD
John David
Wed, Aug 13, 2025 1:03 PM

Maybe I am missing something here, but a NURB can create an exact circle,
and there is a package that released an implementation late last year.
I've used it for a couple of small projects in OpenSCAD as part of the
BOSL2 library: https://github.com/BelfrySCAD/BOSL2/wiki/nurbs.scad

On Mon, Aug 11, 2025 at 1:44 PM Rogier Wolff via Discuss <
discuss@lists.openscad.org> wrote:

On Sun, Aug 10, 2025 at 03:39:42PM +0000, Jordan Brown via Discuss wrote:

Yes.  At least some devices can do gcode arcs in their firmware, which

is a

good step, but I have no idea whether the slicers and CAM connect those
dots.

Yes. I made a 2D foam cutting machine. I bought a "standard"
3D-printer-mainboard in china, installed octoprint on an orange pi
zero, and wrote the GCODE by hand (all 113 lines). I use the machine
for one specific job, so this is way easier than writing a whole
toolchain. There is one curve in the final product. Two products from
one sheet, so there are two arc commands in my GCODE and that works.

I'm using the marlin firmware that the manufacturer put in the
mainboard, so marlin already supports those arcs.

To get openscad to support curves, I'd personally recommend following
Prof. Jim Blinn's advice to just use 3rd degree splines/beziers
everywhere (one or the other: make a choice. Transform the one that
you're not natively supporting). The approximation of a circle and
sphere are then "very good", and by eye you cannot see that they are
not real circles and spheres.

What I don't remember from his class was: Is the curve you get by
intersecting two 3rd degree spline patches also a 3rd degree spline? I
suspect it is not. So that complicates things: intersecting say a
sphere and a cylinder would require you to match a bunch of new 3rd
degree splines with the 6th degree intersection curve (which is hard
to algorithmically find anyway).

Differencing a cylinder along one of the axes with a sphere of the
same radius is going to give predictable results. But rotate the
cylinder off-axis, and you might get "ugly" results, where if say the
sphere is a tiny bit larger than the cylinder, you get ugly edges
(i.e. not a circle).

For openscad the "small steps" road to this support would start with
generalizing the "triangle" between 3 points to supporting bezier/spline
patches between 4 points.

Postpone the difficult parts: When things get messy you can downgrade
the patch to triangles, e.g. to find the intersection.

If we can then export the curves when they haven't been "downgraded",
slicers can already be provided test-data for processing curves.

     Roger.

--
** R.E.Wolff@BitWizard.nl ** https://www.BitWizard.nl/ ** +31-15-2049110
**
** Verl. Spiegelmakerstraat 37 2645 LZ  Delfgauw, The Netherlands.
** KVK: 27239233    **
f equals m times a. When your f is steady, and your m is going down
your a** is going up.  -- Chris Hadfield about flying up the space shuttle.
**  'a' for accelleration.


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

Maybe I am missing something here, but a NURB can create an exact circle, and there is a package that released an implementation late last year. I've used it for a couple of small projects in OpenSCAD as part of the BOSL2 library: <https://github.com/BelfrySCAD/BOSL2/wiki/nurbs.scad> On Mon, Aug 11, 2025 at 1:44 PM Rogier Wolff via Discuss < discuss@lists.openscad.org> wrote: > On Sun, Aug 10, 2025 at 03:39:42PM +0000, Jordan Brown via Discuss wrote: > > Yes. At least some devices can do gcode arcs in their firmware, which > is a > > good step, but I have no idea whether the slicers and CAM connect those > > dots. > > Yes. I made a 2D foam cutting machine. I bought a "standard" > 3D-printer-mainboard in china, installed octoprint on an orange pi > zero, and wrote the GCODE by hand (all 113 lines). I use the machine > for one specific job, so this is way easier than writing a whole > toolchain. There is one curve in the final product. Two products from > one sheet, so there are two arc commands in my GCODE and that works. > > I'm using the marlin firmware that the manufacturer put in the > mainboard, so marlin already supports those arcs. > > To get openscad to support curves, I'd personally recommend following > Prof. Jim Blinn's advice to just use 3rd degree splines/beziers > everywhere (one or the other: make a choice. Transform the one that > you're not natively supporting). The approximation of a circle and > sphere are then "very good", and by eye you cannot see that they are > not real circles and spheres. > > What I don't remember from his class was: Is the curve you get by > intersecting two 3rd degree spline patches also a 3rd degree spline? I > suspect it is not. So that complicates things: intersecting say a > sphere and a cylinder would require you to match a bunch of new 3rd > degree splines with the 6th degree intersection curve (which is hard > to algorithmically find anyway). > > Differencing a cylinder along one of the axes with a sphere of the > same radius is going to give predictable results. But rotate the > cylinder off-axis, and you might get "ugly" results, where if say the > sphere is a tiny bit larger than the cylinder, you get ugly edges > (i.e. not a circle). > > For openscad the "small steps" road to this support would start with > generalizing the "triangle" between 3 points to supporting bezier/spline > patches between 4 points. > > Postpone the difficult parts: When things get messy you can downgrade > the patch to triangles, e.g. to find the intersection. > > If we can then export the curves when they haven't been "downgraded", > slicers can already be provided test-data for processing curves. > > Roger. > > -- > ** R.E.Wolff@BitWizard.nl ** https://www.BitWizard.nl/ ** +31-15-2049110 > ** > ** Verl. Spiegelmakerstraat 37 2645 LZ Delfgauw, The Netherlands. > ** KVK: 27239233 ** > f equals m times a. When your f is steady, and your m is going down > your a** is going up. -- Chris Hadfield about flying up the space shuttle. > ** 'a' for accelleration. > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org >
TA
Todd Allen
Wed, Aug 13, 2025 1:30 PM

Maybe I am missing something here, but a NURB can create an exact circle,

The BOSL2 library can produce points from a NURB.  Those points might all
very nearly lie on an exact circle but they do not define a true circle and
there is no capacity to continue processing or export those points as a
circle or a curve.

On Wed, Aug 13, 2025 at 8:03 AM John David ebo.2112@gmail.com wrote:

Maybe I am missing something here, but a NURB can create an exact circle,
and there is a package that released an implementation late last year.
I've used it for a couple of small projects in OpenSCAD as part of the
BOSL2 library: https://github.com/BelfrySCAD/BOSL2/wiki/nurbs.scad

On Mon, Aug 11, 2025 at 1:44 PM Rogier Wolff via Discuss <
discuss@lists.openscad.org> wrote:

On Sun, Aug 10, 2025 at 03:39:42PM +0000, Jordan Brown via Discuss wrote:

Yes.  At least some devices can do gcode arcs in their firmware, which

is a

good step, but I have no idea whether the slicers and CAM connect those
dots.

Yes. I made a 2D foam cutting machine. I bought a "standard"
3D-printer-mainboard in china, installed octoprint on an orange pi
zero, and wrote the GCODE by hand (all 113 lines). I use the machine
for one specific job, so this is way easier than writing a whole
toolchain. There is one curve in the final product. Two products from
one sheet, so there are two arc commands in my GCODE and that works.

I'm using the marlin firmware that the manufacturer put in the
mainboard, so marlin already supports those arcs.

To get openscad to support curves, I'd personally recommend following
Prof. Jim Blinn's advice to just use 3rd degree splines/beziers
everywhere (one or the other: make a choice. Transform the one that
you're not natively supporting). The approximation of a circle and
sphere are then "very good", and by eye you cannot see that they are
not real circles and spheres.

What I don't remember from his class was: Is the curve you get by
intersecting two 3rd degree spline patches also a 3rd degree spline? I
suspect it is not. So that complicates things: intersecting say a
sphere and a cylinder would require you to match a bunch of new 3rd
degree splines with the 6th degree intersection curve (which is hard
to algorithmically find anyway).

Differencing a cylinder along one of the axes with a sphere of the
same radius is going to give predictable results. But rotate the
cylinder off-axis, and you might get "ugly" results, where if say the
sphere is a tiny bit larger than the cylinder, you get ugly edges
(i.e. not a circle).

For openscad the "small steps" road to this support would start with
generalizing the "triangle" between 3 points to supporting bezier/spline
patches between 4 points.

Postpone the difficult parts: When things get messy you can downgrade
the patch to triangles, e.g. to find the intersection.

If we can then export the curves when they haven't been "downgraded",
slicers can already be provided test-data for processing curves.

     Roger.

--
** R.E.Wolff@BitWizard.nl ** https://www.BitWizard.nl/ ** +31-15-2049110
**
** Verl. Spiegelmakerstraat 37 2645 LZ  Delfgauw, The Netherlands.
** KVK: 27239233    **
f equals m times a. When your f is steady, and your m is going down
your a** is going up.  -- Chris Hadfield about flying up the space
shuttle.
**  'a' for accelleration.


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

Maybe I am missing something here, but a NURB can create an exact circle, The BOSL2 library can produce points from a NURB. Those points might all very nearly lie on an exact circle but they do not define a true circle and there is no capacity to continue processing or export those points as a circle or a curve. On Wed, Aug 13, 2025 at 8:03 AM John David <ebo.2112@gmail.com> wrote: > Maybe I am missing something here, but a NURB can create an exact circle, > and there is a package that released an implementation late last year. > I've used it for a couple of small projects in OpenSCAD as part of the > BOSL2 library: <https://github.com/BelfrySCAD/BOSL2/wiki/nurbs.scad> > > On Mon, Aug 11, 2025 at 1:44 PM Rogier Wolff via Discuss < > discuss@lists.openscad.org> wrote: > >> On Sun, Aug 10, 2025 at 03:39:42PM +0000, Jordan Brown via Discuss wrote: >> > Yes. At least some devices can do gcode arcs in their firmware, which >> is a >> > good step, but I have no idea whether the slicers and CAM connect those >> > dots. >> >> Yes. I made a 2D foam cutting machine. I bought a "standard" >> 3D-printer-mainboard in china, installed octoprint on an orange pi >> zero, and wrote the GCODE by hand (all 113 lines). I use the machine >> for one specific job, so this is way easier than writing a whole >> toolchain. There is one curve in the final product. Two products from >> one sheet, so there are two arc commands in my GCODE and that works. >> >> I'm using the marlin firmware that the manufacturer put in the >> mainboard, so marlin already supports those arcs. >> >> To get openscad to support curves, I'd personally recommend following >> Prof. Jim Blinn's advice to just use 3rd degree splines/beziers >> everywhere (one or the other: make a choice. Transform the one that >> you're not natively supporting). The approximation of a circle and >> sphere are then "very good", and by eye you cannot see that they are >> not real circles and spheres. >> >> What I don't remember from his class was: Is the curve you get by >> intersecting two 3rd degree spline patches also a 3rd degree spline? I >> suspect it is not. So that complicates things: intersecting say a >> sphere and a cylinder would require you to match a bunch of new 3rd >> degree splines with the 6th degree intersection curve (which is hard >> to algorithmically find anyway). >> >> Differencing a cylinder along one of the axes with a sphere of the >> same radius is going to give predictable results. But rotate the >> cylinder off-axis, and you might get "ugly" results, where if say the >> sphere is a tiny bit larger than the cylinder, you get ugly edges >> (i.e. not a circle). >> >> For openscad the "small steps" road to this support would start with >> generalizing the "triangle" between 3 points to supporting bezier/spline >> patches between 4 points. >> >> Postpone the difficult parts: When things get messy you can downgrade >> the patch to triangles, e.g. to find the intersection. >> >> If we can then export the curves when they haven't been "downgraded", >> slicers can already be provided test-data for processing curves. >> >> Roger. >> >> -- >> ** R.E.Wolff@BitWizard.nl ** https://www.BitWizard.nl/ ** +31-15-2049110 >> ** >> ** Verl. Spiegelmakerstraat 37 2645 LZ Delfgauw, The Netherlands. >> ** KVK: 27239233 ** >> f equals m times a. When your f is steady, and your m is going down >> your a** is going up. -- Chris Hadfield about flying up the space >> shuttle. >> ** 'a' for accelleration. >> _______________________________________________ >> OpenSCAD mailing list >> To unsubscribe send an email to discuss-leave@lists.openscad.org >> >
GB
Glenn Butcher
Wed, Aug 13, 2025 1:58 PM

Apologies in advance if this seems harsh...

I think this falls into the old 'reply-all' bucket, don't do that.  I
don't know of a mail program in use today that doesn't display the
contents of the To:, Cc: and Bcc: lines of a draft email, so pay
attention to what's in there.

Words of wisdom from my mother: "Do you know who you're talking to??"

Regards,
Glenn Butcher

On 8/13/2025 7:02 AM, Rogier Wolff via Discuss wrote:

On Wed, Aug 13, 2025 at 08:52:31AM -0400, John David via Discuss wrote:

Would it help for a group of us to request the change?
My mail program (mutt) asks me if I want to reply tot the reply-to
address when it isn't the same. (It asks a yes-no question and does
not clearly state which will be yes, and what will be "no", so there
is still room for improvement.).

But the "reply-to" the list is generally what is usually preferable.
Otherwise many conversations would silently "go private" by accident.

But yes: I agree that the "a private message accidentally going
public" is a bad situation.

Roger.
Apologies in advance if this seems harsh... I think this falls into the old 'reply-all' bucket, don't do that.  I don't know of a mail program in use today that doesn't display the contents of the To:, Cc: and Bcc: lines of a draft email, so pay attention to what's in there. Words of wisdom from my mother: "Do you know who you're talking to??" Regards, Glenn Butcher On 8/13/2025 7:02 AM, Rogier Wolff via Discuss wrote: > On Wed, Aug 13, 2025 at 08:52:31AM -0400, John David via Discuss wrote: >> Would it help for a group of us to request the change? > My mail program (mutt) asks me if I want to reply tot the reply-to > address when it isn't the same. (It asks a yes-no question and does > not clearly state which will be yes, and what will be "no", so there > is still room for improvement.). > > But the "reply-to" the list is generally what is usually preferable. > Otherwise many conversations would silently "go private" by accident. > > But yes: I agree that the "a private message accidentally going > public" is a bad situation. > > Roger. >
JB
Jordan Brown
Wed, Aug 13, 2025 2:01 PM

On 8/13/2025 2:02 PM, Rogier Wolff wrote:

But the "reply-to" the list is generally what is usually preferable.

It's a religious question.  References below.  Being a right-thinking
person, I strongly disagree.  (And it's almost a deal killer for me; if
I valued the OpenSCAD mailing list any less, it would be enough for me
to drop out.  I've done it.)

Otherwise many conversations would silently "go private" by accident.

But yes: I agree that the "a private message accidentally going
public" is a bad situation.

I think that "private message goes public" is far far worse than "public
message goes private". One is unrecoverable; the other is recoverable by
re-sending the message.

If only mail programs had a way for the user who wants to reply to
distinguish whether they want a reply to go only to the original author,
or also to all of the original recipients. Oh, wait, they all do.


References, with a few key quotes...

https://www.gnu.org/software/mailman/mailman-admin/node11.html

Beware!Reply-To:munging is considered a religious issue and the
policies you set here can ignite some of the most heated off-topic
flame wars on your mailing lists. We'll try to stay as agnostic as
possible, but our biases may still peak through.

Reply-To:is a header that is commonly used to redirect replies to
messages. Exactly what happens when your users reply to such a message
depends on the mail readers your users use, and what functions they
provide. Usually, there is both a reply to sender'' button and a reply to all'' button. If people use these buttons correctly, you
will probably never need to mungeReply-To:, so the default values
should be fine.

Since an informed decision is always best, here are links to two
articles that discuss the opposing viewpoints in great detail:

When you set this variable to/Poster/, no additionalReply-To:header
will be added by Mailman. This setting is strongly recommended.

(Note: they don't say it here, but the DMARC settings, which also muck
with "Reply-to", are orthogonal. They change "From" to point to the
mailing list, and in the /Poster/ case, set "Reply-To" to the original
sender, retaining the reply-to-poster semantics but not looking like a
forgery.)

On 8/13/2025 2:02 PM, Rogier Wolff wrote: > But the "reply-to" the list is generally what is usually preferable. It's a religious question.  References below.  Being a right-thinking person, I strongly disagree.  (And it's almost a deal killer for me; if I valued the OpenSCAD mailing list any less, it would be enough for me to drop out.  I've done it.) > Otherwise many conversations would silently "go private" by accident. > > But yes: I agree that the "a private message accidentally going > public" is a bad situation. I think that "private message goes public" is far far worse than "public message goes private". One is unrecoverable; the other is recoverable by re-sending the message. If only mail programs had a way for the user who wants to reply to distinguish whether they want a reply to go only to the original author, or also to all of the original recipients. Oh, wait, they all do. --- References, with a few key quotes... https://www.gnu.org/software/mailman/mailman-admin/node11.html > Beware!Reply-To:munging is considered a religious issue and the > policies you set here can ignite some of the most heated off-topic > flame wars on your mailing lists. We'll try to stay as agnostic as > possible, but our biases may still peak through. > > Reply-To:is a header that is commonly used to redirect replies to > messages. Exactly what happens when your users reply to such a message > depends on the mail readers your users use, and what functions they > provide. Usually, there is both a ``reply to sender'' button and a > ``reply to all'' button. If people use these buttons correctly, you > will probably never need to mungeReply-To:, so the default values > should be fine. > > Since an informed decision is always best, here are links to two > articles that discuss the opposing viewpoints in great detail: > > * Reply-To Munging Considered Harmful > <http://marc.merlins.org/netrants/reply-to-harmful.html> > * Reply-To Munging Considered Useful > <http://marc.merlins.org/netrants/reply-to-useful.html> > > When you set this variable to/Poster/, no additionalReply-To:header > will be added by Mailman. This setting is strongly recommended. > (Note: they don't say it here, but the DMARC settings, which also muck with "Reply-to", are orthogonal. They change "From" to point to the mailing list, and in the /Poster/ case, set "Reply-To" to the original sender, retaining the reply-to-poster semantics but not looking like a forgery.)
WF
William F. Adams
Wed, Aug 13, 2025 2:19 PM

(trimmed recipients down to just the list)

On Wednesday, August 13, 2025 at 09:31:16 AM EDT, Todd Allen via Discuss discuss@lists.openscad.org wrote:

The BOSL2 library can produce points from a NURB.  Those points might all very nearly lie on an exact circle but they do not
define a true circle and there is no capacity to continue processing or export those points as a circle or a curve.

It is an interesting mathematical exercise to prove how a Bézier curve cannot exactly represent a circle --- but I think it would be even more interesting to show a real-world example where the want of that ability has resulted in a difficulty making a part --- it's a close enough approximation for most (or even the vast majority of) usages.

An interesting approach to me is to write out a DXF as a part of the modeling process --- this allows capturing arcs/circle segments/circles as such in the DXF format --- and it has been working for me in my current project (search my name on github if curious), and the success of it has me wanting to extend that to Bézier curves  --- writing out SVG files directly is needlessly complex since the coordinate system differs from that of DXFs and OpenSCAD, but it looks promising to re-implement the METAFONT/METAPOST curve format and to write out .mp files.

In the meanwhile, it does work to open up a DXF written out from my library by way of (Open)PythonSCAD in LibreCAD, then export it from that application as an SVG.

Extending all that to also writing out a NURBS file/definition is something which I hope I can expand my knowledge of mathematics to encompass.

William

-- 
Sphinx of black quartz, judge my vow.
https://designinto3d.com/

(trimmed recipients down to just the list) On Wednesday, August 13, 2025 at 09:31:16 AM EDT, Todd Allen via Discuss <discuss@lists.openscad.org> wrote: >The BOSL2 library can produce points from a NURB.  Those points might all very nearly lie on an exact circle but they do not > define a true circle and there is no capacity to continue processing or export those points as a circle or a curve. It is an interesting mathematical exercise to prove how a Bézier curve cannot exactly represent a circle --- but I think it would be even more interesting to show a real-world example where the want of that ability has resulted in a difficulty making a part --- it's a close enough approximation for most (or even the vast majority of) usages. An interesting approach to me is to write out a DXF as a part of the modeling process --- this allows capturing arcs/circle segments/circles as such in the DXF format --- and it has been working for me in my current project (search my name on github if curious), and the success of it has me wanting to extend that to Bézier curves  --- writing out SVG files directly is needlessly complex since the coordinate system differs from that of DXFs and OpenSCAD, but it looks promising to re-implement the METAFONT/METAPOST curve format and to write out .mp files. In the meanwhile, it does work to open up a DXF written out from my library by way of (Open)PythonSCAD in LibreCAD, then export it from that application as an SVG. Extending all that to also writing out a NURBS file/definition is something which I hope I can expand my knowledge of mathematics to encompass. William --  Sphinx of black quartz, judge my vow. https://designinto3d.com/
RD
Revar Desmera
Wed, Aug 13, 2025 2:29 PM

NURBS are not Bézier curves. (Though Bézier curves can be made with NURBS). As I understand it, while Bézier curves cannot exactly represent a circle, with the right knot values, NURBS can.

-Revar

On Aug 13, 2025, at 7:20 AM, William F. Adams via Discuss discuss@lists.openscad.org wrote:

(trimmed recipients down to just the list)

On Wednesday, August 13, 2025 at 09:31:16 AM EDT, Todd Allen via Discuss discuss@lists.openscad.org wrote:

The BOSL2 library can produce points from a NURB.  Those points might all very nearly lie on an exact circle but they do not
define a true circle and there is no capacity to continue processing or export those points as a circle or a curve.

It is an interesting mathematical exercise to prove how a Bézier curve cannot exactly represent a circle --- but I think it would be even more interesting to show a real-world example where the want of that ability has resulted in a difficulty making a part --- it's a close enough approximation for most (or even the vast majority of) usages.

An interesting approach to me is to write out a DXF as a part of the modeling process --- this allows capturing arcs/circle segments/circles as such in the DXF format --- and it has been working for me in my current project (search my name on github if curious), and the success of it has me wanting to extend that to Bézier curves  --- writing out SVG files directly is needlessly complex since the coordinate system differs from that of DXFs and OpenSCAD, but it looks promising to re-implement the METAFONT/METAPOST curve format and to write out .mp files.

In the meanwhile, it does work to open up a DXF written out from my library by way of (Open)PythonSCAD in LibreCAD, then export it from that application as an SVG.

Extending all that to also writing out a NURBS file/definition is something which I hope I can expand my knowledge of mathematics to encompass.

William

--
Sphinx of black quartz, judge my vow.
https://designinto3d.com/


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

NURBS are not Bézier curves. (Though Bézier curves can be made with NURBS). As I understand it, while Bézier curves cannot exactly represent a circle, with the right knot values, NURBS can. -Revar > On Aug 13, 2025, at 7:20 AM, William F. Adams via Discuss <discuss@lists.openscad.org> wrote: > > (trimmed recipients down to just the list) > >> On Wednesday, August 13, 2025 at 09:31:16 AM EDT, Todd Allen via Discuss <discuss@lists.openscad.org> wrote: >> >> The BOSL2 library can produce points from a NURB. Those points might all very nearly lie on an exact circle but they do not >> define a true circle and there is no capacity to continue processing or export those points as a circle or a curve. > > It is an interesting mathematical exercise to prove how a Bézier curve cannot exactly represent a circle --- but I think it would be even more interesting to show a real-world example where the want of that ability has resulted in a difficulty making a part --- it's a close enough approximation for most (or even the vast majority of) usages. > > An interesting approach to me is to write out a DXF as a part of the modeling process --- this allows capturing arcs/circle segments/circles as such in the DXF format --- and it has been working for me in my current project (search my name on github if curious), and the success of it has me wanting to extend that to Bézier curves --- writing out SVG files directly is needlessly complex since the coordinate system differs from that of DXFs and OpenSCAD, but it looks promising to re-implement the METAFONT/METAPOST curve format and to write out .mp files. > > In the meanwhile, it does work to open up a DXF written out from my library by way of (Open)PythonSCAD in LibreCAD, then export it from that application as an SVG. > > Extending all that to also writing out a NURBS file/definition is something which I hope I can expand my knowledge of mathematics to encompass. > > William > > -- > Sphinx of black quartz, judge my vow. > https://designinto3d.com/ > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org
JB
Jordan Brown
Wed, Aug 13, 2025 2:38 PM

Since religious arguments rarely go anywhere useful, I'll try to avoid
further contributing to this one.

Perhaps we should have a poll.

Since religious arguments rarely go anywhere useful, I'll try to avoid further contributing to this one. Perhaps we should have a poll.
RW
Rogier Wolff
Wed, Aug 13, 2025 2:58 PM

On Aug 13, 2025, at 7:20 AM, William F. Adams via Discuss discuss@lists.openscad.org wrote:

It is an interesting mathematical exercise to prove how a Bézier
curve cannot exactly represent a circle --- but I think it would be
even more interesting to show a real-world example where the want of
that ability has resulted in a difficulty making a part --- it's a
close enough approximation for most (or even the vast majority of)
usages.

We'd like to do 3D printing and CNCing with the results from the CAD
process, right?

Well... if I design a round hole for an object and the object that
goes inside, then I expect that object to be able to rotate. Any
deviation from a true circle will cause it to "not be able to rotate".

If you create sufficient tolerances that it does rotate, you'll get
it to fit tighter and less tight along the full rotation.

This design and wanting to CNC that with a low tolerance on a good CNC
isn't all that farfetched. So maybe my "visually a spline is close
enough to a circle" is not quite good enough.

I got educated on "computer graphics" mid 1980s. So back then: "looks
good" was important and "exact fit" maybe not so much. The wikipedia
article mentions late 1980s as the first implementation of NURBs.

Roger.

--
** R.E.Wolff@BitWizard.nl ** https://www.BitWizard.nl/ ** +31-15-2049110 **
** Verl. Spiegelmakerstraat 37 2645 LZ  Delfgauw, The Netherlands.
** KVK: 27239233    **
f equals m times a. When your f is steady, and your m is going down
your a** is going up.  -- Chris Hadfield about flying up the space shuttle.
**  'a' for accelleration.

> On Aug 13, 2025, at 7:20 AM, William F. Adams via Discuss <discuss@lists.openscad.org> wrote: > It is an interesting mathematical exercise to prove how a Bézier > curve cannot exactly represent a circle --- but I think it would be > even more interesting to show a real-world example where the want of > that ability has resulted in a difficulty making a part --- it's a > close enough approximation for most (or even the vast majority of) > usages. We'd like to do 3D printing and CNCing with the results from the CAD process, right? Well... if I design a round hole for an object and the object that goes inside, then I expect that object to be able to rotate. Any deviation from a true circle will cause it to "not be able to rotate". If you create sufficient tolerances that it does rotate, you'll get it to fit tighter and less tight along the full rotation. This design and wanting to CNC that with a low tolerance on a good CNC isn't all that farfetched. So maybe my "visually a spline is close enough to a circle" is not quite good enough. I got educated on "computer graphics" mid 1980s. So back then: "looks good" was important and "exact fit" maybe not so much. The wikipedia article mentions late 1980s as the first implementation of NURBs. Roger. -- ** R.E.Wolff@BitWizard.nl ** https://www.BitWizard.nl/ ** +31-15-2049110 ** ** Verl. Spiegelmakerstraat 37 2645 LZ Delfgauw, The Netherlands. ** KVK: 27239233 ** f equals m times a. When your f is steady, and your m is going down your a** is going up. -- Chris Hadfield about flying up the space shuttle. ** 'a' for accelleration.
WF
William F. Adams
Wed, Aug 13, 2025 3:19 PM

On Wednesday, August 13, 2025 at 10:30:19 AM EDT, Revar Desmera via Discuss discuss@lists.openscad.org wrote:

NURBS are not Bézier curves. (Though Bézier curves can be made with NURBS). As I understand it, while Bézier curves 
cannot exactly represent a circle, with the right knot values, NURBS can.

Yep turns out adding support for this was an explicit effort:

https://en.wikipedia.org/wiki/Non-uniform_rational_B-spline

NURBS curves also feature a scalar weight for each control point. This allows for more control over the shape of the curve 
without unduly raising the number of control points. In particular, it adds conic sections like circles and ellipses to the set of 
curves that can be represented exactly. The term rational in NURBS refers to these weights.

Is there a 2D implementation of this suited to CNC?

On Wednesday, August 13, 2025 at 10:59:25 AM EDT, Rogier Wolff via Discuss discuss@lists.openscad.org wrote:

We'd like to do 3D printing and CNCing with the results from the CAD
process, right?

Correct.

Well... if I design a round hole for an object and the object that
goes inside, then I expect that object to be able to rotate. Any
deviation from a true circle will cause it to "not be able to rotate".

Yes, given a difference large enough to matter --- as I noted, showing the inability of such curves to represent a true circle is left as an exercise for the reader as well as showing the exact nature of the deviation.

If you create sufficient tolerances that it does rotate, you'll get
it to fit tighter and less tight along the full rotation.

If you have a CNC  or 3D printer where this difference can be expressed as a physical part so as to cause this issue, please let us know. Curious as to which material and manufacturing process and size it can be made to happen at.

This design and wanting to CNC that with a low tolerance on a good CNC
isn't all that farfetched. So maybe my "visually a spline is close
enough to a circle" is not quite good enough.

For practical purposes, one equipment which is within the reach of an individual, or even a typical small company, in my experience, it is.

That said, as noted, the tool which I've been working on will express arcs/circle segments/circles in a DXF or in G-code, so if folks find OpenSCAD's inability to actually represent a circle as a circle, well there is one programmatic option.

That said, I would be interested in further informaton on file formats and so forth which can accurately represent curves/circles/segments and the possibility of implementing them either as part of OpenSCAD/(Open)PythonSCAD, or in libraries which can be loaded into it and used by it.

William

On Wednesday, August 13, 2025 at 10:30:19 AM EDT, Revar Desmera via Discuss <discuss@lists.openscad.org> wrote: >NURBS are not Bézier curves. (Though Bézier curves can be made with NURBS). As I understand it, while Bézier curves  >cannot exactly represent a circle, with the right knot values, NURBS can. Yep turns out adding support for this was an explicit effort: https://en.wikipedia.org/wiki/Non-uniform_rational_B-spline >>NURBS curves also feature a scalar weight for each control point. This allows for more control over the shape of the curve  >>without unduly raising the number of control points. In particular, it adds conic sections like circles and ellipses to the set of  >>curves that can be represented exactly. The term rational in NURBS refers to these weights. Is there a 2D implementation of this suited to CNC? On Wednesday, August 13, 2025 at 10:59:25 AM EDT, Rogier Wolff via Discuss <discuss@lists.openscad.org> wrote: >We'd like to do 3D printing and CNCing with the results from the CAD >process, right? Correct. >Well... if I design a round hole for an object and the object that >goes inside, then I expect that object to be able to rotate. Any >deviation from a true circle will cause it to "not be able to rotate". Yes, given a difference large enough to matter --- as I noted, showing the inability of such curves to represent a true circle is left as an exercise for the reader as well as showing the exact nature of the deviation. >If you create sufficient tolerances that it does rotate, you'll get >it to fit tighter and less tight along the full rotation. If you have a CNC  or 3D printer where this difference can be expressed as a physical part so as to cause this issue, please let us know. Curious as to which material and manufacturing process and size it can be made to happen at. >This design and wanting to CNC that with a low tolerance on a good CNC >isn't all that farfetched. So maybe my "visually a spline is close >enough to a circle" is not quite good enough. For practical purposes, one equipment which is within the reach of an individual, or even a typical small company, in my experience, it is. That said, as noted, the tool which I've been working on will express arcs/circle segments/circles in a DXF or in G-code, so if folks find OpenSCAD's inability to actually represent a circle as a circle, well there is one programmatic option. That said, I would be interested in further informaton on file formats and so forth which can accurately represent curves/circles/segments and the possibility of implementing them either as part of OpenSCAD/(Open)PythonSCAD, or in libraries which can be loaded into it and used by it. William
JB
Jordan Brown
Wed, Aug 13, 2025 3:34 PM

Indeed, we need a clear statement of what is and isn't expected to be
covered in the "language reference" manual.

(Or, more generally, what set of manuals we want to have and what
belongs in each.)

And with that should come some editorial ... willpower? ... to reject
changes that aren't in line with that statement.

Indeed, we need a clear statement of what is and isn't expected to be covered in the "language reference" manual. (Or, more generally, what set of manuals we want to have and what belongs in each.) And with that should come some editorial ... willpower? ... to reject changes that aren't in line with that statement.
JD
John David
Wed, Aug 13, 2025 3:41 PM

I just got a half dozen private and small group replies (that do not
overlap each other), so I am just going to post a reply to the group...

I assure those of you who do not know the mathematics behind NURBS, that
they can indeed represent an exact circle (see:
https://en.wikipedia.org/wiki/Non-uniform_rational_B-spline#Example:_a_circle
for at least some details, and Gerald Farin's book on NURBS
https://www.farinhansford.com/books/nurbs/ for the math and practicalities
behind it).  Now, a couple of people have used the term "true circle".  I
am assuming that you mean "a perfectly round shape defined by a single,
continuous mathematical curve, not a series of short lines".  Depending on
the degree of the NURBS, you get something called C* and G* continuity
(where * is the degree of the object/NURBS).  So yes, a NURB will exactly
define a "true circle".  That said, there are practical implementation
details that come into play.  Since you have evoked CNC/G-code, as well as
NURB curves and surfaces, they have to be evaluated as some epsilon.  Even
a G02 (clockwise arc in g-code), has to evaluate the mathematical
expression of an arc/circle at the precision of a machine's step size.
This is often well below 0.001" (I have machines whose step size are
0.00002").  Both a mathematical circle, as well as a NURBS with
appropriate knots sequences and weights of sqrt(2)/2, will mathematically
give you a fully mathematically continuous and exact circle.

Since you also mentioned wanting these in 3D printing, and CNC, even
LinuxCNC has an experimental implementation, and I know commercial CNC
machines often have NURBS implemented directly in the G-Code
implementation.  I am not familiar with any 3D printing software the
supports NURBS, but I have not needed to check.  I will say that the way
NURBS are defined is so well-defined, that it is typically easy to write a
translator to go from one representation to another.  In addition, there
are enough prototype implementations that a motivated programmer should be
able to port any one of a dozen implementations/libraries to open-source 3D
printing software.  If you go for that, hit me up, and I will dig through
my archived class projects -- back in 2001 I took Gerald Farin's PhD level
class on CAGD, as well as others.  One of the other students and I made a
game of challenging each other with different implementations of evaluating
the N-Dimentional Bernstein Polynomials (and you can implement NURBS based
on them).  Anyway, we ended up with something that is wicked fast, and if I
recall correctly I set mine up to cache the intermediate results for
various efficiency reasons (like further subdivisions, etc.).

Anyway, this was all very long-winded, BUT I think that NURBS will give you
want and need (it will look very weird at first), but  you will have to
either see if there is downstream implementations of NURBS in your 3D
printing and CNC software.

EBo --

On Wed, Aug 13, 2025 at 10:59 AM Rogier Wolff via Discuss <
discuss@lists.openscad.org> wrote:

On Aug 13, 2025, at 7:20 AM, William F. Adams via Discuss <

It is an interesting mathematical exercise to prove how a Bézier
curve cannot exactly represent a circle --- but I think it would be
even more interesting to show a real-world example where the want of
that ability has resulted in a difficulty making a part --- it's a
close enough approximation for most (or even the vast majority of)
usages.

We'd like to do 3D printing and CNCing with the results from the CAD
process, right?

Well... if I design a round hole for an object and the object that
goes inside, then I expect that object to be able to rotate. Any
deviation from a true circle will cause it to "not be able to rotate".

If you create sufficient tolerances that it does rotate, you'll get
it to fit tighter and less tight along the full rotation.

This design and wanting to CNC that with a low tolerance on a good CNC
isn't all that farfetched. So maybe my "visually a spline is close
enough to a circle" is not quite good enough.

I got educated on "computer graphics" mid 1980s. So back then: "looks
good" was important and "exact fit" maybe not so much. The wikipedia
article mentions late 1980s as the first implementation of NURBs.

     Roger.

--
** R.E.Wolff@BitWizard.nl ** https://www.BitWizard.nl/ ** +31-15-2049110
**
** Verl. Spiegelmakerstraat 37 2645 LZ  Delfgauw, The Netherlands.
** KVK: 27239233    **
f equals m times a. When your f is steady, and your m is going down
your a** is going up.  -- Chris Hadfield about flying up the space shuttle.
**  'a' for accelleration.


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

I just got a half dozen private and small group replies (that do not overlap each other), so I am just going to post a reply to the group... I assure those of you who do not know the mathematics behind NURBS, that they can indeed represent an exact circle (see: https://en.wikipedia.org/wiki/Non-uniform_rational_B-spline#Example:_a_circle for at least some details, and Gerald Farin's book on NURBS https://www.farinhansford.com/books/nurbs/ for the math and practicalities behind it). Now, a couple of people have used the term "true circle". I am assuming that you mean "a perfectly round shape defined by a single, continuous mathematical curve, not a series of short lines". Depending on the degree of the NURBS, you get something called C* and G* continuity (where * is the degree of the object/NURBS). So yes, a NURB will exactly define a "true circle". That said, there are practical implementation details that come into play. Since you have evoked CNC/G-code, as well as NURB curves and surfaces, they have to be evaluated as some epsilon. Even a G02 (clockwise arc in g-code), has to evaluate the mathematical expression of an arc/circle at the precision of a machine's step size. This is often well below 0.001" (I have machines whose step size are 0.00002"). Both a mathematical circle, as well as a NURBS with appropriate knots sequences and weights of sqrt(2)/2, will mathematically give you a fully mathematically continuous and exact circle. Since you also mentioned wanting these in 3D printing, and CNC, even LinuxCNC has an experimental implementation, and I know commercial CNC machines often have NURBS implemented directly in the G-Code implementation. I am not familiar with any 3D printing software the supports NURBS, but I have not needed to check. I will say that the way NURBS are defined is so well-defined, that it is typically easy to write a translator to go from one representation to another. In addition, there are enough prototype implementations that a motivated programmer should be able to port any one of a dozen implementations/libraries to open-source 3D printing software. If you go for that, hit me up, and I will dig through my archived class projects -- back in 2001 I took Gerald Farin's PhD level class on CAGD, as well as others. One of the other students and I made a game of challenging each other with different implementations of evaluating the N-Dimentional Bernstein Polynomials (and you can implement NURBS based on them). Anyway, we ended up with something that is wicked fast, and if I recall correctly I set mine up to cache the intermediate results for various efficiency reasons (like further subdivisions, etc.). Anyway, this was all very long-winded, BUT I think that NURBS will give you want and need (it will look very weird at first), but you will have to either see if there is downstream implementations of NURBS in your 3D printing and CNC software. EBo -- On Wed, Aug 13, 2025 at 10:59 AM Rogier Wolff via Discuss < discuss@lists.openscad.org> wrote: > > > On Aug 13, 2025, at 7:20 AM, William F. Adams via Discuss < > discuss@lists.openscad.org> wrote: > > > It is an interesting mathematical exercise to prove how a Bézier > > curve cannot exactly represent a circle --- but I think it would be > > even more interesting to show a real-world example where the want of > > that ability has resulted in a difficulty making a part --- it's a > > close enough approximation for most (or even the vast majority of) > > usages. > > We'd like to do 3D printing and CNCing with the results from the CAD > process, right? > > Well... if I design a round hole for an object and the object that > goes inside, then I expect that object to be able to rotate. Any > deviation from a true circle will cause it to "not be able to rotate". > > If you create sufficient tolerances that it does rotate, you'll get > it to fit tighter and less tight along the full rotation. > > This design and wanting to CNC that with a low tolerance on a good CNC > isn't all that farfetched. So maybe my "visually a spline is close > enough to a circle" is not quite good enough. > > I got educated on "computer graphics" mid 1980s. So back then: "looks > good" was important and "exact fit" maybe not so much. The wikipedia > article mentions late 1980s as the first implementation of NURBs. > > Roger. > > -- > ** R.E.Wolff@BitWizard.nl ** https://www.BitWizard.nl/ ** +31-15-2049110 > ** > ** Verl. Spiegelmakerstraat 37 2645 LZ Delfgauw, The Netherlands. > ** KVK: 27239233 ** > f equals m times a. When your f is steady, and your m is going down > your a** is going up. -- Chris Hadfield about flying up the space shuttle. > ** 'a' for accelleration. > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org >
JD
John David
Wed, Aug 13, 2025 4:05 PM

It has probably been 10 or 20 years since I looked into this, but I
remember working with a library that took in NURBS, and then approximated
them with arcs and lines that were directly convertible to g-code.  I used
that as a side-step so that I could work with NURBS and run on an
unmodified CNC router (that did not support them).  I have no idea
where that code is.  You might check on github for things like tinynurbs,
... Hmmm... what languages do you want to program in?...

On Wed, Aug 13, 2025 at 11:20 AM William F. Adams via Discuss <
discuss@lists.openscad.org> wrote:

On Wednesday, August 13, 2025 at 10:30:19 AM EDT, Revar Desmera via
Discuss discuss@lists.openscad.org wrote:

NURBS are not Bézier curves. (Though Bézier curves can be made with

NURBS). As I understand it, while Bézier curves

cannot exactly represent a circle, with the right knot values, NURBS can.

Yep turns out adding support for this was an explicit effort:

https://en.wikipedia.org/wiki/Non-uniform_rational_B-spline

NURBS curves also feature a scalar weight for each control point. This

allows for more control over the shape of the curve

without unduly raising the number of control points. In particular, it

adds conic sections like circles and ellipses to the set of

curves that can be represented exactly. The term rational in NURBS

refers to these weights.

Is there a 2D implementation of this suited to CNC?

On Wednesday, August 13, 2025 at 10:59:25 AM EDT, Rogier Wolff via Discuss
discuss@lists.openscad.org wrote:

We'd like to do 3D printing and CNCing with the results from the CAD
process, right?

Correct.

Well... if I design a round hole for an object and the object that
goes inside, then I expect that object to be able to rotate. Any
deviation from a true circle will cause it to "not be able to rotate".

Yes, given a difference large enough to matter --- as I noted, showing the
inability of such curves to represent a true circle is left as an exercise
for the reader as well as showing the exact nature of the deviation.

If you create sufficient tolerances that it does rotate, you'll get
it to fit tighter and less tight along the full rotation.

If you have a CNC  or 3D printer where this difference can be expressed as
a physical part so as to cause this issue, please let us know. Curious as
to which material and manufacturing process and size it can be made to
happen at.

This design and wanting to CNC that with a low tolerance on a good CNC
isn't all that farfetched. So maybe my "visually a spline is close
enough to a circle" is not quite good enough.

For practical purposes, one equipment which is within the reach of an
individual, or even a typical small company, in my experience, it is.

That said, as noted, the tool which I've been working on will express
arcs/circle segments/circles in a DXF or in G-code, so if folks find
OpenSCAD's inability to actually represent a circle as a circle, well there
is one programmatic option.

That said, I would be interested in further informaton on file formats and
so forth which can accurately represent curves/circles/segments and the
possibility of implementing them either as part of
OpenSCAD/(Open)PythonSCAD, or in libraries which can be loaded into it and
used by it.

William


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

It has probably been 10 or 20 years since I looked into this, but I remember working with a library that took in NURBS, and then approximated them with arcs and lines that were directly convertible to g-code. I used that as a side-step so that I could work with NURBS and run on an unmodified CNC router (that did not support them). I have no idea where that code is. You might check on github for things like tinynurbs, ... Hmmm... what languages do you want to program in?... On Wed, Aug 13, 2025 at 11:20 AM William F. Adams via Discuss < discuss@lists.openscad.org> wrote: > On Wednesday, August 13, 2025 at 10:30:19 AM EDT, Revar Desmera via > Discuss <discuss@lists.openscad.org> wrote: > > >NURBS are not Bézier curves. (Though Bézier curves can be made with > NURBS). As I understand it, while Bézier curves > >cannot exactly represent a circle, with the right knot values, NURBS can. > > Yep turns out adding support for this was an explicit effort: > > https://en.wikipedia.org/wiki/Non-uniform_rational_B-spline > > >>NURBS curves also feature a scalar weight for each control point. This > allows for more control over the shape of the curve > >>without unduly raising the number of control points. In particular, it > adds conic sections like circles and ellipses to the set of > >>curves that can be represented exactly. The term rational in NURBS > refers to these weights. > > Is there a 2D implementation of this suited to CNC? > > > On Wednesday, August 13, 2025 at 10:59:25 AM EDT, Rogier Wolff via Discuss > <discuss@lists.openscad.org> wrote: > > >We'd like to do 3D printing and CNCing with the results from the CAD > >process, right? > > Correct. > > >Well... if I design a round hole for an object and the object that > >goes inside, then I expect that object to be able to rotate. Any > >deviation from a true circle will cause it to "not be able to rotate". > > Yes, given a difference large enough to matter --- as I noted, showing the > inability of such curves to represent a true circle is left as an exercise > for the reader as well as showing the exact nature of the deviation. > > >If you create sufficient tolerances that it does rotate, you'll get > >it to fit tighter and less tight along the full rotation. > > If you have a CNC or 3D printer where this difference can be expressed as > a physical part so as to cause this issue, please let us know. Curious as > to which material and manufacturing process and size it can be made to > happen at. > > >This design and wanting to CNC that with a low tolerance on a good CNC > >isn't all that farfetched. So maybe my "visually a spline is close > >enough to a circle" is not quite good enough. > > For practical purposes, one equipment which is within the reach of an > individual, or even a typical small company, in my experience, it is. > > That said, as noted, the tool which I've been working on will express > arcs/circle segments/circles in a DXF or in G-code, so if folks find > OpenSCAD's inability to actually represent a circle as a circle, well there > is one programmatic option. > > That said, I would be interested in further informaton on file formats and > so forth which can accurately represent curves/circles/segments and the > possibility of implementing them either as part of > OpenSCAD/(Open)PythonSCAD, or in libraries which can be loaded into it and > used by it. > > William > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org >
JB
Jordan Brown
Wed, Aug 13, 2025 4:20 PM

On 8/12/2025 11:26 PM, Steve Lelievre via Discuss wrote:

Maybe the comment is meant to relate only to the narrow context of
user-defined modules or maybe I've misunderstood where the discussion
has got to, but in the general sense is there really only one type of
module? In my simplistic world view, there are two: primitive modules
that create shapes, and modifier modules that do things to shapes. My
distinction arises because some (native) modules accept children, some
do not. For example OpenSCAD, sensibly, rejects:  cube(1) sphere(1);

There is at the low levels only one kind of module.

A module can (but need not):

  • Add shapes to the model.
  • Accept children and transform them.
  • Emit output to the console.

It may do any or all of those.

It is somewhat useful to distinguish between what are sometimes called
"object modules", that only add a shape to the model, and what are
sometimes called "operator" modules, that only modify the shape(s)
passed to them by their children.  But that's only a model for
categorizing modules, not a difference in the module infrastructure per se.

You might distinguish flow-control modules (like "if" and "for"), but
they really fall into the "operator module" category.  (They to have
somewhat magic syntax and/or semantics.)

All of the built-in modules fall into one of those categories. (Well,
almost all: echo() and assert() don't.)

When you write your own module, you are not limited to doing only one of
the things listed above.  You can have a module that adds a shape and
accepts children and transforms them.

Here's a simple example:

module cube_topper(size) {
     cube(size);
     translate([size/2, size/2, size])
         children();
}

This module creates a cube, and puts its children centered on the top of
the cube.  You use it like so:

cube_topper(10) sphere(5);

It's a floor wax and a dessert topping!

Note that it's legal to call children() when there are no children
supplied, so this module can also be used to create a cube without
adding anything to it.

And of course you could stack calls:

cube_topper(10) cube_topper(7) sphere(5);
On 8/12/2025 11:26 PM, Steve Lelievre via Discuss wrote: > > Maybe the comment is meant to relate only to the narrow context of > user-defined modules or maybe I've misunderstood where the discussion > has got to, but in the general sense is there really only one type of > module? In my simplistic world view, there are two: primitive modules > that create shapes, and modifier modules that do things to shapes. My > distinction arises because some (native) modules accept children, some > do not. For example OpenSCAD, sensibly, rejects:  cube(1) sphere(1); > There is at the low levels only one kind of module. A module can (but need not): * Add shapes to the model. * Accept children and transform them. * Emit output to the console. It may do any or all of those. It is somewhat useful to distinguish between what are sometimes called "object modules", that only add a shape to the model, and what are sometimes called "operator" modules, that only modify the shape(s) passed to them by their children.  But that's only a model for categorizing modules, not a difference in the module infrastructure per se. You might distinguish flow-control modules (like "if" and "for"), but they really fall into the "operator module" category.  (They to have somewhat magic syntax and/or semantics.) All of the built-in modules fall into one of those categories. (Well, almost all: echo() and assert() don't.) When you write your own module, you are not limited to doing only one of the things listed above.  You can have a module that adds a shape *and* accepts children and transforms them. Here's a simple example: module cube_topper(size) { cube(size); translate([size/2, size/2, size]) children(); } This module creates a cube, and puts its children centered on the top of the cube.  You use it like so: cube_topper(10) sphere(5); It's a floor wax *and* a dessert topping! Note that it's legal to call children() when there are no children supplied, so this module can also be used to create a cube without adding anything to it. And of course you could stack calls: cube_topper(10) cube_topper(7) sphere(5);
JD
John David
Wed, Aug 13, 2025 4:24 PM

yea... lets set up a poll.  That said, if the pole said to change it, would
the admin do so?

On Wed, Aug 13, 2025 at 10:40 AM Jordan Brown via Discuss <
discuss@lists.openscad.org> wrote:

Since religious arguments rarely go anywhere useful, I'll try to avoid
further contributing to this one.

Perhaps we should have a poll.


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

yea... lets set up a poll. That said, if the pole said to change it, would the admin do so? On Wed, Aug 13, 2025 at 10:40 AM Jordan Brown via Discuss < discuss@lists.openscad.org> wrote: > Since religious arguments rarely go anywhere useful, I'll try to avoid > further contributing to this one. > > Perhaps we should have a poll. > > > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org >