# Layout invariants Everything on the canvas is a bounding box: tensors, full offset stacks, brackets, operators, arrow labels, annotations, symbols, shape labels, stage headings, the meaning box, the signature. **Tangency counts as collision.** ## Place by cursor, not by coordinate The invariants below are *statements about the finished figure*; the flow layout in `api.md` is how you get them without checking each one by hand. Use it by default: `\ststage` / `\strow` … `\strowend` / `\stcol` … `\stcolend`, with an empty coordinate argument on every face. The failure it removes is specific. With hand-written offsets, each gap is a magic number tuned against the *current* content, so the day a label grows by two characters it silently lands on the next tensor — the figure still compiles and still looks clean. With the cursor, every object reserves its own width, so growing one object can only push the rest apart. And because a band declares its height, an object that does not fit becomes a `Package supertensor Warning`, which `build.sh` turns into a failed build. Hand placement remains available for the cases the cursor cannot express. When you use it, wrap the node in `\sttrack` so the bounding box and the vertical cursor still see it. ## Gutters Define one base gutter `g ≥ 1 em`; that is what `\stgutter` (6 mm) is. Unrelated boxes stay at least `g` apart; stage bands at least `1.5g` (`\strowgap`, `\stblockgap`). Set them once at the top of the figure rather than per call — a per-call `gap=` is for stating a *relationship* (`gap=0pt` = these shards tile), not for nudging. Overlap is allowed only inside one declared composite: - tiles inside their own face, - shards tiling a parent, - outline sheets in one `\ststack`, - a bracket around its own tensor, - a connector endpoint touching its source/target border. Every other intersection or occlusion is forbidden. ## Lanes Reserve separate vertical lanes and never put anything else in them: ``` stage heading (connector annotations) tensor / operator row symbols <- \stcaption arg 2 shapes <- \stcaption arg 3 ``` Faces of different heights would otherwise hang their captions at different depths. Fix it with a shared baseline — `\strowend` arms one automatically: ```tex \strow{rowA}{T} ... \strowend \stcaption{Q}{$\mathbf Q^{(i)}$}{$h\times T\times d_h$} ``` Under absolute placement, arm it yourself with `\stlane{rowA}` … `\stnolane`. Either way every `\stcaption` inside hangs from the bottom of `rowA`, so symbols and shapes form two flat lanes. Stage headings share one left rail. `\ststage` puts them there: the rail is a single stored `x` (`\stleftrail` to move it), and the `y` is derived from the lowest ink drawn so far, so a heading can neither drift right nor collide with the row above it. Explanatory prose belongs in the stage subtitle, the bottom box, or above its own connector. Never drop a floating commentary card between two operands unless it is a real operation node (`st comm`). ## Layers The package declares three: `stbg` (connectors), `main` (tensors, operators), `stfg` (text). `\starrow` and `\starrowlabel` route on `stbg` automatically, so a connector can never cover a face. Two consequences you still own: - A connector may not cross a box that is not one of its endpoints. Move the row, don't route over. - A label's white underlay may cover only its own connector — never a tensor, never another label. This is the single most common failure after a first draft, and `\stlink` is the fix: it makes the label itself a flow object and draws the arrow to whatever lands on either side of it, so the label cannot be wider than its connector. `\starrowlabel` between two hand-placed nodes still has the old failure mode. ## Stacks `\ststack` includes its offset sheets in the bounding box, so neighbours can be spaced against the real extent. Back sheets are outline-only and must carry no semantic content of their own. If individual slices need to be read, use separate panels instead of overlap. ## When it does not fit In this order: 1. shorten or remove secondary annotation, 2. widen the natural crop, 3. increase row spacing, 4. move the whole stage to another row. Never solve crowding by shrinking below the type hierarchy, closing the gutter, or covering another object.