1# Pikchr User Manual
2
3# Introduction
4
5This is a guide to generating diagrams using Pikchr
6(pronounced "Picture").  This guide is
7designed to teach you to use Pikchr.  It is not a reference for the
8Pikchr language (that is a [separate document][gram]) nor is it an explanation
9of why you might want to use Pikchr.  The goal here is to provide
10a practical and accessible tutorial on using Pikchr.
11
12[gram]: ./grammar.md
13
14# Running Pikchr Scripts <a id="running"></a>
15
16The design goal of Pikchr is to enable embedded line diagrams in Markdown or other
17simple markup languages.  The details on how to embedded Pikchr in Markdown is
18[covered separately][embed].  For the purpose of this tutorial, we will only write
19pure Pikchr scripts without the surrounding markup.  To experiment
20with Pikchr, visit the [](/pikchrshow) page on the website hosting
21this document (preferably in a separate window).  Type in the following
22script and press the Preview button:
23<a id="firstdemo"></a>
24
25~~~~~ pikchr source toggle indent
26     line; box "Hello," "World!"; arrow
27~~~~~
28
29If you do this right, the output should appear as:
30
31~~~~~ pikchr toggle indent
32     line; box "Hello," "World!"; arrow
33~~~~~
34
35So there you go: you've created and rendered your first diagram using
36Pikchr!  You will do well to keep that /pikchrshow screen handy, in a
37separate browser window, so that you can try out scripts as you proceed
38through this tutorial.
39
40[embed]: ./usepikchr.md
41
42# Viewing Pikchr Script Source Code For This Document <a name="viewsrc"></a>
43
44For this particular document, you can click on any of the diagrams
45rendered by Pikchr and the display will convert to showing you the
46original Pikchr source text.  Click again to go back to seeing the
47rendered diagram.
48
49The click-to-change-view behavior is a property of this one
50particular document and is not a general capability of Pikchr. On
51other documents containing Pikchr diagrams that are generated using Fossil
52you can use ctrl-click (alt-click on Macs) to toggle the view.
53That is, click on the diagram while holding down the Ctrl key or the Alt key.
54This is not possible if
55you are on a tablet or phone, since you don't have a Ctrl or Alt key to hold
56down there.  Other systems might not implement the view-swapping behavior
57at all.  This is a platform-depending feature that is one layer above
58Pikchr itself.
59
60# About Pikchr Scripts <a id="about"></a>
61
62Pikchr is designed to be simple.  A Pikchr script is
63just a sequence of Pikchr statements, separated by either new-lines or
64semicolons.  The "Hello, world!" example above used three statements,
65a "line", a "box", and an "arrow", each separated by semicolons.
66
67Whitespace (other than newlines) and comments are ignored.  Comments in
68pikchr can be in the style of TCL, C, or C++.  That is to say, comments
69consist of a "`#`" or "`//`"  and include all characters up to but
70not including the next new-line, or all text
71in between "`/*`" and the first following "`*/`".
72The example script above could be rewritten with each statement on
73a separate line, and with comments describing what each statement is
74doing:
75
76~~~~~ pikchr source toggle indent
77    # The first component of the drawing is a line
78    line
79    // The second component is a box with text "Hello, World!"
80    box "Hello," "World!"
81    /* Finally an arrow */
82    arrow
83~~~~~
84
85Remember that new-lines separate statements.  If you have a long statement
86that needs to be split into multiple lines, escape the newline with
87a backslash character and the new-line will be treated as any other space:
88
89~~~~~ pikchr source toggle indent
90    line
91    box \
92       "Hello," \
93       "World!"
94    arrow
95~~~~~
96
97So, a Pikchr script is just a list of statements, but what is a statement?
98
99# Pikchr Statements <a id="statements"></a>
100
101*Most* statements are descriptions of a single graphic object that
102becomes part of the diagram.  The first token of the statement is the
103object class-name.  The following classes are currently supported:
104
105~~~~~ pikchr toggle indent
106box "box"
107circle "circle" at 1 right of previous
108ellipse "ellipse" at 1 right of previous
109oval "oval" at .8 below first box
110cylinder "cylinder" at 1 right of previous
111file "file" at 1 right of previous
112line "line" above from .8 below last oval.w
113arrow "arrow" above from 1 right of previous
114spline from previous+(1.8cm,-.2cm) \
115   go right .15 then .3 heading 30 then .5 heading 160 then .4 heading 20 \
116   then right .15
117"spline" at 3rd vertex of previous
118dot at .6 below last line
119text "dot" with .s at .2cm above previous.n
120arc from 1 right of previous dot
121text "arc" at (previous.start, previous.end)
122text "text" at 1.3 right of start of previous arc
123~~~~~
124
125A statement can be only the class-name and nothing else, but the class-name
126is usually followed by one or more "attributes".  Attributes are used
127to modify the appearance of the object, or to position the object relative
128to prior objects.
129
130So to revisit the ["Hello, World" demonstration script above](#firstdemo),
131we see that that script contains three object descriptions:
132
133  1.  A "line" object with no attributes (meaning that the line is shown
134      with no changes to its default appearance).
135  2.  A "box" object with two string literal attributes.  The string
136      literal attributes cause the corresponding strings to be drawn
137      inside the box.
138  3.  An "arrow" object with no attributes.
139
140# Layout <a id="layout"></a>
141
142By default, objects are stacked beside each other from left to right.
143The Pikchr layout engine keeps track of the "layout direction", which
144can be one of "right", "down", "left", or "up".  The layout direction
145defaults to "right", but you can change it using a statement which
146consists of just the name of the new direction.  So,
147if we insert the "down" statement in front of our test script, like
148this:
149
150~~~~~ pikchr source toggle indent
151    down
152    line
153    box  "Hello,"  "World!"
154    arrow
155~~~~~
156
157Then the objects are stacked moving downward:
158
159~~~~~ pikchr toggle indent
160    down
161    line
162    box  "Hello,"  "World!"
163    arrow
164~~~~~
165
166Or, you can change the layout direction to "left":
167
168~~~~~ pikchr toggle indent
169    left
170    line
171    box  "Hello,"  "World!"
172    arrow
173~~~~~
174
175Or to "up":
176
177~~~~~ pikchr toggle indent
178    up
179    line
180    box  "Hello,"  "World!"
181    arrow
182~~~~~
183
184It is common to stack line objects (lines, arrows, splines) against
185block objects (boxes, circles, ovals, etc.), but this is not required.
186You can stack a bunch of block objects together.
187For example:
188
189~~~~~ pikchr source toggle indent
190    box; circle; cylinder
191~~~~~
192
193Yields:
194
195~~~~~ pikchr toggle indent
196    box; circle; cylinder
197~~~~~
198
199More often, you want to put space in between the block objects.
200The special "move" object exists for that purpose.  Consider:
201
202~~~~~ pikchr source toggle indent
203    box; move; circle; move; cylinder
204~~~~~
205
206This script creates the same three block objects but with
207whitespace in between them:
208
209~~~~~ pikchr toggle indent
210    box; move; circle; move; cylinder
211~~~~~
212
213Implementation note:  A "move" is really just an invisible "line".  So
214the following script generates the same output as the previous.
215([Try it!](/pikchrshow?content=box;line%20invisible;circle;line%20invisible;cylinder))
216
217~~~~~ pikchr source toggle indent
218    box; line invisible; circle; line invisible; cylinder
219~~~~~
220
221# Controlling Layout Using Attributes <a id="attributes"></a>
222
223The automatic stacking of objects is convenient in many cases, but
224most diagrams will want some objects placed somewhere other than
225immediately adjacent to their predecessor.  For that reason, layout
226attributes are provided that allow precise placement of objects.
227
228To see how this works, consider the previous example of a box, circle,
229and cylinder separated by some space.  Suppose we want to draw an arrow
230that goes downward out of the box, then right, then up into the
231cylinder.  The complete script might look something like this:
232
233~~~~~ pikchr source toggle indent
234    box; move; circle; move; cylinder
235    arrow from first box.s \
236          down 1cm \
237          then right until even with first cylinder \
238          then to first cylinder.s
239~~~~~
240
241This script results in the following diagram:
242
243
244~~~~~ pikchr toggle indent
245    box; move; circle; move; cylinder
246    arrow from first box.s \
247          down 1cm \
248          then right until even with first cylinder \
249          then to first cylinder.s
250~~~~~
251
252That is indeed the image we want, but there are a lot of words on
253that "arrow" statement!  Don't panic, though.  It's actually pretty
254simple.  We'll take it apart and explain it piece by piece.
255
256First note that the "arrow" statement is broken up into four separate
257lines of text, with a "`\`" at the end of the first three lines to
258prevent the subsequent new-line from prematurely closing the statement.
259Splitting up the arrow into separate lines this way is purely for
260human readability.  If you are more comfortable putting the whole
261statement on one line, that is fine too.  Pikchr doesn't care.  Just
262be sure to remember the backslashes if you do split lines!
263
264The attributes on the "arrow" statement describe the path taken by
265the arrow.  The first attribute is "`from first box.s`".  This "from"
266attribute specifies where the arrow starts.  In this case, it starts
267at the "s" (or "south") anchor point of the "first box".  The "first box"
268part is probably self explanatory.  (You can also write it as
269"1st box" instead of "first box", and in fact legacy-PIC requires
270the use of "1st" instead of "first".)  But what is the ".s" part?
271
272Every block object has eight anchor points on its perimeter that are named
273for compass points, like this:
274
275~~~~~ pikchr toggle indent
276A: box
277dot color red at A.nw ".nw " rjust above
278dot same at A.w ".w " rjust
279dot same at A.sw ".sw " rjust below
280dot same at A.s ".s" below
281dot same at A.se " .se" ljust below
282dot same at A.e " .e" ljust
283dot same at A.ne " .ne" ljust above
284dot same at A.n ".n" above
285dot same at A.c " .c" ljust
286A: circle at 1.5 right of A
287dot color red at A.nw ".nw " rjust above
288dot same at A.w ".w " rjust
289dot same at A.sw ".sw " rjust below
290dot same at A.s ".s" below
291dot same at A.se " .se" ljust below
292dot same at A.e " .e" ljust
293dot same at A.ne " .ne" ljust above
294dot same at A.n ".n" above
295dot same at A.c " .c" ljust
296A: cylinder at 1.5 right of A
297dot color red at A.nw ".nw " rjust above
298dot same at A.w ".w " rjust
299dot same at A.sw ".sw " rjust below
300dot same at A.s ".s" below
301dot same at A.se " .se" ljust below
302dot same at A.e " .e" ljust
303dot same at A.ne " .ne" ljust above
304dot same at A.n ".n" above
305dot same at A.c " .c" ljust
306~~~~~
307
308As you can see, there is also a ninth point in the middle called ".c".
309Every block object has these anchor points; you can refer to them
310when positioning the object itself, or when positioning other objects
311relative to the block object.  In this case, we are starting the
312arrow at the ".s" anchor of the box.
313
314The next phrase on the "arrow" statement is "`down 1cm`".  As you
315might guess, this phrase causes the arrow to move downward from its
316previous position (its starting point) by 1 centimeter.  This phrase
317highlights a key enhancement of Pikchr over PIC, which did
318everything in inches only.  No units were allowed.  Pikchr allows
319you to attach units to measurements, as in this case where it is
320"1cm".  Internally, Pikchr still keeps track of everything in inches
321for compatibility with PIC, so the "1cm" token is really just an
322alternative spelling for the numeric constant "0.39370078740157480316",
323which is the inch-equivalent of 1 centimeter.  Surely you agree that
324"1cm" is much easier to read and write!  Other units recognized by Pikchr
325are "px" for pixels, "pt" for points, "pc" for picas, "mm" for millimeters,
326and of course "in" for inches.  Inches are assumed if no units are
327specified.
328
329Back to our arrow: we have now established a path for the arrow
330down 1 centimeter from the ".s" anchor of the box.  The next phrase
331is:  "`then right until even with first cylinder`".
332You can perhaps guess that this means that the arrow should continue
333to the right until it is lined up below the first cylinder.  You,
334the diagram designer, don't know (and don't really want to know)
335how far apart the box and the cylinder are, so you can't tell it
336exactly how far to go.  This phrase is a convenient way of telling
337Pikchr to "make the line long enough".
338
339Note that the "`first cylinder`" part of the "until even with"
340phrase is actually an abbreviation for "`first cylinder.c`" - the
341center of the cylinder.  This is what we want.  You could also
342write "`first cylinder.s`" if you want.
343
344The "until even with" phrase is not found in the original version of PIC.  In that
345system, you would have to do some extra math to figure out the
346distance for yourself, something like
347"`then right (1st cylinder.s.x - 1st box.s.x)`".  We think the
348"until even with" phrase is easier to use and understand.
349
350The final phrase in the "arrow" statement is
351"`then to first cylinder.s`".  This phrase tells the arrow to go
352from wherever it is at the moment directly to the ".s" anchor
353of the cylinder.
354
355# The Advantage Of Relative Layout <a id="relative"></a>
356
357Notice that our sample diagram contains no coordinates and only
358one hard-coded distance, the "down 1cm" bit in the "arrow" statement.  The script
359is written in such a way that the script-writer does not have
360to do a lot of distance calculation.  The layout compensates
361automatically.
362
363For example, suppose you come back to this script later and
364decide you need to insert an ellipse in between the circle and
365the cylinder.  This is easily accomplished:
366
367~~~~~ pikchr source toggle indent
368    box; move; circle; move; ellipse; move; cylinder
369    arrow from first box.s \
370          down 1cm \
371          then right until even with first cylinder \
372          then to first cylinder.s
373~~~~~
374
375We simply add the ellipse (and an extra "move") on the first line.
376Even though the coordinate positions of the objects have adjusted,
377the description of the arrow that connects the box to the
378cylinder is not based on coordinates or absolute distances,
379so it does not have to change at all.  Pikchr
380compensates automatically:
381
382~~~~~ pikchr toggle indent
383    box; move; circle; move; ellipse; move; cylinder
384    arrow from first box.s \
385          down 1cm \
386          then right until even with first cylinder \
387          then to first cylinder.s
388~~~~~
389
390Both PIC and Pikchr allow you to specify hard-coded coordinates
391and distances when laying out your diagram, but you are encouraged
392to avoid that approach.  Instead, place each new object you create
393relative to the position of prior objects.
394Pikchr provides many mechanisms for specifying the location
395of each object in terms of the locations of its predecessors.  With
396a little study of the syntax options available to you (and discussed
397further below) you will be generating complex diagrams using Pikchr
398in no time.
399
400# Single-Pass Design <a id="single-pass"></a>
401
402Both Pikchr and PIC operate on a single-pass design.  Objects
403can refer to other objects that occur before them in the script, but not
404to objects that occur later in the script.  Any computations that go
405into placing an object occur as the object definition is parsed.  As soon
406as the newline or semicolon that terminates the object definition is
407reached, the size, location, and characteristics of the object are
408fixed and cannot subsequently be altered.  (One exception:  sub-objects that
409are part of a `[]`-container (discussed later) are placed relative to the
410origin of the container.  Their shape and locations relative to each
411other are fixed, but their final absolute position is not fixed until
412the `[]`-container itself is fixed.)
413
414The single-pass approach contributes to the conceptual simplicity of
415Pikchr (and PIC).  There is no "solver" that has to work through
416forward and backward layout constraints to find a solution.  This
417simplicity of design helps to keep Pikchr scripts easy to write and
418easy to understand.
419
420# Labeling Objects <a id="labeling"></a>
421
422The previous example used the phrases like "`first box`" and "`first cylinder`"
423to refer to particular objects.  There are many variations on this naming
424scheme:
425
426  *  "`previous`" &larr; the previous object regardless of its class
427  *  "`last circle`" &larr; the most recently created circle object
428  *  "`3rd last oval`" &larr; the antipenultimate oval object
429  *  "`17th ellipse`" &larr; the seventeenth ellipse object
430  *  ... and so forth
431
432These relative and ordinal references work, but they can be fragile.
433If you go back later and insert a new
434object in the stream, you can mess up the counting.  Or, for that matter,
435you might just miscount.
436
437In a complex diagram, it often works better to assign symbolic names to
438objects, which we call “labels” in Pikchr. A label begins with a capital
439letter followed by some number of regular ASCII letters, digits or
440underscores, followed by a colon. This must come immediately before
441an object, without an intervening newline.
442Afterwards, the object can be referred to
443by that label.
444
445Consider how this simplifies our previous example:
446
447~~~~~ pikchr source toggle indent
448    B1:  box; move;
449         circle; move;
450         ellipse; move;
451    C1:  cylinder
452         arrow from B1.s \
453            down 1cm \
454            then right until even with C1 \
455            then to C1.s
456~~~~~
457
458By giving symbolic names to the box (B1) and cylinder (C1), the arrow path
459description is simplified.  Furthermore, if the ellipse gets changed
460into another cylinder, the arrow still refers to the correct cylinder.
461
462The indentation of the lines following each symbolic name
463above is syntactically unimportant: it serves only to improve human
464readability. Nevertheless, this is typical coding style for Pikchr
465and PIC before it.
466
467# Layout Of Block Objects <a id="block-objects"></a>
468
469For lines (and arrows and splines), you have to specify a path that the line
470follows, a path that might involve multiple bends and turns.  Defining the location
471of block objects is easier: you just provide a single location to place
472the object.  Ideally, you should place the object relative to some other
473object, of course.
474
475Let's say you have box, and you want to position a circle 2 centimeters to the
476right of that box.  You simply use an "`at`" attribute on the circle to tell it
477to position itself 2 cm to the right of the box:
478
479~~~~~ pikchr source toggle indent
480  B1: box
481      circle at 2cm right of B1
482~~~~~
483
484The resulting diagram is:
485
486~~~~~ pikchr toggle indent
487  B1: box
488      circle at 2cm right of B1
489
490  X1: line thin color gray down 50% from 2mm south of B1.s
491  X2: line same from (last circle.s,X1.start)
492      arrow <-> thin from 3/4<X1.start,X1.end> right until even with X2 \
493         "2cm" above color gray
494      assert( last arrow.width == 2cm )
495~~~~~
496
497(We’ve added gray dimension lines purely for illustration.  Click the
498diagram [per the instructions above](#viewsrc) to see that they do not
499change the example, only add to it.)
500
501[fossil]: https://fossil-scm.org/
502
503The circle is positioned so that its *center* is 2 centimeters to the
504right of the *center* of the box.  If what you really wanted is that the
505left (or west) side of the circle is 2 cm to the right (or east)
506of the box, then just say so:
507
508~~~~~ pikchr source toggle indent
509  B1: box
510  C1: circle with .w at 2cm right of B1.e
511~~~~~
512
513Normally an "`at`" clause will set the center of an object, but if
514you add a "`with`" prefix you can specify any other anchor
515point of the object to be the reference for positioning.  The Pikchr
516script above is saying "make the C1.w point be 2 cm right of B1.e".
517And we have:
518
519~~~~~ pikchr toggle indent
520  B1: box
521  C1: circle with .w at 2cm right of B1.e
522
523  X1: line thin color gray down 50% from 2mm south of B1.se
524  X2: line same from (C1.w,X1.start)
525      arrow <-> thin from 3/4<X1.start,X1.end> right until even with X2 \
526         "2cm" above color gray
527      assert( last arrow.width == 2cm )
528~~~~~
529
530That's the whole story behind positioning block objects on a diagram.
531You just add an attribute of the form:
532
533>  **with** *reference-point* **at** *position*
534
535And Pikchr will place the specified reference-point of the object at
536*position*.  If you omit the "`with`" clause, the center of the
537object ("`.c`") is used as the *reference-point*.  The power of Pikchr
538comes from the fact that "*position*" can be a rather complex expression.
539The previous example used a relatively simple *position*
540of "`2cm right of B1.e`".  That was sufficient for our simple diagram.
541More complex diagrams can have more complex *position* phrases.
542
543## Automatic Layout Of Block Objects <a id="auto-layout-block"></a>
544
545If you omit the "`at`" attribute from a block object, the object is positioned
546as if you had used the following:
547
548>  `with .start at previous.end`
549
550Except, the very first object in the script has no "previous" and so it
551is positioned using:
552
553>  `with .c at (0,0)`
554
555Let's talk little more about the usual case:
556"`with .start at previous.end`".  The "`previous`" keyword means the
557previous object in the script.  (You can also use the keyword "`last`"
558for this purpose.)  So we are positioning the current object relative
559to the previous object.  But what about the ".start" and ".end"?
560
561Remember that every object has 8 anchor points whose names correspond
562to compass directions:  ".n", ".ne", ".e", ".se", ".s", ".sw", ".w",
563and ".nw", plus the ninth anchor, the center point ".c".  Every object
564also has ".start" and ".end" anchor
565points, but their position varies depending on the
566layout direction that is current when the object is created.
567
568<blockquote>
569<table border="1" cellpadding="10px" cellspacing="0">
570<tr><th>Layout Direction<th>.start<th>.end
571<tr><td>right<td>.w<td>.e
572<tr><td>down<td>.n<td>.s
573<tr><td>left<td>.e<td>.w
574<tr><td>up<td>.s<td>.n
575</table></blockquote>
576
577Recall the earlier example that consisted of three objects stacked
578together:
579
580~~~~~ pikchr source toggle indent
581    right; box; circle; cylinder
582~~~~~
583
584(I added a "`right`" at the beginning to make the layout direction
585clear, but as "right" is the default layout direction, so it doesn't change
586anything.)
587
588Armed with our new knowledge of how "`at`"-less block objects are
589positioned, we can better understand what is going on.  The box is
590the first object.  It gets positioned with its center at (0,0), which
591we can show by putting a red dot at (0,0):
592
593~~~~~ pikchr source toggle indent
594    right; box; circle; cylinder
595    dot color red at (0,0)
596~~~~~
597
598~~~~~ pikchr toggle indent
599    right; box; circle; cylinder
600    dot color red at (0,0)
601~~~~~
602
603Because the layout direction is "right", the start and end of the box
604are the .w and .e anchor points.  Prove this by putting more colored dots
605at those points and rendering the result:
606
607~~~~~ pikchr source toggle indent
608    right; box; circle; cylinder
609    dot color green at 1st box.start
610    dot color blue at 1st box.end
611~~~~~
612
613~~~~~ pikchr toggle indent
614    right; box; circle; cylinder
615    dot color green at 1st box.start
616    dot color blue at 1st box.end
617~~~~~
618
619Similarly, we can show that the .start and .end of the circle are its
620.w and .e anchor points.  (Add new color dots to prove this to yourself,
621if you like.)  And clearly, the .start of the circle is directly on top
622of the .end of the box.
623
624Now consider what happens if we change the layout direction after the
625circle is created but before the cylinder is created:
626
627~~~~~ pikchr source toggle indent
628    right; box; circle; down; cylinder
629~~~~~
630
631This script works a little differently on Pikchr than it does on PIC.
632The change in behavior is deliberate, because we feel that the Pikchr
633approach is better.  On PIC, the diagram above would be rendered
634like this:
635
636~~~~~ pikchr toggle indent
637    right; box; circle; cylinder with .n at previous.e
638~~~~~
639
640But on Pikchr the placement of the cylinder is different:
641
642~~~~~ pikchr toggle indent
643    right; box; circle; cylinder with .n at previous.s
644~~~~~
645
646Let's take apart what is happening here.  In both systems, after
647the "circle" object has been parsed and positioned, the .end of
648the circle is the same as .e, because the layout direction is "right".
649If we omit the "down" and "cylinder" and draw a dot at the ".end" of
650circle to show where it is, we can see this:
651
652~~~~~ pikchr toggle indent
653    right; box; circle
654    dot color red at last circle.end
655~~~~~
656
657The next statement is "down".  The "down" statement changes the layout
658direction to "down" in both systems.  In legacy PIC the .end of the circle
659remains at the .e anchor.  Then when the "cylinder" is positioned,
660its ".start" is at .n because the layout direction is now "down",
661so the .n point of the cylinder is aligned to the .e point of
662the circle.
663
664Pikchr works like PIC with one important change: when the "down" statement
665is evaluated, Pikchr also moves the ".end" of the previous object
666to a new location that is appropriate for the new direction. In other
667words, the down command moves the .end of the circle from .e to .s.
668You can see this by setting a red dot at the .end of
669the circle *after* the "down" command:
670
671~~~~~ pikchr toggle indent
672    right; box; circle; down
673    dot color red at first circle.end
674~~~~~
675
676Or, we can "`print`" the coordinates of the .end of the circle before
677and after the "down" command to see that they shift:
678
679~~~~~ pikchr toggle indent
680    right; box; C1: circle
681    print "before: ", C1.end.x, ", ", C1.end.y
682    down
683    print "after: ", C1.end.x, ", ", C1.end.y
684~~~~~
685
686## Adjusting The Size Of Block Objects <a id="block-obj-size"></a>
687
688The size of every block object is controlled by three parameters:
689
690  *  `width` (often abbreviated as `wid`)
691  *  `height` (or `ht`)
692  *  `radius` (or `rad`)
693
694There is also a fourth convenience parameter:
695
696  *  `diameter`
697
698The `diameter` is always twice the radius. Setting the `diameter` automatically
699changes the `radius` and setting the `radius` automatically changes the
700`diameter`.
701
702Usually the meanings of these parameters are obvious.
703
704~~~~ pikchr toggle indent
705A: box thick
706line thin color gray left 70% from 2mm left of A.nw
707line same from 2mm left of A.sw
708text "height" at (7/8<previous.start,previous.end>,1/2<1st line,2ndline>)
709line thin color gray from previous text.n up until even with 1st line ->
710line thin color gray from previous text.s down until even with 2nd line ->
711X1: line thin color gray down 50% from 2mm below A.sw
712X2: line thin color gray down 50% from 2mm below A.se
713text "width" at (1/2<X1,X2>,6/8<X1.start,X1.end>)
714line thin color gray from previous text.w left until even with X1 ->
715line thin color gray from previous text.e right until even with X2 ->
716~~~~
717
718The `radius` parameter, however, sometimes has non-obvious meanings.
719For example, on a box, the `radius` determines the rounding of corners:
720
721~~~~ pikchr toggle indent
722A: box thick rad 0.3*boxht
723line thin color gray left 70% from 2mm left of (A.w,A.n)
724line same from 2mm left of (A.w,A.s)
725text "height" at (7/8<previous.start,previous.end>,1/2<1st line,2ndline>)
726line thin color gray from previous text.n up until even with 1st line ->
727line thin color gray from previous text.s down until even with 2nd line ->
728X1: line thin color gray down 50% from 2mm below (A.w,A.s)
729X2: line thin color gray down 50% from 2mm below (A.e,A.s)
730text "width" at (1/2<X1,X2>,6/8<X1.start,X1.end>)
731line thin color gray from previous text.w left until even with X1 ->
732line thin color gray from previous text.e right until even with X2 ->
733X3: line thin color gray right 70% from 2mm right of (A.e,A.s)
734X4: line thin color gray right 70% from A.rad above start of X3
735text "radius" at (6/8<X4.start,X4.end>,1/2<X3,X4>)
736line thin color gray from (previous,X3) down 30% <-
737line thin color gray from (previous text,X4) up 30% <-
738~~~~
739
740For a [cylinder object](./cylinderobj.md) the `radius` determines the
741thickness of the end caps:
742
743~~~~ pikchr toggle indent
744A: cylinder thick rad 150%
745line thin color gray left 70% from 2mm left of (A.w,A.n)
746line same from 2mm left of (A.w,A.s)
747text "height" at (7/8<previous.start,previous.end>,1/2<1st line,2ndline>)
748line thin color gray from previous text.n up until even with 1st line ->
749line thin color gray from previous text.s down until even with 2nd line ->
750X1: line thin color gray down 50% from 2mm below (A.w,A.s)
751X2: line thin color gray down 50% from 2mm below (A.e,A.s)
752text "width" at (1/2<X1,X2>,6/8<X1.start,X1.end>)
753line thin color gray from previous text.w left until even with X1 ->
754line thin color gray from previous text.e right until even with X2 ->
755X3: line thin color gray right 70% from 2mm right of (A.e,A.ne)
756X4: line thin color gray right 70% from A.rad below start of X3
757text "radius" at (6/8<X4.start,X4.end>,1/2<X3,X4>)
758line thin color gray from (previous,X4) down 30% <-
759line thin color gray from (previous text,X3) up 30% <-
760~~~~
761
762For a [file object](./fileobj.md) the `radius` determines the size of
763the page fold-over in the upper-right corner:
764
765~~~~ pikchr toggle indent
766A: file thick rad 100%
767line thin color gray left 70% from 2mm left of (A.w,A.n)
768line same from 2mm left of (A.w,A.s)
769text "height" at (7/8<previous.start,previous.end>,1/2<1st line,2ndline>)
770line thin color gray from previous text.n up until even with 1st line ->
771line thin color gray from previous text.s down until even with 2nd line ->
772X1: line thin color gray down 50% from 2mm below (A.w,A.s)
773X2: line thin color gray down 50% from 2mm below (A.e,A.s)
774text "width" at (1/2<X1,X2>,6/8<X1.start,X1.end>)
775line thin color gray from previous text.w left until even with X1 ->
776line thin color gray from previous text.e right until even with X2 ->
777X3: line thin color gray right 70% from 2mm right of (A.e,A.n)
778X4: line thin color gray right 70% from A.rad below start of X3
779text "radius" at (6/8<X4.start,X4.end>,1/2<X3,X4>)
780line thin color gray from (previous,X4) down 30% <-
781line thin color gray from (previous text,X3) up 30% <-
782~~~~
783
784For a [circle object](./circleobj.md), the width, height, and diameter
785are always the same, and the radius is always half the diameter.  Changing
786any parameter automatically adjusts the other three.
787
788~~~~ pikchr toggle indent
789A: circle thick rad 120%
790line thin color gray left 70% from 2mm left of (A.w,A.n)
791line same from 2mm left of (A.w,A.s)
792text "height" at (7/8<previous.start,previous.end>,1/2<1st line,2ndline>)
793line thin color gray from previous text.n up until even with 1st line ->
794line thin color gray from previous text.s down until even with 2nd line ->
795X1: line thin color gray down 50% from 2mm below (A.w,A.s)
796X2: line thin color gray down 50% from 2mm below (A.e,A.s)
797text "width" at (1/2<X1,X2>,6/8<X1.start,X1.end>)
798line thin color gray from previous text.w left until even with X1 ->
799line thin color gray from previous text.e right until even with X2 ->
800X3: line thin color gray right 70% from 2mm right of (A.e,A.s)
801X4: line thin color gray right 70% from A.rad above start of X3
802text "radius" at (6/8<X4.start,X4.end>,1/2<X3,X4>)
803line thin color gray from (previous,X3) down 30% <-
804line thin color gray from (previous text,X4) up 30% <-
805line thin color gray <-> from A.sw to A.ne
806line thin color gray from A.ne go 0.5*A.rad ne then 0.25*A.rad east
807text " diameter" ljust at end of previous line
808~~~~
809
810Even though they are curvy objects, the `radius` (and hence `diameter`)
811has no effect on [ellipse](./ellipseobj.md) and [oval](./ovalobj.md) objects.
812The size of those objects is determined purely by their width and height:
813
814~~~~ pikchr toggle indent
815A: ellipse thick
816line thin color gray left 70% from 2mm left of (A.w,A.n)
817line same from 2mm left of (A.w,A.s)
818text "height" at (7/8<previous.start,previous.end>,1/2<1st line,2ndline>)
819line thin color gray from previous text.n up until even with 1st line ->
820line thin color gray from previous text.s down until even with 2nd line ->
821X1: line thin color gray down 50% from 2mm below (A.w,A.s)
822X2: line thin color gray down 50% from 2mm below (A.e,A.s)
823text "width" at (1/2<X1,X2>,6/8<X1.start,X1.end>)
824line thin color gray from previous text.w left until even with X1 ->
825line thin color gray from previous text.e right until even with X2 ->
826~~~~
827
828~~~~ pikchr toggle indent
829A: oval thick
830X0: line thin color gray left 70% from 2mm left of (A.w,A.n)
831X1: line same from 2mm left of (A.w,A.s)
832text "height" at (7/8<previous.start,previous.end>,1/2<X0,X1>)
833line thin color gray from previous text.n up until even with X0 ->
834line thin color gray from previous text.s down until even with X1 ->
835X2: line thin color gray down 50% from 2mm below (A.w,A.s)
836X3: line thin color gray down 50% from 2mm below (A.e,A.s)
837text "width" at (1/2<X2,X3>,6/8<X2.start,X2.end>)
838line thin color gray from previous text.w left until even with X2 ->
839line thin color gray from previous text.e right until even with X3 ->
840
841A: oval thick wid A.ht ht A.wid at 2.0*A.wid right of A
842X0: line thin color gray left 70% from 2mm left of (A.w,A.n)
843X1: line same from 2mm left of (A.w,A.s)
844text "height" at (7/8<previous.start,previous.end>,1/2<X0,X1>)
845line thin color gray from previous text.n up until even with X0 ->
846line thin color gray from previous text.s down until even with X1 ->
847X2: line thin color gray down 50% from 2mm below (A.w,A.s)
848X3: line thin color gray down 50% from 2mm below (A.e,A.s)
849text "width" small at (1/2<X2,X3>,6/8<X2.start,X2.end>)
850line thin color gray from previous text.w left until even with X2 ->
851line thin color gray from previous text.e right until even with X3 ->
852~~~~
853
854Notice that with an oval object, the semicircular end-cap is always
855on the narrow end of the object.  In the default configuration where
856the height is less than the width, the semicircular end-caps are on the
857left and right, but if the width and height are modified so that the
858width is less than the height, then semicircles appear on the top and
859bottom instead.
860
861
862### Default Sizes <a id="def-size"></a>
863
864Block objects have default sizes, which are determined by variables.
865For example, the width of a box is initialized with the value of the `boxwid`
866variable, which defaults to `0.75in`.
867
868It is common for Pikchr scripts
869to change these default at or near the beginning of a script in order to adjust
870the default sizes of objects defined within that script.
871
872### Setting Sizes Using Attributes <a id="size-attr"></a>
873
874Use the "`width`" (or "`wid`") attribute to change the width of an object.
875The argument to this attribute can be an expression — such as "`1cm`" or
876"`0.75*boxwid`" — or it can be a percentage of the prior value,
877such as "`75%`".  This also works for "`height`",
878"`radius`", and "`diameter`".
879
880### Automatic Sizing To Fit Text Annotations <a id="text-ann-size"></a>
881
882If a block object contains text annotations, the "`fit`" attribute causes
883the width and height to be adjusted so that the object neatly encloses that
884text.  The "`fit`" attribute only considers text that is previously defined
885for the object, or in other words text annotations that occur to the left
886of the "`fit`" keyword.  The width and height can be adjusted further after
887the "`fit`" keyword, for example to provide a larger margin around the
888text.  Click on the following script to see the difference that the
889"`width 125%`" at the end of the second box definition makes.
890
891~~~~ pikchr source toggle indent
892    down
893    box "Auto-fit text annotation" "as is" fit
894    move 50%
895    box "Auto-fix text annotation" "with 125% width" fit width 125%
896~~~~
897
898If at the end of a block object definition, either the width or height of the
899object is less than or equal to zero, then that dimension is increased so as to
900enclose all text annotations on the object.  Thus, for example,
901you can make all of the
902boxes in your diagram auto-fit around their text annotations by prefacing
903your script with something like:
904
905~~~~ pikchr source toggle indent
906    boxwid = 0; boxht = 0;
907    box "Hello";
908    move
909    box "A longer label" "with multiple lines" "of label text"
910~~~~
911
912For all of these auto-fit features, Pikchr needs to know the dimensions of the
913text annotations after rendering.  Unfortunately, that information is not
914readily available, as Pikchr runs long before the generated SVG reaches the
915web-browser in which it will be displayed.  Hence, Pikchr has to guess at the
916text size.  Usually it does a good job of this, but it can be a little off,
917especially for unusual (read: "non-ASCII") characters or if the CSS for
918the rendering environment sets a non-standard font face or font size.  To
919compensate, the "`charwid`" and "`charht`" variables can be adjusted or
920extra spaces can be added at the beginning or end of text strings.
921
922These auto-fit features are a new innovation for Pikchr and are not available
923in other PIC family interpreters, as far as we are aware.
924
925## Attributes For Stroke Width And Drawing Colors <a id="stroke-attr"></a>
926
927Various attributes can be added to both block and line objects to influence
928how the objects are drawn.
929
930  *  `thickness` *dimension*
931  *  `thick`
932  *  `thin`
933  *  `invisible` (or `invis`)
934  *  `color` *color*
935  *  `fill` *color*
936
937The "`thickness`", "`thick`", "`thin`", and "`invisible`" attributes control
938the stroke width of the lines that construct an object.  The default stroke width
939for all objects is determined by the "`thickness`" variable, which defaults
940to "`0.015in`".  The "`thick`" and "`thin`" attributes increase or decrease
941the stroke width by fixed percentages.  These attributes can be repeated
942to make the stroke width ever thicker or thinner, up to the limit of the object’s
943dimensions where the stroke fills the entire object.  The "`invisble`" attribute
944simply sets the stroke width to 0.
945
946~~~~ pikchr toggle indent
947   boxwid = 0
948   boxht = 0
949   right
950   box "normal"
951   move
952   box "thin" thin
953   move
954   box "thick" thick
955   move
956   box "thick thick thick" thick thick thick
957   move
958   box "invisible" invisible
959~~~~
960
961Notice that “invisible” refers only to the object outline, not to the
962whole object. You therefore cancel the “invisible” attribute with
963“solid”, not “visible”:
964
965~~~~ pikchr toggle indent
966   boxwid = 0
967   boxht = 0
968   box "fully visible"
969   box invisible color gray "outline invisible"
970   box same solid "outline visible again" fit
971~~~~
972
973The "`color`" and "`fill`" attributes change the foreground and background
974colors of an object.  Colors can be expressed using any of [the 148 standard
975CSS color names][ccn] such as "Bisque" or "AliceBlue" or "LightGray".  Color
976names are not case sensitive, so "bisque", "BISQUE", and "Bisque" all mean
977the same thing.  Color names can also be expressed as an integer which is
978interpreted as a 24-bit RGB value.  It is convenient to express numeric
979color values using hexadecimal notation.  "Bisque" is the same as "0xffe4c4",
980which is the same as "16770244".
981
982~~~~ pikchr toggle indent
983   box "Color: CadetBlue" "Fill: Bisque" fill Bisque color CadetBlue fit
984   move
985   oval "Color: White" "Fill: RoyalBlue" color White fill ROYALBLUE fit
986~~~~
987
988Setting the "`fill`" to a negative number, to "None", or to "Off" makes the
989background transparent.  That is the default.
990
991The default foreground color is black.
992
993[ccn]: https://developer.mozilla.org/en-US/docs/Web/CSS/color_value
994
995### Filled Polygons <a id="filled-polys"></a>
996
997The "`fill`" attribute does not affect the rendering of lines unless the
998route of the line is terminated by the "`close`" attribute.  The "`close`"
999keyword converts the line into a polygon:
1000
1001~~~~ pikchr toggle indent
1002   line go 3cm heading 150 then 3cm west close \
1003                                      /* ^^^^^ nota bene! */ \
1004       fill 0x006000 color White "green" below "triangle" below
1005~~~~
1006
1007Polygons are not required to have a fill color. With the default fill of “none,”
1008you can use the "`close`"
1009keyword to convert a polygon into a line and leave the background transparent,
1010but using "`fill` *color*" together with "`close`" is a common idiom.
1011
1012## Text Annotations <a id="text-ann"></a>
1013
1014Every object can have up to five lines of text annotation.  Each annotation
1015is a string literal attribute on the object definition.  By default, the
1016annotations are displayed around the center of the object, from top to bottom,
1017in the order that they appear in the input script.
1018
1019~~~~ pikchr toggle indent
1020   box "box containing" "three lines" "of text" fit
1021   move
1022   arrow "Labeled" "line" wid 200%
1023~~~~
1024
1025## Text Attributes <a id="text-attr"></a>
1026
1027The layout and font style of the annotations can be modified using keywords
1028that appear after each string literal.  The following modifiers are supported:
1029
1030  * **above**
1031  * **aligned**
1032  * **below**
1033  * **big**
1034  * **bold**
1035  * **center**
1036  * **italic**
1037  * **ljust**
1038  * **rjust**
1039  * **small**
1040
1041### Position Text Above Or Below The Center Of The Object <a id="text-pos"></a>
1042
1043The "`above`" and "`below`" keywords control the location of the
1044text above or below the center point of the object with which
1045the text is associated.  If there is just one text on the object
1046and the "`above`" and "`below`" keywords are omitted, the text is
1047placed directly over the center of the object.  This causes
1048the text to appear in the middle of lines:
1049
1050~~~~ pikchr indent toggle
1051  line "on the line" wid 150%
1052~~~~
1053
1054So, if there is just a single text label on a line, you probably
1055want to include either the "`above`" or "`below`" keyword.
1056
1057~~~~ pikchr indent toggle
1058  line "above" above; move; line "below" below
1059~~~~
1060
1061If there are two texts on the object, they straddle the center point
1062above and below, even without the use of the "`above`" and "`below`"
1063keywords:
1064
1065~~~~ pikchr indent toggle
1066  line wid 300% "text without \"above\"" "text without \"below\""
1067~~~~
1068
1069The "`above`" and "`below`" attributes do not stack or accumulate.  Each "`above`"
1070or "`below`" overrides any previous "`above`" or "`below`" for the same text.
1071
1072If there are multiple texts and all are marked "`above`" or "`below`", then
1073all are placed above or below the center point, in order of appearance.
1074
1075~~~~ pikchr indent toggle
1076  line width 200% "first above" above "second above" above
1077  move
1078  line same "first below" below "second below" below
1079~~~~
1080
1081### Justify Text Left Or Right <a id="text-just"></a>
1082
1083As the "`above`" and "`below`" keywords control up and down positioning of
1084the text, so the "`ljust`" and "`rjust`" keywords control left and right
1085positioning.
1086
1087For a line, the "`ljust`" means that the left side of the text is flush
1088against the center point of the line, and "`rjust`" means that the right
1089side of the text is flush against the center point of the line.
1090(In the following diagram, the red dot is at the center of the line.)
1091
1092~~~~ pikchr indent toggle
1093   line wid 200% "ljust" ljust above "rjust" rjust below
1094   dot color red at previous.c
1095~~~~
1096
1097For a block object, "`ljust`" shifts the text to be left justified
1098against the left edge of the block (with a small margin) and
1099"`rjust`" puts the text against the right side of the object (with
1100the same margin).
1101
1102~~~~ pikchr indent toggle
1103   box "ljust" ljust "longer line" ljust "even longer line" ljust fit
1104   move
1105   box "rjust" rjust "longer line" rjust "even longer line" rjust fit
1106~~~~
1107
1108The behavior of "`ljust`" and "`rjust`" for block objects in Pikchr differs
1109from legacy PIC.
1110In PIC, text is always justified around the center point, as in lines,
1111but this means there is no easy way to left justify multiple lines of
1112text within a "box" or "file", so the behavior was changed for
1113Pikchr.
1114
1115Pikchr allows three separate text objects inside another object by combining
1116"`ljust`", "`rjust`", and the default text centering:
1117
1118~~~~ pikchr indent toggle
1119  box wid 300% \
1120     "above-ljust" above ljust \
1121     "above-rjust" above rjust \
1122     "centered" center \
1123     "below-ljust" below ljust \
1124     "below-rjust" below rjust
1125~~~~
1126
1127### Text Attribute "center" <a id="text-center"></a>
1128
1129The "`center`" attribute cancels all prior "`above`", "`below`", "`ljust`", and
1130"`rjust`" attributes for the current text object.
1131
1132### Bold And Italic Font Styles <a id="font-style"></a>
1133
1134The "`bold`" and "`italic`" attributes cause the text object to use a bold or
1135italic font.  Fonts can be both bold and italic at the same time:
1136
1137~~~~ pikchr indent toggle
1138  box "bold" bold "italic" italic "bold-italic" bold italic fit
1139~~~~
1140
1141### Aligned Text <a id="text-align"></a>
1142
1143The "`aligned`" attribute causes text associated with a straight line
1144to be rotated to align with that line:
1145
1146~~~~ pikchr indent toggle
1147  arrow go 150% heading 30 "aligned" aligned above
1148  move to 1cm east of previous.end
1149  arrow go 150% heading 170 "aligned" aligned above
1150  move to 1cm east of previous.end
1151  arrow go 150% north "aligned" aligned above
1152~~~~
1153
1154To display rotated text not associated with a line, attach the
1155text to a line that is marked "`invisible`"
1156
1157~~~~ pikchr indent toggle
1158  box ht 200% wid 50%
1159  line invis from previous.s to previous.n "rotated text" aligned
1160~~~~
1161
1162Note that the direction of aligned text is the same as the direction of
1163the line itself, so if you draw a line from right to left, the aligned
1164text will appear upside down:
1165
1166~~~~ pikchr indent toggle
1167  circle "C1" fit
1168  circle "C0" at C1+(2.5cm,-0.3cm) fit
1169  arrow from C0 to C1 "aligned" aligned above chop
1170~~~~
1171
1172If you need aligned text on an arrow that goes from right to left,
1173and you do not want the text to be rendered upside-down, draw
1174the arrow from left to right and include the "`<-`" attribute
1175so that the arrowhead is at the beginning rather than at the end:
1176
1177~~~~ pikchr indent toggle
1178  circle "C1" fit
1179  circle "C0" at C1+(2.5cm,-0.3cm) fit
1180  arrow from C1 to C0 "aligned" aligned above <- chop
1181~~~~
1182
1183### Adjusting The Font Size <a id="font-size"></a>
1184
1185The "`big`" and "`small`" attributes cause the text to be a little larger
1186or a little smaller, respectively.  Two "`big`" attributes cause the
1187text to be larger still, as do two "`small`" attributes. Text
1188size does not increase or decrease beyond two "`big`" or "`small`" keywords.
1189
1190~~~~ pikchr indent toggle
1191  box "small small" small small "small" small \
1192    "(normal)" italic \
1193    "big" big "big big" big big ht 200%
1194~~~~
1195
1196A "`big`" keyword cancels any prior "`small`" keywords on the same text,
1197and a "`small`" keyword cancels any prior "`big`" keywords.
1198
1199
1200## Text Is Positioned Around The Center Of The Object <a id="text-center"></a>
1201
1202The anchor point for text annotations is usually the center of the bounding box for
1203the whole object.  This is intuitive for block objects and straight lines.
1204But for multi-segment lines, the text might not be near
1205the line itself.  For example, in the following four-segment arrow,
1206the red box is the bounding box and the red dot shows the center of the
1207bounding box.  The text label is aligned relative to the center of the
1208bounding box, which is not close to any part of the actual line.
1209
1210~~~~ pikchr toggle indent
1211arrow up 1.5cm right 1.5cm then down .5cm right 1cm then up .5cm right .3cm \
1212   then down 2.5cm right 1cm "text"
1213box color red thin thin width previous.wid height previous.ht \
1214   with .c at previous.c
1215dot at last arrow.c color red behind last arrow
1216~~~~
1217
1218If you need to position text beside one specific segment of a multi-segment
1219line, consider creating a separate "`invis`" line over top of that line
1220segment and attaching the text to the "invis" line instead.  Here is the
1221same arrow as before, but with the text attached to a separate "invis" line
1222that overlays the second segment of the arrow:
1223
1224~~~~ pikchr toggle indent
1225arrow up 1.5cm right 1.5cm then down .5cm right 1cm then up .5cm right .3cm \
1226   then down 2.5cm right 1cm
1227box color red thin thin width previous.wid height previous.ht \
1228   with .c at previous.c
1229dot at last arrow.c color red behind last arrow
1230line invis from 2nd vertex of last arrow to 3rd vertex of last arrow \
1231   "text" below aligned
1232~~~~
1233
1234The anchor point for text is *usually* the center of the object, but
1235in some cases, the anchor point might be fudged a little.  This happens,
1236for example for cylinder objects:
1237
1238~~~ pikchr toggle indent
1239C1: cylinder "text in a" "cylinder" rad 120%
1240    dot color red at C1.c
1241    dot color blue at 0.75*C1.rad below C1.c
1242~~~
1243
1244The red dot is on the center of the cylinder and the blue dot shows the
1245anchor point for the text.  The text is a little lower for cylinders because
1246that looks better.  With out this adjustment of the text center point, the
1247cylinder text would look goofy:
1248
1249~~~ pikchr toggle indent
1250C1: cylinder rad 120%
1251    text "text in a" "cylinder" at C1.c
1252~~~
1253
1254# Containers
1255
1256A "container" is a list of one or more objects contained within "`[`...`]`".
1257A container is a collection of one or more objects that looks like a single
1258object to the remainder of the script.
1259
1260For example:
1261
1262~~~ pikchr toggle source indent
1263    A: [
1264      oval "Hello"
1265      arrow
1266      box "World" radius 4px
1267    ]
1268    Border: box thin width A.width+0.5in height A.height+0.5in at A.center
1269~~~
1270
1271The "A" container is composed of an oval, and arrow, and a box with rounded
1272corners.  But to the subsequent "Border" box, the "A" container appears to
1273be a single object.  The Border box can reference the overall width and height
1274and the center point of the A container in order to size and position itself to
1275enclose the container with a 0.25in border:
1276
1277~~~ pikchr toggle indent
1278    A: [
1279      oval "Hello"
1280      arrow
1281      box "World" radius 4px
1282    ]
1283    Border: box thin width A.width+0.5in height A.height+0.5in at A.center
1284~~~
1285
1286A container is mostly useful for adding a border around a collection of
1287objects, as shown above, or adding a caption to a diagram.  The following
1288diagram shows what a caption might look like.
1289(Click to see the Pikchr source text.)
1290
1291~~~ pikchr toggle indent
1292    A: [
1293      oval "Hello"
1294      arrow
1295      box "World" radius 4px
1296    ]
1297    Caption: text "Diagram Caption" italic with .n at 0.1in below A.s
1298~~~
1299
1300
1301In legacy PIC, layout direction changes (the "up", "down", "left", and "right"
1302commands) and variable definitions within a container only affect subsequent
1303statements within the same container.  Once the container closes, the prior direction
1304and variable values are restored.  Pikchr does not work this way.  In
1305Pikchr, layout direction changes and variable definitions that occur within
1306a container continue to be in effect after the container.
1307
1308# Summary And Conclusion
1309
1310Though based on the decades-old PIC language, Pikchr itself is a relatively
1311new system.  However it has already proven itself to be amazingly useful for
1312helping to illustrate concepts in technical documentation written using Markdown.
1313
1314This document has provided an overview of how Pikchr works.  For more
1315details and other perspectives, see the following resources:
1316
1317  *  [The original Kernighan paper on PIC](/uv/pic.pdf)
1318  *  [DPIC documentation](/uv/dpic-doc.pdf)
1319  *  [ESR's documentation on GnuPIC](/uv/gpic.pdf)
1320  *  [Pikchr Language Spec](./grammar.md)
1321  *  [Differences between PIC and Pikchr](./differences.md)
1322  *  [The scope and purpose of Pikchr](./purpose.md)
1323  *  [Step-by-step example of writing a Pikchr document](./teardown01.md)
1324