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: .. sheeptext-example:: :label: Directional layout :alt: Three boxes ingest process and store automatically arranged left to right with arrows between them direction right A: box "ingest" B: box "process" C: box "store" A -> B B -> C ``column`` (and its sibling ``row``) aligns a set of shapes into a single band. This column stacks three steps top to bottom: .. sheeptext-example:: :label: Layout column :alt: Three boxes one two three stacked into an aligned vertical column 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: .. sheeptext-example:: :label: Unnamed column :alt: Three boxes one two three stacked into an aligned vertical column declared without a constraint name 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: .. sheeptext-example:: :label: Order without alignment :alt: Two boxes where the second sits to the right of and below the first, ordered on each axis without being aligned 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: .. sheeptext-example:: :label: Layout group :alt: Three boxes auth api and db grouped inside a labelled Services container 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: .. sheeptext-example:: :label: Branching flow :alt: A vertical flowchart from start to a validity check that branches yes to a process box and no to a reject box side by side 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 Start -> Check Check -> Ok "yes" Check -> Bad "no" 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: .. sheeptext-example:: :label: Parallel arrows :alt: Two boxes with a request arrow and a parallel return arrow, each on its own port direction right A: box "client" B: box "server" A -> B "request" B -> A "response" 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: .. sheeptext-example:: :label: Routed return :alt: The same two boxes, with the return arrow forced onto a detour below them direction right A: box "client" B: box "server" A -> B "request" B -> A "response" 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: .. sheeptext-example:: :label: Routed return in a downward flow :alt: Two stacked boxes with a request arrow down and a return arrow routed to their left direction down A: box "client" B: box "server" A -> B "request" B -> A "response" 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: 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: .. sheeptext-example:: :label: Structure only :alt: An image-moderation chat flow with no layout statements: users reach a chat client, which calls an API Gateway inside an AWS Region group; Lambda moderates with Rekognition and replies to the chat client 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" Users -> ChatClient "(1)" ChatClient -> ApiGateway "(2)" ApiGateway -> Lambda "(3)" Lambda <-> Rekognition "(4)" Lambda -> ChatClient "(5)" 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: .. sheeptext-example:: :label: Steered with two statements :alt: The same image-moderation chat flow with its three top-level members held on one row and the return arrow routed above the region 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" Users -> ChatClient "(1)" ChatClient -> ApiGateway "(2)" ApiGateway -> Lambda "(3)" Lambda <-> Rekognition "(4)" Lambda -> ChatClient "(5)" 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: .. sheeptext-example:: :label: Pipeline stages :alt: A two-stage pipeline with an Ingest stage feeding a Store stage direction right stage Ingest "Ingest": Collector stage Store "Store": Warehouse Collector: box "collector" Warehouse: box "warehouse" Collector -> 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: .. sheeptext-example:: :label: Required alignment :alt: Two boxes on a required shared row with an arrow between them direction right require row Peers: A B A: box "primary" B: box "replica" A -> 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: .. sheeptext-example:: :label: Mixed strengths :alt: A required column of three steps with a preferred row aligning two side branches 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" Start -> Check Check -> 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: :doc:`editing` shows how to make these changes in the editor.