The simplest diagram is (from Andrew Tannenbaum’s famous book) two connected blocks.
![]() | ![]() |
This is essentially an arrow specification with the participating blocks automatically created (using default shape, label, layout and other attributes). A more detailed version can be seen below.
![]() | ![]() |
Here each block is first defined to be a box, which essentially dictates its shape.
After the box
keyword comes the name of the block that is used
later to specify the arrow. These names also become the label of the block if you do
not specify any other label. In this example, we do - after the colon comes the label.
Note that you do not have to name a block, names can be omitted. They are needed only
if you want to refer to the block later (such as for an arrow).
Note that you can omit the box
keyword. In that case the block is created only
if it has not been created previously. If it has, only its attributes are changed,
such as in the case of block B
below. Blocks that are created take their
attributes from the running style, which can be set by the use
command.
Any block or arrow created after that is impacted by any attributes setting after
use
. There is in fact two running styles, one for blocks and one for arrows.
They can be set via the blocks use
and arrows use
command. Writing just
use
will impact both.
![]() | ![]() |
If just listed one after the other, the blocks are laid left-to-right. This is
called a row. You can make blocks go top-to-bottom by inserting them into
a column, or col for short. On the figure below, blocks B
and C
are part of an nunnamed column, where block A
and the
unnamed col are in a row (that is laid left-to-right). The space
command
is used to insert a bit of extra blank space between block A
and the
unnamed column.
![]() | ![]() |
You can also see that it is easy to specify several arrows at once, by listing multiple destinations (or sources) in a comma-separated list.
If you want to enclose two blocks in another block, add them as content.
In the example below the unnamed col has been replaced to an unnamed box.
We use the boxcol
keyword, this is the same as box
, but arranges
its content in a column instead of a row by default.
After the boxcol
keyword, attributes can be specified in square brackets, similar
to other languages of Msc-generator. In particular, we set the corners of the
unnamed box to round.
![]() | ![]() |
Next, we can add a label to a container block, that is, one which has
content. This, however, moves blocks B
and C
downwards
messing up the symmetry of the arrows. This is because in a row elements are
vertically centered by default, thus block A
is vertically centered
to the unnamed container block right to it. (Note also that blocks in a column
are also centered horizontally by default. Note also, that you can define
multiple block with one box
command.)
![]() | ![]() |
To fix the arrow asymmetry problem, we can add a named column (BC
)
inside the container box and make block A
align to that vertically.
For this we use the
middle
attribute on the block A
. This makes the block’s middle
to vertically align to the middle of another block.
This way we can override the default row alignment between block A
and
the unnamed container block.
Note that you can forward reference BC
even before it was defined.
![]() | ![]() |
Adding this extra column is a bit cumbersome just to group blocks for alignment.
You can shortcut
it by listing a group of blocks directly in the middle
attribute.
Msc-generator will calculate the middle (or top, bottom or any other part)
of the blocks combined and will align there.
![]() | ![]() |
Continuing the example, we could add two more blocks with different alignment.
The attributes top
and bottom
make the top and the bottom of
the block to align to that of another block. Note that the blocks A
and E
are laid out further apart from one another - this is the only
way to fulfill the alignment requirements we have specified via the attributes.
![]() | ![]() |
You can use the below
, above
, leftof
and rightof
alignment modifiers in front of any block to place it in relation to
the previous block. In the example below, below
refer to the big container
Cont
, so block N
is placed below it. In turn, leftof
refers
to block N
, so block M
is placed left of it.11
![]() | ![]() |
In addition to middle
, top
and bottom
there are three more
alignment attributes that can be used to govern horizontal alignment. They
are called center
, left
and right
. Since I always confuse middle
(the vertical one) and center
(the horizontal one), Msc-generator also has
four aliases to these two: xcenter
, xmiddle
, ycenter
and ymiddle
to disambiguite which axis is along with we seek the center position.
As value for these attributes, you can specify not only a block name, but also
a part of the block after the at sign @
. Furthermore, alignment modifiers
can be followed by a block so that they can work no blocks other than the previous
ones.
![]() | ![]() |
It is possible to have not only boxes, but any arbitrary shape for a block.
This can be achieved via using the shape
keyword followed by the name
of the shape instead of the box
keyword. As a shorthand, the asterisk
symbol (*
) can also be used. A handful of basic shapes are defined
in the default design library and can be used. You can also add text without any
borders or background. This is useful as explanatory notes. Those can be added with the
text
command as seen below.
![]() | ![]() |
You can define your own shapes via the defshape
command, but
defining a separate shape for something simple is often too complicated.
To this end, Msc-generator allows you to join blocks that
are overlapping or touching. Joing blocks will remove any internal lines and keep
a single contour. Below you can see 4 blocks without and with an additional
join
command.
![]() | ![]() | ![]() |
Note that the fill of the joined blocks is kept, together with any label. You can assign any line, fill or shadow attributes to the joined block, which override the line, fill and shadow attributes of the original blocks. By default, only line attributes are on, thus the joined block has no fill or shadow.
Another way to define a new block is to encircle a set of existing blocks.
This can be done by the around
keyword. In the middle figure of the below
example you can see that we use two boxes (A1
and A2
) and an oval
(A3
) to encircle various boxes. On the right figure, we have added
the join
command at the last line of the example, which combined the two
boxes. Note that even if A3
does not touch or overlap with A1
or
A2
, it can still be part of the join.
![]() | ![]() | ![]() |
Such around
blocks have no fill by default.
Note that we have used compound names when specifying the boxes to encircle.
Each of the four column had a name (x
, y
, z
and v
),
but inside the columns the box names were re-used
(a
, b
, c
and d
). To name a specific block you can use
the name of the containing block to disambiguite before the block name.
When drawing diagrams, a technique is often used to indicate that we have several
instances of a block. This technique can be expressed by prepending the
multi
keyword in front of any block definition.
![]() | ![]() |
You can apply a number after the multi
keyword to specify how many copies
do you want, the default is 3. You can still refer to any blocks contained within
(B.o
in the example) and two more blocks: front
and back
to
refer to the first and last in the series of copies.
You can also copy an already existing block. This is a quick way to define larger diagrams. You can give the copy a name, change its attributes or even replace its content (or add to it).
![]() | ![]() |
Alignment
modifiers also result in side-by-side placement (subject to the respective
margins). Thus below
means that the Y coordinate of the bottom of the
previous block (plus its bottom margin) equals to the Y coordinate of the current
block (minus its top margin).