Add flow layout: cursor placement, left rail, declared band heights

Figures were positioned by hand-written offsets. Every gap was a magic
number tuned against the content that happened to be there, so a label
that grew two characters landed on the next tensor, and two stages
started from two different x shared no rail. Both failures compile
cleanly.

Replace it with a cursor. Objects placed with an empty coordinate
argument reserve their own width -- including a stack's offset sheets
and a bracket's overhang -- and gaps are declared once (\stgutter,
\strowgap, \stblockgap). The gap belongs to the object that follows it
and the first object in a band gets none, so every band starts flush on
a shared rail and gap=0pt states that two shards tile exactly.

\stlink makes a connector's label a flow object, which is what removes
the label-wider-than-its-arrow failure entirely. \stcol is a vertical
sub-flow for a split along the contracted axis. \strow declares its
height, so an object that does not fit -- or a column that does not add
up to what it declared, and is therefore drawn off-center -- becomes a
package warning, which build.sh fails on.

Absolute placement is unchanged: passing a coordinate takes the original
code path, and \sttrack folds a hand-placed node back into the cursor.

All three golden examples and the new tests/flow.tex are converted and
build clean.
This commit is contained in:
dela
2026-08-05 15:55:21 +08:00
parent 7a22bef9e3
commit 7b59c81d02
11 changed files with 672 additions and 223 deletions
+17 -7
View File
@@ -37,14 +37,14 @@ A minimal figure:
\stdim{d}{4}
\begin{document}\begin{tikzpicture}
\stface[role=act, bracket=true]{X}{(0,0)}{T}{d}
\node[st op, right=6mm of X] (m) {$\times$};
\stface[role=w]{W}{($(m)+(1.4,0)$)}{d}{d}
\node[inner sep=0pt, fit=(X)(W)] (row) {};
\stlane{row}
\ststage{S1}{one band, placed by cursor}
\strow{row}{T} % band height, declared once
\stface[role=act, bracket=true]{X}{}{T}{d} % empty coord = at the cursor
\stglyph{m}{$\times$}
\stface[role=w]{W}{}{d}{d}
\strowend
\stcaption{X}{$\mathbf X$}{$T\times d$}
\stcaption{W}{$\mathbf W$}{$d\times d$}
\stnolane
\end{tikzpicture}\end{document}
```
@@ -52,13 +52,19 @@ Because `T` and `d` come from the ledger, the contracted axis is automatically o
length in both operands, `d×d` is automatically square, and any other face of shape `T×d`
in the figure is automatically identical to `X`.
Because the coordinates are empty, each object reserves its own width and the gap between
them is `\stgutter`, declared once. Nothing here is a tuned offset, so growing a label can
only push its neighbours apart — it can never land on top of one. And the band declares its
height, so an object that does not fit is a failed build rather than something the reader
discovers.
See `references/api.md` for the full macro list.
## Examples
| file | shows |
|---|---|
| `tp-ffn-allreduce.tex` | column-then-row sharding, exact tiling, one hue per TP rank, a collective as a real node |
| `tp-ffn-allreduce.tex` | column-then-row sharding, exact tiling, one hue per TP rank, a collective as a real node, a `\stcol` split along the contracted axis |
| `mha-causal.tex` | leading axes as stack depth, a physically swapped `Kᵀ`, a mask in a different grammar from the scores it gates |
| `moe-topk-gather.tex` | scores → indices → Boolean support → gather, with all three cell grammars side by side |
| `antipatterns.tex` | four figures that compile cleanly and still teach something false |
@@ -77,6 +83,10 @@ Two LaTeX warnings produce a figure that is quietly wrong rather than visibly br
greps for both and exits non-zero. A `Package supertensor Warning` — an undeclared role
falling back to gray — is treated the same way.
The flow layout adds two of its own: an object that overflows its band, and a `\stcol`
whose contents do not add up to the height it declared (which means it is drawn
off-center). Both are things a reader would have to notice for you.
A clean build still proves nothing about collisions, hue budget or whether the math is
right. That is what `references/checklist.md` is for.