Automatic layoutΒΆ

Earlier diagrams used a mix of implicit left-to-right flow and explicit at coordinates. For larger flow-style diagrams you can describe the structure and hand most placement to SheepText. Declare a direction and connect the shapes; they arrange themselves along that axis:

Directional layout

Open in editor

direction right
A: box "ingest"
B: box "process"
C: box "store"
arrow from A to B
arrow from B to C

column (and its sibling row) aligns a set of shapes into a single band. This column stacks three steps top to bottom:

Layout column

Open in editor

column Pipe: A B C
A: box "one"
B: box "two"
C: box "three"

The name Pipe is optional. Give one when you want to talk about the constraint later. A diagnostic quotes it back at you, and the editor’s visual-intent commands address it by name. Leave it out for a one-off:

Unnamed column

Open in editor

column: A B C
A: box "one"
B: box "two"
C: box "three"

Those are the same diagram. If SheepText ever has to tell you it could not honour an unnamed constraint, it names the members instead of a name you never wrote.

Sometimes you want order without alignment: this box goes to the left of that one, and where it sits vertically is not your concern. left of says exactly that, and above is its vertical twin (right of and below are the same statements read the other way round). Nothing here puts A and B in a shared row or column; the second statement below could not hold if the first had:

Order without alignment

Open in editor

A: box "first"
B: box "second"
A left of B
B below A

group arranges shapes and wraps them in a labelled container in one declaration, with no coordinates required:

Layout group

Open in editor

group Svc "Services": A B C
A: box "auth"
B: box "api"
C: box "db"

Automatic layout shines for flowcharts. Combine a downward flow with a row for the two branch targets so they sit side by side; style the nodes by role and let the arrows describe the branches:

Branching flow

Open in editor

direction down
row Branches: Ok Bad
Start: box "start" fill #dbeafe
Check: box "valid?" fill #fef3c7
Ok: box "process" fill #dcfce7
Bad: box "reject" fill #fee2e2
arrow from Start to Check
from Check arrow "yes" to Ok
from Check arrow "no" to Bad

A second edge between the same two shapes needs no help. SheepText gives each edge its own attachment port, so a return arrow runs parallel to the outbound one rather than on top of it:

Parallel arrows

Open in editor

direction right
A: box "client"
B: box "server"
from A arrow "request" to B
from B arrow "response" to A

Use a route policy when you want an edge to leave on a particular side, to keep it away from other content, or simply to match how you would draw it. It is a choice about which way an edge goes, not a fix for overlapping lines:

Routed return

Open in editor

direction right
A: box "client"
B: box "server"
from A arrow "request" to B
from B arrow "response" to A route below

There are four directions, one per side: route above, route below, route left and route right. They all mean the same thing: prefer the named side. Which one reads naturally depends on how your diagram flows. In a left-to-right layout, above and below are the useful pair, because the two boxes are already side by side and the interesting choice is which way the return arrow bends. In a top-to-bottom layout that is reversed, and left and right become the natural pair:

Routed return in a downward flow

Open in editor

direction down
A: box "client"
B: box "server"
from A arrow "request" to B
from B arrow "response" to A route left

A route policy expresses a preference, and it shapes the choice in three ways: the named side is tried first, the opposite side is dropped from consideration entirely, and the finished route is checked against the half-plane the policy asks for. What it does not do is override the endpoint constraints you have already stated. An authored port or a pinned side still wins because those say exactly where the edge attaches while a policy only says which way it should prefer to go.

Steering a real diagramΒΆ

The diagram on the front page is written with no layout statement at all: five services, five arrows, one region. SheepText places the services in flow order, routes the return arrow over the gateway by the free top faces, and keeps every label clear of the lines. This is the honest baseline, what you get before you ask for anything:

Structure only

Open in editor

use icons aws

Users: icon aws:users "Users"
ChatClient: icon aws:client "Chat client"

MainRegion: [
  ApiGateway: icon aws:amazon-api-gateway "Amazon\nAPI Gateway"
  Lambda: icon aws:aws-lambda "AWS\nLambda"
  Rekognition: icon aws:amazon-rekognition "Amazon\nRekognition"
] "AWS Region"

from Users arrow "(1)" to ChatClient
from ChatClient arrow "(2)" to ApiGateway
from ApiGateway arrow "(3)" to Lambda
from Lambda arrow "(4)" to Rekognition heads both
from Lambda arrow "(5)" to ChatClient

Two statements steer it, and the source is otherwise identical. row Spine: Users ChatClient MainRegion pins the three top-level members to one horizontal line, so the region can never drop below the client even if its contents grow; and route above on the return arrow says which way round it should go, so the choice survives edits that would otherwise change the solver’s mind. Everything else (the placement inside the region, the port each arrow uses, where the labels sit) is still SheepText’s:

Steered with two statements

Open in editor

use icons aws
row Spine: Users ChatClient MainRegion

Users: icon aws:users "Users"
ChatClient: icon aws:client "Chat client"

MainRegion: [
  ApiGateway: icon aws:amazon-api-gateway "Amazon\nAPI Gateway"
  Lambda: icon aws:aws-lambda "AWS\nLambda"
  Rekognition: icon aws:amazon-rekognition "Amazon\nRekognition"
] "AWS Region"

from Users arrow "(1)" to ChatClient
from ChatClient arrow "(2)" to ApiGateway
from ApiGateway arrow "(3)" to Lambda
from Lambda arrow "(4)" to Rekognition heads both
from Lambda arrow "(5)" to ChatClient route above

Write the statement that carries meaning and leave the rest out. A row you did not need is a constraint SheepText has to honour when the diagram changes, and a route you did not need is a corridor it can no longer reconsider.

For pipeline diagrams, stage labels each phase and arranges its members, much like group but tuned for left-to-right flow:

Pipeline stages

Open in editor

direction right
stage Ingest "Ingest": Collector
stage Store "Store": Warehouse
Collector: box "collector"
Warehouse: box "warehouse"
arrow from Collector to Warehouse

How hard is a constraint?ΒΆ

direction, row, column and the order statements (left of, above) state a constraint, and every one you have written so far was a preference. SheepText tries to honour it, and if the geometry will not allow it the diagram still renders in a degraded state, with a warning naming the statement it could not keep. That is the default because it is almost always what you want: a diagram that draws is more useful than one that refuses.

(stage and group are not constraints. They declare a visible container, which the engine cannot fail to honour, so they take no strength and SheepText refuses one written on them.)

Say require in front of a direction, row, column or order when you would rather be told than be given a diagram that lost your intent without a diagnostic:

Required alignment

Open in editor

direction right
require row Peers: A B
A: box "primary"
B: box "replica"
arrow from A to B

The strength always leads the statement, so you read the modality before the payload: require row Peers: A B, never row Peers: A B require. prefer is the other half of the pair and states the default out loud, which is worth doing when a constraint sits among required ones and the contrast matters:

Mixed strengths

Open in editor

direction down
require column Spine: Start Check Done
prefer row Branches: Check Aside
Start: box "start"
Check: box "check"
Aside: box "note"
Done: box "done"
arrow from Start to Check
arrow from Check to Done

A require that cannot hold is an error, not a warning: SheepText refuses the diagram and tells you which constraint it could not satisfy. When two or more required statements contradict each other, such as require column: A B alongside require A left of B, the refusal names every one of them, each at its own line, because the fault is in the combination and not in any single statement. A prefer that cannot hold renders and warns.

Next: bring in Icons.