umlimator 0.20.0 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -22,11 +22,10 @@ drill-down, a data pipeline, an AI agent's skills, and host pages for embedding,
22
22
  straight; orthogonal lines that never run through a card, room for every label, containers kept apart, and cards with
23
23
  no lines in a row of their own, under the view or at the bottom of their box. The same model gives the same picture.
24
24
  - **Reading**: animated flow, neighbours lit on selection, numbered steps, tours, minimap, light and dark themes.
25
- - **Card shapes**: three notations. `box` (the default) draws every card as a rounded box, as before. `c4` draws people,
26
- browser apps, phones, databases, queues and files as the C4 model's tools do. `uml` draws UML 2.5's actors, nodes,
27
- artifacts, packages and data stores, with UML's component icon on a box. A card's own `shape` wins in any notation.
28
- The notation comes from the model, a view, `render()`, the page's toggle or the link; switching it draws the cards
29
- again and lays nothing out ([`examples/notations.html`](examples/notations.html)).
25
+ - **Card shapes**: one style, the union of what the C4 model's tools and UML 2.5 draw: people, robots, browser apps,
26
+ phones, terminals, queues, packages, hosts, data stores, files and hooks, each by its card's kind, and a rounded box
27
+ where no shape says more. A card's own `shape` wins. Each shape keeps to its card's box, so the layout is the same
28
+ ([`examples/notations.html`](examples/notations.html)).
30
29
  - **Exploring**: every path between two cards, or everything a card reaches, lit on the map; a view in plain sentences
31
30
  (`describe()`); a tour along any path the host names.
32
31
  - **Live data**: marks over the map without touching the model (`overlay()`): flow as fast as the traffic, errors that
@@ -66,8 +65,37 @@ drill-down, a data pipeline, an AI agent's skills, and host pages for embedding,
66
65
  [what it covers](docs/conformance/uml-communication.md)). Messages are inserted, moved in time, wrapped in a frame and
67
66
  deleted on the canvas, by pointer and by key, each gesture an `edit` event; checked by the types' rules; a sequence
68
67
  diagram is read from and written to Mermaid's `sequenceDiagram`, and an OpenTelemetry trace becomes one
