commit aa92098f5625a336228aeb8ce8a6a705cce80e24 Author: dozens Date: Mon Nov 20 12:19:00 2023 -0700 🦆 diff --git a/README b/README new file mode 100644 index 0000000..f594ff6 --- /dev/null +++ b/README @@ -0,0 +1,3 @@ +# groffduck + +Let's make a duck in groff! diff --git a/duck.grn b/duck.grn new file mode 100644 index 0000000..4564b74 --- /dev/null +++ b/duck.grn @@ -0,0 +1,137 @@ +sungremlinfile +1 0 0 + + +CURVE BEZIER +0.65 2.95 +-0.1 1.75 +1.68 2.73 +* +3 3 +0 +CURVE BEZIER +0.65 2.95 +0.9 3.05 +1.14 2.80 +* +3 3 +0 +CURVE BEZIER +1.14 2.80 +1.35 2.65 +1.68 2.73 +* +3 3 +0 + + + +CURVE BEZIER +0.65 2.95 +0.8 4.05 +1.68 4.24 +* +3 3 +0 +CURVE BEZIER +1.68 4.24 +2.5 4.1 +2.53 2.4 +* +3 3 +0 + + + +CURVE BEZIER +0.8 2.24 +-0.2 1.1 +0.8 0.3 +* +3 3 +0 +CURVE BEZIER +0.8 0.3 +2 -0.1 +3.5 0.65 +* +3 3 +0 +CURVE BEZIER +3.5 0.65 +4.2 1.5 +3.5 2.83 +* +3 3 +0 +CURVE BEZIER +3.5 2.83 +3 2.5 +2.53 2.4 +* +3 3 +0 + + + +CURVE BEZIER +1.3 3.2 +1.38 3.45 +1.6 3.4 +* +3 3 +0 +CURVE BEZIER +1.6 3.4 +1.73 3.3 +1.67 3.1 +* +3 3 +0 +CURVE BEZIER +1.67 3.1 +1.6 2.9 +1.45 2.93 +* +3 3 +0 +CURVE BEZIER +1.45 2.93 +1.27 2.95 +1.3 3.2 +* +3 3 +0 + + + +CURVE BEZIER +0.77 3.32 +0.84 3.57 +1.03 3.5 +* +3 3 +0 +CURVE BEZIER +1.03 3.5 +1.12 3.4 +1.04 3.22 +* +3 3 +0 +CURVE BEZIER +1.04 3.22 +0.97 3.07 +0.87 3.07 +* +3 3 +0 +CURVE-BEZIER +0.87 3.07 +0.72 3.09 +0.77 3.32 +* +3 3 +0 + +-1 diff --git a/duck.me b/duck.me new file mode 100644 index 0000000..b6a8bef --- /dev/null +++ b/duck.me @@ -0,0 +1,596 @@ +.ds TI HOW TO DRAW A DUCK IN GROFF WITH GREMLIN AND PIC +.he |\*(TI||% +. +. +. +.tp +.sp 2i +.(l C +.sz +3 +.b "\*(TI" +.sp 0.5i +dozens +.sp 0.5i +.sz -1 +\*(td +.)l +.bp +. +. +. +.sh 1 "PIC" +.(x +PIC +.)x +.pp +There is a really cool project called tikzducks\** +.(f +\** https://github.com/samcarter/tikzducks +.)f +that is basically a bunch of different ducks +drawn in LaTeX. +They are hecking cute and you should go give them a look. +They are drawn using the TikZ\** +.(f +\** https://tikz.dev/ +.)f +.R +package, +which is a LaTeX package used for drawing complex pictures, charts, and figures. +.pp +Naturally, +when I see something done in LaTeX, +I am immediately tempted to attempt to recreate it in groff. +Unfortunately, +groff lacks any kind of sophisticated picture capabilities. +It provides only very primitive picture capabilities +via the pic language and preprocessor.\** +.(f +\** https://pikchr.org/home/uv/pic.pdf +.)f +.pp +For example, +here is some pic code +that will produce +a small chicken-like object +made from a spline, and a few circles, arcs, and lines. +.(b L +.(q +.TS +tab(;); +r | l. +1;# head +2;spline right then up then left then down +3;# eyes +4;fillval = 1 +5;circle fill rad 0.05 at 0.2,0.2 +6;circle fill rad 0.05 at 0,0.2 +7;# body +8;arc from 0.25,0 to 1,0 +9;arc to 0.50,0.30 +10;# legs +11;line at 1st arc .s - (0.02, 0) down 0.2 left 0.02 then left 0.1 +12;line at 1st arc .s + (0.04, 0) down 0.2 right 0.02 then right 0.1 +.TE +.(c +.i "Table 1: A pic program that creates a small duckling" +.)c +.(x t +Table 1: A pic program that creates a small duckling +.)x +.)q +.)b +.pp +The resulting duck +is very small and cute. +Also it is basically a baby chicken. +.PS +# head +spline right then up then left then down +# eyes +fillval = 1 +circle fill rad 0.05 at 0.2,0.2 +circle fill rad 0.05 at 0,0.2 +# body +arc from 0.25,0 to 1,0 +arc to 0.50,0.30 +# legs +line at 1st arc .s - (0.02, 0) down 0.2 left 0.02 then left 0.1 +line at 1st arc .s + (0.04, 0) down 0.2 right 0.02 then right 0.1 +.PE +.(c +.i "Figure 1: A baby Pic chicken" +.)c +.(x f +Figure 1: A baby Pic chicken +.)x +. +. +. +.sp +.sh 1 "GREMLIN" +.(x +GREMLIN +.)x +.pp +There is a second, +more obscure and archaic preprocessor +for the already relatively obscure and archaic groff +called grn. +It is the gremlin preprocessor, +and it will process gremlinfiles. +Gremlin caught my eye +because it supports bezier curves, +which will allow us to draw a much nicer duck. +.pp +grn is apparently only available while using the me macro set.\** +.(f +\** https://www.man7.org/linux/man-pages/man7/groff_me.7.html +.)f +So that's something to know. +In my experience, +the ms macros seem to be the most popular, +followed by the mom macro set. +I certainly wasn't familiar with 'me'. +I had to learn it just to produce this document. +.pp +Here is the output of the example gremlinfile from +the grn manpage. +.sp +.(b +.GS +width 2 +height 2 +file triangle.grn +.GE +.sp +.(c +.i "Figure 2: A Gremlin Triangle" +.)c +.(x f +Figure 2: A Gremlin Triangle +.)x +.)b +.sp +.pp +Gremlinfiles are super weird. +As far as I can tell, +GREMLIN is an old graphics editor from 1981.\** +And I guess these gremlinfiles are maybe their save file format? +Anyway, +somebody added gremlin support to groff +via the +.i grn +preprocessor, +and it has just quietly stuck around all this time. +There are some Pic tutorials out there. +But I can find basically nothing on Gremlin. +.(f +\** A GREMLIN Tutorial for the SUN Workstation. +Opperman, Thompson, Chen. Appendix A. +.br +https://www2.eecs.berkeley.edu/Pubs/TechRpts/1987/CSD-87-322.pdf +.)f +.(z +.(l +.TS +tab(;); +r | l. +1;sungremlinfile +2;1 0 0 +3;POLYGON +4;224 416 +5;96 160 +6;384 160 +7;* +8;3 3 +9;0 +10;CENTCENT +11;240 128 +12;* +13;2 3 +14;10 A Triangle +15;-1 +.TE +.(c +.i "Table 2: An Example Gremlinfile. It makes a triangle and a label that says 'Triangle'" +.)c +.(x t +Table 2: An Example Gremlinfile +.)x +.)l +.)z +.pp +A gremlinfile starts with two lines: "sungremlinfile" (or "gremlinfile"), and "1 0 0". (See lines 1 - 2 on Table 2.) sungremlinfile is the SUN workstation version of the file format, whereas "gremlinfile" is the format used for the AED graphics terminal.\** I chose to go with the SUN version because you can use element names when defining elements (see below), whereas with the AED version, you can only refer to elements by id number in the gremlinfile. And I didn't feel like looking up element ids in order to use them. +The manual literally says of the "1 0 0" line: "The stuff on this line isn't all that important; We suggest using 1 0.00 0.00." So that's neat. I guess we can just ignore what that line means. +A gremlinfile always ends with a "-1" on a line. (See line 15 on Table 2.) +.(f +\** It is difficult to find info on the AED graphics terminal +thanks to the ubiquity of the Automated External Defibrillator. +But check out these dope brochures! +http://bitsavers.org/pdf/aed/brochures/ +.)f +.pp +Following the opening pair of lines are a series of elements. +Element names are followed by a series of coordinates, +followed by an asterisk (or a "-1 -1" in the AED gremlinfile; don't know why), a "brush / size" line, and a text label line. See lines 3 - 9, and 10 - 14. +.pp +The coordinates mean different things depending on the element. +For example, for polygons, they're coordinates of the corners of the polygon. +And for arcs and circles, they're coordinates for the center and radius of the circle arc. +.pp +The "brush / size" line can also mean different things. For text elements, brush means bold, italic, regular text, etc. For polygons, size means fill pattern. So you really just gotta have the manual out when you're doing stuff I guess. +.pp +The text label line is straightforward, +but unusual by today's standards. +If you're gonna have text, +you gotta put how many characters long the string is, +and then the string. +See line 14. +And if you don't have a string, +then you have to put 0 +to indicate a zero length string. +Like on line 9. +Isn't that funny! +. +. +. +.pp +Anyway, let's make a gremlin duck! +I'm just going to copy the LaTeX curves +from the answer on stackexchange\** +and tweak them a little bit +and see how it looks. +(You can see all of the gremlin that creates this duck +in Appendix A; It is too long to include here.) +.(f +\** https://tex.stackexchange.com/a/471540 +.)f +.sp +.(b +.GS +width 2 +height 2 +file duck.grn +.GE +.(c +.i "Figure 3: A Gremlin duck" +.)c +.(x f +Figure 3: A Gremlin duck +.)x +.)b +.sp +.pp +It is kind of ugly, but also weirdly cute! +I expected the bezier curves to be more smooth and curvy. +I feel like I could have gotten something almost as good just using Pic splines. +. +. +. +.sp +.sh 1 "PIC REDUX" +.(x +PIC REDUX +.)x +.pp +So maybe let's just try this again with pic arcs and splines? +.PS 2 +# beak +spline left .5 down 1 \ + then right 1 up .8 \ + then left .2 \ + then left .1 up .2 \ + then to (0,0) +# head +arc cw rad .5 from 1st spline +arc cw rad .5 +line down .2 +#body +spline right .2 then right .2 up .15 +spline down .6 right .4 \ + then down .6 left .4 \ + then left .8 down .2 \ + then left .65 up .4 \ + then up .48 right .1 +# eye macro +copy thru { + circle rad .1 at $1, $2 + circle fill rad .05 at $1+.05, $2-.02 +} +.5 .1 +.2 .2 +.PE +.(c +.i "Figure 4: Pic duck 2.0." +.)c +.(c +.i "You may feel that the lines are not quite right. But they are. I just drew them myself.\**" +.)c +.(x f +Figure 4: Pic duck 2.0 +.)x +.(f +\** Apologies to George Harrison. But it's only a Northern Duck. +.)f +.pp +This honestly looks much better to me. +The lines are sharper +and the curves are smoother. +Pic is also much nicer to write than gremlin. +You can write comments for one. +You can write macros, loops, and conditionals. +And I find the Logo-esque\** "up, down, then..." syntax +to be much easier to reason about +than gremlin's coordinate based syntax. +.(f +\** https://en.wikipedia.org/wiki/Logo_(programming_language) +.)f +.pp +Here are the pic commands that created this duck. +.(b L +.(q +.TS +tab(;); +r | l. +1;.PS 2 +2;# BEAK +3;spline left .5 down 1 \[rs] +4; then right 1 up .8 \[rs] +5; then left .2 \[rs] +6; then left .1 up .2 \[rs] +7; then to (0,0) +8;# HEAD +9;arc cw rad .5 from 1st spline +10;arc cw rad .5 +11;line down .2 +12;#BODY +13;spline right .2 then right .2 up .15 +14;spline down .6 right .4 \[rs] +15; then down .6 left .4 \[rs] +16; then left .8 down .2 \[rs] +17; then left .65 up .4 \[rs] +18; then up .48 right .1 +19;# EYE MACRO +20;copy thru { +21; circle rad .1 at $1, $2 +22; circle fill rad .05 at $1+.05, $2-.02 +23;} +24;.5 .1 +25;.2 .2 +26;.PE +.TE +.(c +.i "Table 3: Pic Duck 2.0." +.)c +.(x t +Table 3: Pic Duck 2.0. +.)x +.)q +.)b +. +. +. +.sp +.sh 1 "CONCLUSION" +.(x +CONCLUSION +.)x +.pp +Gremlin is the only way that I know to get actual bezier curves +out of the box +using a groff preprocessor. +It is possibly the most obscure +of groff's preprocessors. +And I don't think it looks that good honestly. +I think there is little reason to use it +other than as a curious novelty +or an academic exercise. +At least as far as drawing ducks is concerned. +The format is kind of arbitrary and inconsistent. +And its use of bare coordinates really does make it feel +as though it is meant to be autogenerated from a gui graphics program, +and not really meant to be written by hand. +Especially when compared to Pic's much more ergonomic +"left then right then down" syntax +and its ability to reference previous elements by name. +.pp +Having tried it, +I would ultimately recommend just using pic splines +if you need pictures with curves. +Or just making something in Inkscape. +(You can convert the svg to eps with imagemagick, +and then embed it in your groff with the .PSPIC macro.) +.pp +Okay that's it! +Thanks for learning all about drawing ducks in groff with me! +Bye! +.sp 1i +.PS 4 +# beak +spline left .5 down 1 \ + then right 1 up .8 \ + then left .2 \ + then left .1 up .2 \ + then to (0,0) +# head +arc cw rad .5 from 1st spline +arc cw rad .5 +line down .2 +#body +spline right .2 then right .2 up .15 +spline down .6 right .4 \ + then down .6 left .4 \ + then left .8 down .2 \ + then left .65 up .4 \ + then up .48 right .1 +# eye macro +copy thru { + circle rad .1 at $1, $2 + circle fill rad .05 at $1+.05, $2-.02 +} +.5 .1 +.2 .2 +.PE +. +. +. +.bp +.uh "APPENDIX A: DUCK GREMLINFILE" +.(x +APPENDIX A: DUCK GREMLINFILE +.)x +.pp +Here is the entire contents of the gremlinfile +that produced the duck. +It is not very interesting to read +because it is just a solid wall of CURVE BEZIER elements. +I don't know how to include comments in the gremlinfile itself, +but I have labeled the element sections here for the sake of legibility. +.sp +.(q +.hl +.TS +tab(;); +r | l l. +1;sungremlinfile;header content +2;1 0 0; +3;CURVE BEZIER; Start beak section +4;0.65 2.95; +5;-0.1 1.75; +6;1.68 2.73; +7;*; +8;3 3; +9;0; +10;CURVE BEZIER; +11;0.65 2.95; +12;0.9 3.05; +13;1.14 2.80; +14;*; +15;3 3; +16;0; +17;CURVE BEZIER; +18;1.14 2.80; +19;1.35 2.65; +20;1.68 2.73; +21;*; +22;3 3; +23;0;End Beak Section +24;CURVE BEZIER;Start Head section +25;0.65 2.95; +26;0.8 4.05; +27;1.68 4.24; +28;*; +29;3 3; +30;0; +31;CURVE BEZIER; +32;1.68 4.24; +33;2.5 4.1; +34;2.53 2.4; +35;*; +36;3 3; +37;0;End Head section +38;CURVE BEZIER;Start body +39;0.8 2.24; +40;-0.2 1.1; +41;0.8 0.3; +42;*; +43;3 3; +44;0; +45;CURVE BEZIER; +46;0.8 0.3; +47;2 -0.1; +48;3.5 0.65; +49;*; +50;3 3; +51;0; +52;CURVE BEZIER; +53;3.5 0.65; +54;4.2 1.5; +55;3.5 2.83; +56;*; +57;3 3; +58;0; +59;CURVE BEZIER; +60;3.5 2.83; +61;3 2.5; +62;2.53 2.4; +63;*; +64;3 3; +65;0;End body +66;CURVE BEZIER;Right eye +67;1.3 3.2; +68;1.38 3.45; +69;1.6 3.4; +70;*; +71;3 3; +72;0; +73;CURVE BEZIER; +74;1.6 3.4; +75;1.73 3.3; +76;1.67 3.1; +77;*; +78;3 3; +79;0; +80;CURVE BEZIER; +81;1.67 3.1; +82;1.6 2.9; +83;1.45 2.93; +84;*; +85;3 3; +86;0; +87;CURVE BEZIER; +88;1.45 2.93; +89;1.27 2.95; +90;1.3 3.2; +91;*; +92;3 3; +93;0;End right eye +94;CURVE BEZIER;Left eye\** +95;0.77 3.32; +96;0.84 3.57; +97;1.03 3.5; +98;*; +99;3 3; +100;0; +101;CURVE BEZIER; +102;1.03 3.5; +103;1.12 3.4; +104;1.04 3.22; +105;*; +106;3 3; +107;0; +108;CURVE BEZIER; +109;1.04 3.22; +110;0.97 3.07; +111;0.87 3.07; +112;*; +113;3 3; +114;0; +115;CURVE-BEZIER; +116;0.87 3.07; +117;0.72 3.09; +118;0.77 3.32; +119;*; +120;3 3; +121;0;End left eye +122;-1;end gremlinfile +.(q +.TE +.hl +.(f +\** Rest in peace, Lisa "Left Eye" Lopez +.)f +. +. +. +.hx +.bp +.b CONTENTS +.xp +.sp +.b TABLES +.xp t +.sp +.b FIGURES +.xp f diff --git a/duck.pdf b/duck.pdf new file mode 100644 index 0000000..1c5dfb5 Binary files /dev/null and b/duck.pdf differ diff --git a/justfile b/justfile new file mode 100644 index 0000000..a397af0 --- /dev/null +++ b/justfile @@ -0,0 +1,11 @@ +# list all recipes +default: + just --list --unsorted + +# make the pdf +pdf: + groff -Tpdf -me -t -p -g duck.me > duck.pdf + +# watch for changes +watch: + ls duck.me duck.grn | entr just pdf diff --git a/triangle.grn b/triangle.grn new file mode 100644 index 0000000..bbacc6a --- /dev/null +++ b/triangle.grn @@ -0,0 +1,18 @@ +sungremlinfile +1 0 0 + +POLYGON +224 416 +96 160 +384 160 +* +3 3 +0 + +CENTCENT +240 128 +* +2 3 +10 A Triangle + +-1