discuss@lists.openscad.org

OpenSCAD general discussion Mailing-list

View all threads

is color an actual operator module ?

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.