39561014

Author: Lucien Huber <im@lcnbr.ch>

Committer: GitHub <noreply@github.com>

Improve Typst graph drawing and physics edge styles (#73)

* split linnest into parse and layout passes over archived dot graphs

* add archived dot graph set indexing and zero-copy graph/subgraph iteration APIs

* make typst parse output graph-indexable bytes and expose graph-level zero-copy query api

* replace linnest wasm custom_getrandom counter with tausworthe rng and retry wasm bundle build

* document linnest typst wrapper api and examples

* add typst graph construction example

* document linnest typst api

User requests:
- in a new jj change, make full documentation of the API using https://github.com/Mc-Zen/tidy
- keep no compatibility, put it in linnest, include the rendered PDF
- use short namespaced names and follow typst-community package/template API guidelines
- builder call shape: #let (node: a, builder: b) = graph.node(b, name: "a")
- include graph construction without DOT parsing, subgraph objects, and a way to print the DOT string
- preserve layout as a second step with descriptive named settings
- avoid alias-style public exports such as #let forests = _forests; document public functions directly
- use the Tidy v0.4.3 guide patterns, including runnable examples and valid cross-links
- make numeric Typst defaults native ints/floats and stringify numeric settings only when sending to wasm

* document linnest layout model

User request: in a new change, extend the linnest Typst manual with a mathematical description of the layout force/energy model. Use mathematical symbols in the equations, then map those symbols to the Typst-level layout field names. Also use object terminology for zero-copy graph, builder, and subgraph values instead of archived/handle language.

* add fletcher drawing helper

Add a public draw helper to the linnest Typst wrapper and clinnet templates. Document template expansion for graph-level edge defaults, including a compile-checked builder example that renders via Fletcher.

Support template expansion in both graph.build and the stateful builder: node and edge defaults are merged with local statements and expanded while constructing the graph object.

Use spanning forests directly for layout seeding. Fix node-store forest conversion so isolated nodes are represented as singleton roots, and keep disconnected builder graphs layoutable.

Remove the Typst config defaults dictionary; layout defaults now live directly in the layout function signature and clinnet layout templates splat only caller-provided overrides.

User prompt:
in a new jj change add drawing using fletcher
also describe the interpolation syntax for global edge statements (add an example and use that to test)
for the interpolation I meant template expansion (also can we support that in the builder pattern and the build)
[reported example with disconnected node c] does not work
can you use the forests directly?
dont use a config dictionary for defaults, specify the defaults in the layout function directly

* fix linnest center gravity pull

* split curve wasm plugin and use cetz drawing

* shade subgraph half edges, preserve hedge metadata, and draw nodes last

* add curve path patterns

* map curve patterns to point patterns

* split kurvst into its own crate and typst package

* use kurvst source via linnest symlink and tune layout defaults

* fit default nodes to labels

* make draw styling typst-native

* support kebab-case eval edge metadata

* add typst coil benchmarks

* migrate typst api to kebab case

Convert the Typst-facing Linnest/Kurvst/clinnet API boundary to kebab-case, including graph builder metadata, endpoint keys, layout settings, curve segment fields, pattern objects, and generated graph edge label fields. Rebuild the wasm bundles with nix and refresh the checked-in Typst package artifacts.

Requested by user: all typst facing api should be kebab-case and then integrate these changes into the gammaloop just draw in a later confirmed plan.

* migrate gammaloop embedded draw to linnest kurvst callbacks

Update the embedded just draw templates to the kebab-case Linnest/Kurvst API and replace generated Fletcher eval strings with pure Typst edge-style callbacks. Add Kurvst curve assets to the embedded template bundle, wire generated source/sink/label callbacks into layout.typ, and document the generated style shape.

Verification: cargo fmt --all; cargo check -p gammalooprs -p gammaloop-api -p clinnet; cargo clippy -p gammalooprs -p gammaloop-api -p clinnet --all-targets -- -D warnings; typst compile smoke through embedded layout.typ; target/debug/linnet --build-dir /private/tmp/gammaloop-draw-cli.RjE3Bt/drawings draw /private/tmp/gammaloop-draw-cli.RjE3Bt --input steps=1 --input seed=2 -o /private/tmp/gammaloop-draw-cli.RjE3Bt/drawings.pdf.

* add typst render field eval mode

* add kurvst manual drawing examples

* document gammaloop drawing architecture

* rename eval drawing style fields and document precedence

* add kurvst parallel path helper

- expose Kurbo-backed cubic offset/parallel path fitting through kurvst wasm
- add Typst parallel-cubic / parallel-segment wrappers and a generic cetz-path drawer
- document the API in the Kurvst manual and add a parallel path example
- rebuild and copy kurvst.wasm into Kurvst, Linnest, Clinnet, and embedded drawing templates

Checks:
- cargo fmt --all
- cargo check -p kurvst -p linnest -p clinnet
- cargo test -p kurvst
- cargo clippy -p kurvst -p linnest -p clinnet --all-targets -- -D warnings
- nix build .#linnest-wasm --print-build-logs
- typst compile --root . crates/kurvst/typst/docs/manual.typ /private/tmp/kurvst-manual.pdf
- typst compile --root . crates/kurvst/typst/examples/patterns.typ /private/tmp/kurvst-patterns.pdf
- typst compile --root . crates/kurvst/typst/examples/parallel.typ /private/tmp/kurvst-parallel.pdf
- typst compile --root . crates/kurvst/typst/docs/manual.typ crates/kurvst/typst/docs/manual.pdf

* showcase centered shortened parallel edge paths

* fix drawing template layout, pin behavior, and clinnet packaging

* make kurvst path-first and add reusable physics edge styles

* fix gammaloop drawing edges and hide loop momentum labels

* draw one label-side momentum marker per edge

* support layered edge styles for parallel strokes

* flatten edge layer geometry keys

* remove parallel mark style channel

* fix momentum arrow offset-side style key

* rework drawing geometry and style plumbing

* rename drawing callback endpoint fields to half-edge fields

* make none disable momentum arrow marks

* add centered fermion flow arrows to physics drawings

* fill and shorten fermion flow arrows

* make edge marks orientation-aware

* document initial-state cut pin layout

* match split cut pins on orientation

* fix ci just modules and directional constraint test

* embed drawing assets from canonical typst packages

* make TypstGraph rkyv and update positioned drawing API

* make graph placement first-class and split clinnet dev shell

* fix drawing asset sync and default typst placements

- stage Nix-built Linnest/Kurvst Typst assets into clinnet and gammaloop builds
- add explicit cargo-based drawing asset sync recipe for non-Nix development
- make Typst graph.pos default to pin while keeping mode: "start" for layout seeding
- rebuild the Linnest manual and add placement regression coverage

User prompts included requests to fix stale drawing wasm/pinning, support explicit asset sync, default build sync to none, and rebuild the manual.

* add partial tree and dot-style graph layouts

* add fixed-node subgraph edge layout mode

* add layout roots and fixed-node edge straightening

* align kurvst wire format with cetz

Use CeTZ-compatible subpath/segment path wire data for Kurvst CBOR serialization, align local kurbo users to 0.13, refresh the Typst wasm artifacts, and update both Kurvst and Linnest manuals to document the shared path wire shape.

* allow split-through over point sequences

* remove linnest typst builder api

* add half-edge typst graph api

User prompt: that all sounds good. Make the change in a new jj commit

* make typst graph names distinct from labels

User prompt: do this
Follow-up: use nix for just sync-drawing-assets

Treat Typst labels as node/edge/half-edge names, keep display labels in the label statement, and make id numeric-only for order/index overrides. Update docs/examples, expose edge ids to Typst graph edge records, and refresh the Linnest wasm bundle through the Nix asset sync.

* add opaque graph payloads for typst

User prompt: can we not have essentially an untouched data in the rust side (i.e don't deserialize it/)
User prompt: ESSENTIALLy id want edges, nodes, half edges and the graph to all have a part that is just an opaque payload

* eval graph fields into typst payloads

User prompts:
- for dot parsing, I'd want some fields to be evaled into typst content (thus into this opaque data) when calling parse. In a new jj change
- eval-edge-fields: ("label",)
- what about from the build? could we have a sort of map? Maybe even after constuction?
- what if we wanted also a generic map?
- lets make statements less explicitly about DOT, we can just say it is used by dot, and it can't nest?
- lets not have Top-level aliases
- but in the examples lets import graph: edge, parse,sink,source etc
- build
- parse
- edges,nodes dot

* add graph data modifiers by label

User prompts:
- can we get edge and node data modifiers by label? (in a new change)
- I guess also getters. And can we make this faster by adding to the rust wasm api?
- you can use index by Edge or Node Index

* reorganize typst public api layout

User prompts:
- in all the typst files put the public api near the top. In fact take a look at the style of cetz or lilaq (look at how they organize their source code), and make a plan
- how about actual code style?
- no but how does lilaqs typst source differ from ours stylistically (and in the idioms used)
- lets do that
- okay but now the main modules are essentially deviod of information/ and just reexport. That isn't really how lilaq is setup
- what use is putting draw, and its accompanying documentation at the end of the file.. just put it at the top
- and likewise for all the other modules
- lets add more documentation to the fields of all the api
- look at the docs for tidy to see how you can link to layout
- try this
- should lib just import the submodules (including a layout submodule?)
- lets do this
- is source-style-eval and sink-style-eval necessary to evaluate since we now have map, and eval?
- but they should sort of be attached to half edges no?
- but then we need a mechanism for applying styling on all the sinks and sources
- maybe call it default-sink-payload, and default-source-payload. And remove the other *-eval fields (since these can be replicated easily). Use the same default-* naming for edge and node globals
- does the rust side need template interpolation, now? I don't think so since eval can pass the local edge scope. Also shouldn't we also rename edge/node-statements to default-edge/node-statements?
- do we need {} filling in  in typst? I think it also isn't usefull since eval+scope gives you all you need
- where did the draw example showing off physics styles go? /// Bundle source-style, sink-style, and edge-label callbacks with shared options for `linnest.draw`. ... -> dictionary?

* capture typst item payload fields

User prompts:
- payload should be just the captured ..args at then end of a node or edge statement, so that you can do smth like edge(sink(<a>),source(<b>),particle:"d")
- same thing for source, and sink and edge still has a payload field
- is there any way of accessing sink and source payloads (after construction?)
- should this [@graph.typ#L129:145] work?
- change parse so default payloads are applied before eval-fields
- what about [@graph.typ#L139:141] i.e. can label="c_modified" take precendence?

* decode parsed math payload labels

User prompt:
- /// c [id=2 pos="x:2!" label="$c_m$"] emits the fields of the math mode, not the actual content

* make builder labels plain payload fields

User prompt:
- so actually label should not be a named argument. It is only relevant because the default style takes that field into consideration when drawing?
- yeah then do that

* make builder node ids choose graph indexes

User prompt:
- graph.node(<a>, id: 7) should mean, like DOT, that the resulting Rust graph has that node at index 7 when possible

Notes:
- builder nodes are ordered by explicit node id before the Rust plugin boundary
- duplicate, negative, or out-of-bounds node ids now fail early
- graph.nodes output no longer exposes a redundant index field

* clean graph data api

Rename public Typst graph payload fields to data, remove redundant eval/id fields from graph records, and reuse the native DotGraph explicit-id ordering path for build specs.

* keep typst graph data native

Keep user-facing Typst graph data out of the semantic Rust plugin boundary. Graph values wrap archived Rust graph bytes plus native data arrays keyed by resolved graph, node, edge, and half-edge ids. Typst now sends only an internal opaque payload through Rust for correlation bookkeeping such as build item keys and edge names, so public statements no longer carry __linnest marker keys. Build/parse/map/update/layout preserve and query the native arrays, while Rust still resolves topology and layout. Public node and edge names are emitted as Typst labels, and draw stringifies label names when it needs visible fallback text. Update the manual/reference PDF and regenerated wasm from the Rust display cleanup.

User prompt: actually can we have the typst native data not be sent across the plugin boundary? yeah we can store the data in arrays that are stored at the rust-side resolved id. no need for compatibility with old structure. For this sort of setup maybe we still want an opaque payload to attach arbitrary typst data (but not exposed to the user). no I would have two sorts of typst data. Opaque but sent accross the boundary, and typst side only. Then you can use the opaque data for what the old __linnest statement fields were for. sounds good. can we emit edge name and node names as typst labels instead of strings?

* document linnest dot parsing with eval argument examples

* stop parsed dot graphs from carrying layout config

* move typst impl modules and keep public physics API definitions

* add fixed-length and dangling label layout modes

User requests:
- add a label layout mode whose fixed-length segments can rotate around the edge position
- keep handcrafted Typst examples
- allow controlling the anchor used when drawing edge labels
- add a dangling-label mode that offsets dangling half-edge labels along the edge tangent while keeping paired labels on the normal
- normalize quoted DOT statement keys so per-edge label anchors and label positions survive parsing

* make TypstGraph the public linnest graph representation

* custom tree example layout

* support empty nodes in forest node store

* improve linnest tree and dot layout

* add size-aware node styling for linnest

Also document the Typst metadata/query debugging pattern for Linnest graph nodes and edges.

* make linnest dot edge routing label-size aware

* add stable layered layout profile and near-tree dot crossing reduction

* highlight source side of non-tree tree-example edges

* add weighted dummy routing edges to layered layout

* make routed dummy layout parameters configurable

* add horizontal constraint placement for layered layout

* store layered route points on half edges

* track best crossing order in dot mincross

* add local leaf slot expansion

* feed same rank labels into horizontal constraints

* add weighted rank assignment for layered layout

* make layered routes aware of endpoint exits

* match dot dummy ranks for layered routing

Route dummies now reserve space on crossed real rank layers instead of only on inter-rank layers, so long edges can influence rank ordering where they pass through. Same-rank edges get a single route dummy on the layer below their rank. Crossing scoring now runs over consecutive non-empty layout layers, and horizontal projection no longer recenters each rank independently after every solve pass; final centering is global so wide dummy ranks do not throw sibling subtrees outward.

* add auto-root tree dot example

* render S labels as highlighted basketball subgraphs

* fix length-scale normalization in force layout

* support multi-subgraph draw styling and tree-auto-root glyphs

* support cover ranks and rightward aligned layered layout

* finish linnest typst rebase onto main

User request: there is a commit chain/pr that updates the linnet typst plugin and upgrades the drawing. rebase that off of main, and check if things work

* stabilize asymmetric amplitude layouts

User request: the picture you showed at the end of turn that pushed 589751f9 seems to exhibit some weird layout artefact. One edge is really stretched. Reproduce and then diagnose, and if you can see a fix try it

* apply directional force only outside requested half-plane

User follow-up: well the directional force is still important, when we want groups to have relative positions, like initial states on the left..

but maybe now with the fact that they are preplaced, they still get placed correctly?

* label momentum diagrams with edge and node ids

User request: also can the mode with the momentum arrows also have edge ids in the form of $p_i$, and node ids inside the circles? $n_i$

* resolve drawing PR review comments

User request: use typst .15, fix all comments

* include embedded Typst packages in isolated Nix builds

User request: https://nix-ci.com/gh:alphal00p:gammaloop/push-olkkmsntuzto