69
- (`umlimator.py trace --diagram uml.sequence`). The MCP server, the `map-repo` skill and the diff Action learn these
70
- types in one package after 0.20.0; until then a reorder of a view's messages shows in a diff as changed, not moved.
68
+ (`umlimator.py trace --diagram uml.sequence`). A diff says "moves" for a reordered message, and `paths()` on a
69
+ sequence view runs in time order (0.22.0).
70
+ - **UML use case, activity, state machine and interaction overview diagrams** (0.21.0): actors as stick figures, use
71
+ cases as ellipses with their extension points, a subject as a box holding its use cases, include, extend and
72
+ generalization ([`examples/shopping-use-cases.json`](examples/shopping-use-cases.json),
73
+ [what it covers](docs/conformance/uml-use-case.md)); actions, object nodes, data stores, send and accept actions, call
74
+ behaviour actions that open the activity they call, and the control nodes, in lanes (partitions, nested)
75
+ ([`examples/fulfil-activity.json`](examples/fulfil-activity.json), [what it covers](docs/conformance/uml-activity.md));
76
+ states with their entry, do and exit activities and internal transitions, composite states as boxes, orthogonal
77
+ regions with dashed dividers, every pseudostate, and transitions written `trigger [guard] / effect`
78
+ ([`examples/order-states.json`](examples/order-states.json), [what it covers](docs/conformance/uml-state-machine.md));
79
+ interaction uses and inline interactions, drawn with their sequence diagram inside, joined by the activity's control
80
+ nodes ([`examples/buy-book-overview.json`](examples/buy-book-overview.json),
81
+ [what it covers](docs/conformance/uml-interaction-overview.md)). Lines end on the outline of a circle, a diamond, a
82
+ bar or an ellipse. F2 edits a transition's or a flow's label through its parts; a drop changes a node's lane or a
83
+ state's region. A state machine is read from and written to Mermaid's `stateDiagram`. The MCP server's read tools and
84
+ the diff Action are tested on all four.
85
+ - **UML component, deployment and composite structure diagrams** (0.22.0): components nested in components and
86
+ packages, ports on their borders, provided and required interfaces as a ball and socket or as a rectangle, assembly
87
+ and delegation connectors (a delegation runs from a box's port inward to the port of what it holds), artifacts and
88
+ their manifestations ([`examples/bookshop-components.json`](examples/bookshop-components.json),
89
+ [what it covers](docs/conformance/uml-component.md)); nodes, devices and execution environments drawn as cubes and
90
+ nested to any depth, artifacts deployed in them or by a «deploy» line, deployment specifications and communication
91
+ paths ([`examples/bookshop-deployment.json`](examples/bookshop-deployment.json),
92
+ [what it covers](docs/conformance/uml-deployment.md)); a class's parts and ports, each part showing its type's ports,
93
+ connectors through parts, open collaborations as dashed ellipses and collaboration uses with their role bindings
94
+ ([`examples/order-service-structure.json`](examples/order-service-structure.json),
95
+ [what it covers](docs/conformance/uml-composite-structure.md)). A port's side is chosen from where its lines go, or
96
+ pinned by a drag or Alt + arrows; `B` turns an interface into a ball and back; a port or a part is added as a row of
97
+ its owner. The MCP server's read tools and the diff Action are tested on all three, and the Bookshop atlas opens them
98
+ from the map's Hosts.
71
99
  - **Export**: any view as a stand-alone SVG or PNG, in the browser or from the CLI; the whole map as one PDF to hand in
72
100
  for a review: a cover with the contents, each view with its legend and tables of its cards, lines and boxes, then the
73
101
  rules (`umlimator.py pdf`).
@@ -90,7 +118,7 @@ drill-down, a data pipeline, an AI agent's skills, and host pages for embedding,
90
118
  npm install umlimator
91
119
  ```
92
120
 
93
- Or from GitHub, at a tag or any commit: `"umlimator": "github:zintaen/umlimator#v0.20.0"`. npm 12 refuses git
121
+ Or from GitHub, at a tag or any commit: `"umlimator": "github:zintaen/umlimator#v0.22.0"`. npm 12 refuses git
94
122
  dependencies unless the project opts in, so that also needs `allow-git=root` in the `.npmrc` next to `package.json`.
95
123
 
96
124
  ## Embed
@@ -135,17 +163,15 @@ function MapView({ model, onSelect }) {
135
163
  - `map.lens(id)` puts one of the model's lenses on the map. `critical(model, view, { from, to, by })` finds the slowest
136
164
  or costliest path, `whatIf(model, view, { remove })` what loses its way when cards go down, and
137
165
  `sequenceFromTrace(model, spans, { view, match })` keeps a trace as a numbered view; all three in Node too.
138
- - `shapes: 'box' | 'c4' | 'uml'` draws every view in that notation, over each view's own (and the model's).
139
- `map.shapes` reads the notation shown and sets another (`null`: each view's own again); the cards are drawn again from
140
- the geometry they have, with the camera, selection and marks kept, and nothing is laid out.
141
166
  - `editable: true` turns on editing gestures ([docs/editing.md](docs/editing.md); `examples/edit.html` is a working host).
142
- - `import { render, apply, history } from 'umlimator/all'` draws diagram types too: a class, object, package, sequence or communication diagram, whose gestures emit
167
+ - `import { render, apply, history } from 'umlimator/all'` draws diagram types too: a class, object, package, sequence, communication, use case, activity, state machine, interaction overview, component, deployment or composite structure diagram, whose gestures emit
143
168
  `edit` transactions that `apply(model, e.commands)` turns into the next model (`examples/class-editor.html` is a
144
169
  working host). `umlimator` alone draws maps, and a typed view as plain cards with a warning.
145
170
  - `diff(before, after)` returns `after` with each card and line marked added, changed or removed, what changed in words,
146
- and the views that show it; `drift(model, observed)` marks the lines traffic ran on that nobody drew, and the drawn ones
147
- that carried nothing. Both are models to draw, in Node too. `update()` eases into the next model (`examples/timelapse.html`);
148
- the option `ease: false` draws it at once.
171
+ and the views that show it (on a typed diagram, a reordered member or message reads "moves");
172
+ `drift(model, observed)` marks the lines traffic ran on that nobody drew, and the drawn ones that carried nothing. Both
173
+ are models to draw, in Node too. `update()` eases into the next model (`examples/timelapse.html`); the option
174
+ `ease: false` draws it at once.
149
175
  - `mountPage` is the whole standalone viewer that the CLI writes. `render()` can draw its pieces too, each on its own or
150
176
  any mix, inside the map's element; the host keeps its own header:
151
177
 
@@ -182,8 +208,7 @@ the map is drawn, and stay where scripts don't run ([`examples/element.html`](ex
182
208
  - **Attributes**: `view`, `minimap`, `controls="false"`, `wheel="ctrl"` (the wheel zooms only with Ctrl or ⌘, and scrolls
183
209
  the page otherwise, as a map in a document should), `height` (a number is pixels; 480 by default, or size it in CSS)
184
210
  and `theme` (`light` or `dark`: theme.css's palette for that map, whatever the page's). Changing one draws the map
185
- again, and removing the element destroys it. `shapes` (`box`, `c4` or `uml`) is the notation; changing it draws the
186
- cards again in the map drawn, with nothing loaded or laid out again.
211
+ again, and removing the element destroys it.
187
212
  - **Events**: `umlimator:select`, `umlimator:open` (cancel it to stay) and `umlimator:viewchange`, the map's event as
188
213
  `detail`; `load` once it is drawn, `error` when it can't be. `el.map` is the `render()` handle.
189
214
  - **Colours**: theme.css, as above, or your own `--um-*` variables. The element fetches nothing but its model.
@@ -218,8 +243,10 @@ path. The full schema is `engine/references/schema.md` (§ Map model); `examples
218
243
  A model file that starts with `"$schema": "<path to>/umlimator.schema.json"` (exported as `umlimator/schema.json`)
219
244
  gets completion and checks in editors, and `validate(model)` lists its errors and warnings, each with where it is.
220
245
  `"schemaVersion": 2` marks a model that may hold typed elements and typed views (`docs/diagrams/model.md`). A view whose
221
- `diagram` is `"uml.class"`, `"uml.object"`, `"uml.package"`, `"uml.sequence"` or `"uml.communication"` is a UML class, object,
222
- package, sequence or communication diagram, drawn by `umlimator/all` and the CLI; a type not drawn yet shows its
246
+ `diagram` is `"uml.class"`, `"uml.object"`, `"uml.package"`, `"uml.sequence"`, `"uml.communication"`, `"uml.use-case"`,
247
+ `"uml.activity"`, `"uml.state-machine"`, `"uml.interaction-overview"`, `"uml.component"`, `"uml.deployment"` or
248
+ `"uml.composite-structure"` is a UML class, object, package, sequence, communication, use case, activity, state machine,
249
+ interaction overview, component, deployment or composite structure diagram, drawn by `umlimator/all` and the CLI; a type not drawn yet shows its
223
250
  nodes as plain cards, with a warning. A model with no `schemaVersion` is a map, as always, and a version newer than the
224
251
  module reads is an error.
225
252
 
@@ -233,7 +260,7 @@ kinds such as `public`, `lane`, `script`, `hook` and `board` work too). Fields b
233
260
  | node | `noSub` | the name only; the description stays in the details panel |
234
261
  | node | `opensView`, `opensCount` | the view the card opens, which may not be loaded yet, and the ⤢ number for it |
235
262
  | node | `owner` | who owns the card (a team): rules and lenses pick by it, and a lens can ring cards by owner |
236
- | node | `shape` | the card's own shape in every notation: `box`, `person`, `browser`, `mobile`, `cylinder`, `pipe`, `document`, `hexagon`, `robot`, `terminal`, `window`, `folder` or `node` |
263
+ | node | `shape` | the card's own shape, over the one its kind draws: `box`, `person`, `browser`, `mobile`, `cylinder`, `pipe`, `document`, `hexagon`, `robot`, `terminal`, `window`, `folder` or `node` |
237
264
  | node, edge | `edited` | a marker on the card or line |
238
265
  | edge | `kind` | what the line means, drawn as its colour: `calls` (default), `feeds`, `triggers`, `state`, `guard` |
239
266
  | edge | `weight` | 1, 2 or 3: how much the line stands for, drawn as its width |
@@ -249,9 +276,8 @@ kinds such as `public`, `lane`, `script`, `hook` and `board` work too). Fields b
249
276
  | view | `repair: false` | no port repair |
250
277
  | view | `subAndChips` | cards 80 px tall that show their sub-line, then their chips |
251
278
  | view | `kindsFromLabels` | a line whose edges name no `kind` takes one guessed from its label |
252
- | view, model | `shapes` | the notation the cards are drawn in: `box` (default), `c4` or `uml`; a view's wins over the model's ([what each draws](docs/module-api.md#card-shapes-box-c4-and-uml)) |
253
279
  | container | `badges` | tabs on the box's border |
254
- | container | `tone` | a palette name, as a badge's: the region behind the box tinted in it, its border dashed and its title in the tone (in `c4`, every box is dashed) |
280
+ | container | `tone` | a palette name, as a badge's: the region behind the box tinted in it, its border dashed and its title in the tone |
255
281
  | model | `rules` | what must hold: no line `from` some cards `to` others (picked by id, kind, box or owner), or `noCycles` between boxes |
256
282
  | model | `stories` | walk-throughs: steps that each set the view, camera, selection, highlight, tour and caption |
257
283
  | model | `lenses` | ways to look at the map: what `pick` picks (by id, kind, box, owner or `line` kind) lit, the rest dimmed; `color: "owner"` rings cards by owner |
@@ -287,6 +313,38 @@ and a communication diagram (`examples/checkout-communication.json`,
287
313
  | view | `edges` | a sequence view's messages and interaction uses (`uml.InteractionUse`, `props.covers`), inline and in time order; a communication view's connectors, then its messages, by id, in order. Bars and numbers are derived |
288
314
  | view | `fragments` | a sequence view's combined fragments (`uml.CombinedFragment`, `props.operator`), each with its operands as `members` (`label` the guard); a message's or fragment's `parent` is its operand |
289
315
 
316
+ A use case diagram, an activity diagram, a state machine diagram and an interaction overview diagram
317
+ (`examples/shopping-use-cases.json`, `fulfil-activity.json`, `order-states.json` and `buy-book-overview.json`; each
318
+ type's note in [`docs/conformance/`](docs/conformance/)), from 0.21.0:
319
+
320
+ | On | Field | What it does |
321
+ |---|---|---|
322
+ | node, member, edge | `type` | use case: `uml.Actor`, `uml.UseCase` (members `uml.ExtensionPoint`), `uml.Subject`; lines `uml.Association`, `uml.Include`, `uml.Extend`, `uml.Generalization` |
323
+ | node, edge | `type` | activity: `uml.Action`, `uml.CallBehaviorAction`, `uml.SendSignalAction`, `uml.AcceptEventAction`, `uml.ObjectNode`, `uml.DataStoreNode`, `uml.InitialNode`, `uml.ActivityFinalNode`, `uml.FlowFinalNode`, `uml.DecisionNode`, `uml.MergeNode`, `uml.ForkNode`, `uml.JoinNode`, `uml.ActivityPartition`; lines `uml.ControlFlow`, `uml.ObjectFlow` |
324
+ | node, member, edge | `type` | state machine: `uml.State` (members `uml.Region`, `uml.InternalTransition`), `uml.Pseudostate`, `uml.FinalState`; lines `uml.Transition` |
325
+ | node, edge | `type` | interaction overview: the activity's control nodes, `uml.InteractionUse`, `uml.Interaction` (an inline interaction); lines `uml.ControlFlow` |
326
+ | node | `parent` | a use case's subject; an activity node's partition (its lane), a partition's enclosing partition; a substate's state or region |
327
+ | node | `opensView` | the activity a call behaviour action calls; the sequence view an interaction use or inline interaction shows |
328
+ | node | `props` | a state's `entry`, `do`, `exit`; a pseudostate's `kind` (`initial`, `choice`, `junction`, `fork`, `join`, `shallowHistory`, `deepHistory`, `terminate`) |
329
+ | edge, member | `props` | an extend's `extensionPoints` (ids) and `condition`; a flow's `guard` (its `label` is its name); a transition's or internal transition's `trigger`, `guard` and `effect`, drawn `trigger [guard] / effect` |
330
+ | view | `diagram` | `"uml.use-case"`, `"uml.activity"`, `"uml.state-machine"` or `"uml.interaction-overview"` |
331
+
332
+ A component diagram, a deployment diagram and a composite structure diagram (`examples/bookshop-components.json`,
333
+ `bookshop-deployment.json` and `order-service-structure.json`; each type's note in
334
+ [`docs/conformance/`](docs/conformance/)), from 0.22.0:
335
+
336
+ | On | Field | What it does |
337
+ |---|---|---|
338
+ | node, member, edge | `type` | component: `uml.Component` (members `uml.Port`), `uml.Interface`, `uml.Artifact`, `uml.Package`; lines `uml.InterfaceRealization`, `uml.Usage`, `uml.ComponentRealization`, `uml.Connector`, `uml.Dependency`, `uml.Manifestation` |
339
+ | node, edge | `type` | deployment: `uml.Node`, `uml.Device`, `uml.ExecutionEnvironment`, `uml.Artifact`, `uml.DeploymentSpecification`, `uml.Component`; lines `uml.Deployment`, `uml.Manifestation`, `uml.CommunicationPath`, `uml.Dependency` |
340
+ | node, member, edge | `type` | composite structure: the subject (`uml.Class`, `uml.Component` or `uml.Collaboration`) with its parts (`uml.Property`) and ports (`uml.Port`), `uml.Collaboration` (its roles `uml.Property`), `uml.CollaborationUse`; lines `uml.Connector`, `uml.RoleBinding` (its `label` the role) |
341
+ | node | `parent` | a component's component or package; an artifact's target (deployed by nesting); a target's target (any depth); a collaboration use's subject |
342
+ | node, member | `props` | a port's `valueType`; a part's `valueType` (the class or component whose ports it shows, by label), `multiplicity` and `aggregation` (`shared` is dashed); a collaboration use's `collaboration` |
343
+ | edge | `props` | a connector's `kind` (`assembly`, `delegation`); an end through a part, `ends.from.part` or `ends.to.part` (UML's `partWithPort`) |
344
+ | view | `subject` | a composite structure view's class, component or collaboration, listed in `nodeIds` |
345
+ | view | `present` | an interface drawn as a ball (`{ "as": "ball" }`); a port's side (`{ "side": "left" }`); on a part, `{ "ports": { "<port>": { "side": "top" } } }` |
346
+ | view | `diagram` | `"uml.component"`, `"uml.deployment"` or `"uml.composite-structure"` |
347
+
290
348
  ## Command line
291
349
 
292
350
  ```bash
@@ -303,6 +361,7 @@ python3 umlimator.py record bike-share.html --story ride --out ride.png # bike
303
361
  python3 umlimator.py import workspace.dsl --out model.json # a diagram you have already, as a model
304
362
  python3 umlimator.py import classes.mmd --out classes.json # a Mermaid classDiagram, as a UML class diagram (needs Node)
305
363
  python3 umlimator.py import checkout.mmd --out checkout.json # a Mermaid sequenceDiagram, as a UML sequence diagram (needs Node)
364
+ python3 umlimator.py import order.mmd --out order.json # a Mermaid stateDiagram, as a UML state machine diagram (needs Node)
306
365
  python3 umlimator.py render examples/sales-classes.json --out classes.html # a class diagram's page; stills, check and pdf take it too
307
366
  docker compose config --format json > compose.json && python3 umlimator.py import compose.json --out model.json
308
367
  kubectl get deploy,sts,svc,ing -A -o json > cluster.json && python3 umlimator.py import cluster.json --out model.json
@@ -316,14 +375,14 @@ python3 umlimator.py mcp model.json # an MCP
316
375
 
317
376
  `import` reads Structurizr DSL (people, systems, containers and components, their relationships, and the workspace's
318
377
  views), C4-PlantUML (its element, relationship and boundary macros), Mermaid (`flowchart` or `graph`, and `C4Context`,
319
- `C4Container` or `C4Component`; a `classDiagram` becomes a UML class diagram and a `sequenceDiagram` a UML sequence
320
- diagram, each read through Node), and the JSON of `docker compose config` (services, `depends_on`, networks) and of
378
+ `C4Container` or `C4Component`; a `classDiagram` becomes a UML class diagram, a `sequenceDiagram` a UML sequence
379
+ diagram and a `stateDiagram` a UML state machine diagram, each read through Node), and the JSON of `docker compose config` (services, `depends_on`, networks) and of
321
380
  `kubectl get` (workloads, Services, Ingresses). It tells the format from the content, then the extension; `--format`
322
381
  decides. Groups, boundaries, subgraphs, networks and namespaces become boxes; Structurizr's views stay views, a card
323
382
  opening the view below it; `examples/clinic.json` is `examples/clinic.dsl`, imported. What each element becomes, and
324
383
  what is left out: [docs/module-api.md § Import](docs/module-api.md#import-90). Whatever the file holds that `import`
325
- doesn't read is listed on stderr with its line (in JSON, its path). A Structurizr, C4-PlantUML or Mermaid C4 source is
326
- drawn in the `c4` notation: its people as people (`person`, or `user` outside the system), its phone apps as phones. A
384
+ doesn't read is listed on stderr with its line (in JSON, its path). A Structurizr, C4-PlantUML or Mermaid C4 source's
385
+ people are people (`person`, or `user` outside the system), and its phone apps phones. A
327
386
  Structurizr workspace's `styles` give its elements their shapes (`shape Person`, `Cylinder`, `WebBrowser`, ...), in
328
387
  Structurizr's own order; a shape the map has no counterpart for is listed in `notImported`.
329
388
 
@@ -337,8 +396,8 @@ the title and "page N of M". It takes `--views` and `--theme`, as `stills` does,
337
396
  default; both across).
338
397
 
339
398
  The page has breadcrumbs, a details panel per card (with the slowest path from it and what-if), ⌘K search, deep links
340
- (`#view=<id>&node=<id>`, `#story=<id>&step=<n>` for a story's step, `#lens=<id>` and `#shapes=c4`), stories, lenses, a
341
- card shapes toggle next to ◐ (box, c4, uml; the page keeps the reader's choice), and export. For
399
+ (`#view=<id>&node=<id>`, `#story=<id>&step=<n>` for a story's step, `#lens=<id>`), stories, lenses, a
400
+ light and dark toggle (◐), and export. For
342
401
  scripts and tests, it keeps its map's handle on `window.umlimatorMap`: the `Handle` that `render()` returns (`setView()`,
343
402
  `highlight()`, `tour()`, `play()` ...).
344
403
  `stills` skips a view whose inputs have not changed since its last export (`--all` exports every view), and exits 1,
@@ -355,9 +414,9 @@ ffmpeg -f apng -i ride.png -vf "split[a][b];[a]palettegen[p];[b][p]paletteuse" r
355
414
  ffmpeg -f apng -i ride.png -vf "scale=trunc(iw/2)*2:trunc(ih/2)*2" -pix_fmt yuv420p ride.mp4
356
415
  ```
357
416
 
358
- On pull requests, the diff Action posts what they change in your maps: one comment with the summary and a sketch, and
359
- the pictures as the run's artifact. The comment names the commit it describes, only the run for the pull request's
360
- latest commit writes it, and it says so when the diff fails.
417
+ On pull requests, the diff Action posts what they change in your maps and UML diagrams (every type above): one comment
418
+ with the summary and a sketch, and the pictures as the run's artifact. The comment names the commit it describes, only
419
+ the run for the pull request's latest commit writes it, and it says so when the diff fails.
361
420
 
362
421
  ```yaml
363
422
  on: pull_request
@@ -368,7 +427,7 @@ jobs:
368
427
  runs-on: ubuntu-latest
369
428
  steps:
370
429
  - uses: actions/checkout@v4
371
- - uses: zintaen/umlimator@v0.20.0
430
+ - uses: zintaen/umlimator@v0.22.0
372
431
  with:
373
432
  models: "docs/*.json" # optional: where the models are (default: every .json that is a map model)
374
433
  ```
@@ -386,7 +445,7 @@ claude mcp add umlimator -- python3 /path/to/umlimator.py mcp /path/to/model.jso
386
445
  |---|---|
387
446
  | `list_views()` | the views (id, title, parent, number of cards) and the stories |
388
447
  | `describe_view(view)` | the view in sentences (`describe()`), then each card's id |
389
- | `paths(view, from, to)` | every card and line on a path from one card to another (`paths()`), as Refs for `highlight` |
448
+ | `paths(view, from, to)` | every card and line on a path from one card to another (`paths()`; on a sequence view, in time order), as Refs for `highlight` |
390
449
  | `reach(view, card, backward?, depth?)` | what a card leads to, or what leads to it, with the distance of each (`reach()`) |
391
450
  | `broken_rules()`, `validate()` | each break of the model's `rules` (`rules()`), and its own problems (`validate()`) |
392
451
  | `diff(other_model_path)` | what changed from another model file to this one, in words, and the views that show it (`diff()`) |
@@ -441,7 +500,7 @@ With `UMLIMATOR_OFFLINE=1` the CLI fetches nothing: a logo not in the cache keep
441
500
 
442
501
  ```bash
443
502
  npm run build # src/ into lib/umlimator.js and lib/umlimator-all.js: edit the sources, commit all three
444
- node --test # layout() in Node: the bench views' geometry and the layout rules
503
+ node --test # layout() in Node: the bench views' geometry and the layout rules; npm test runs the "(timed)" tests apart, one file at a time
445
504
  python3 tests/embed.py # render() in headless Chrome: events, keyboard, colours, contrast, editing, the element
446
505
  python3 bench/bench.py --check-determinism --expect bench/expected.json --max-ms m50=2000
447
506
  ```