figdown 0.1.8 → 0.3.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/.claude-plugin/plugin.json +1 -1
- package/dist/figdown.js +971 -169
- package/dist/figdown.mjs +971 -169
- package/examples/evpn-fabric.svg +3 -4
- package/examples/showcase/arp-resolution.svg +1 -1
- package/examples/showcase/ethernet-frame.svg +1 -1
- package/examples/showcase/l2-forwarding-logic.svg +9 -9
- package/examples/showcase/tcp-handshake.svg +1 -1
- package/examples/showcase/tcp-header.svg +1 -1
- package/examples/showcase/tcp-state-machine.svg +77 -55
- package/guide/expressing.md +30 -18
- package/guide/layout.md +19 -19
- package/guide/showcase.md +62 -56
- package/package.json +2 -2
- package/skill/figdown/SKILL.md +30 -4
- package/skill/figdown/figdown.html +1030 -194
- package/skill/figdown/reference/experimental/block.md +60 -0
- package/skill/figdown/reference/experimental/chart.md +32 -0
- package/skill/figdown/reference/experimental/flowchart.md +148 -20
- package/skill/figdown/reference/experimental/statechart.md +138 -0
- package/skill/figdown/reference/experimental/timing.md +1 -1
- package/skill/figdown/reference/experimental/topology.md +148 -22
- package/skill/figdown/reference/reading.md +25 -1
- package/skill/figdown/reference/scene.md +78 -10
- package/skill/figdown/reference/experimental/constructs.md +0 -90
package/guide/showcase.md
CHANGED
|
@@ -141,7 +141,7 @@ endpoint's TCP state segment by segment.
|
|
|
141
141
|

|
|
142
142
|
|
|
143
143
|
```figdown
|
|
144
|
-
figdown 0.
|
|
144
|
+
figdown 0.2 flowchart
|
|
145
145
|
title "L2 Switch Forwarding Decision"
|
|
146
146
|
|
|
147
147
|
class forward "Forward — send the frame out the single learned egress port" fill=#16a34a
|
|
@@ -160,13 +160,13 @@ node flt "Filter (drop):\nsame-port destination" shape=rounded class=f
|
|
|
160
160
|
|
|
161
161
|
flow down
|
|
162
162
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
163
|
+
flowline wire -> learn
|
|
164
|
+
flowline learn -> lookup
|
|
165
|
+
flowline lookup -> hit
|
|
166
|
+
flowline hit -[no]-> fld
|
|
167
|
+
flowline hit -[yes]-> same
|
|
168
|
+
flowline same -[yes]-> flt
|
|
169
|
+
flowline same -[no]-> fwd
|
|
170
170
|
```
|
|
171
171
|
|
|
172
172
|
**Human sees:** a frame from the ingress port → source-MAC learning →
|
|
@@ -292,59 +292,59 @@ prose rather than on an edge of its own.
|
|
|
292
292
|
|
|
293
293
|
---
|
|
294
294
|
|
|
295
|
-
## 6. TCP connection state machine — every state, every transition (`
|
|
295
|
+
## 6. TCP connection state machine — every state, every transition (`statechart`)
|
|
296
296
|
|
|
297
297
|

|
|
298
298
|
|
|
299
299
|
```figdown
|
|
300
|
-
figdown 0.
|
|
300
|
+
figdown 0.2 statechart
|
|
301
301
|
title "TCP Connection State Machine (RFC 9293, Figure 5)"
|
|
302
302
|
|
|
303
|
-
class states "A
|
|
303
|
+
class states "A state IS a TCP connection state (RFC 9293 §3.3.2); the two CLOSED states are one state drawn twice — only this label says so" fill=#eef2ff
|
|
304
304
|
class setup "Connection-setup transition — opening the connection (OPEN, SYN exchange, first ACK)" stroke=#2563eb
|
|
305
305
|
class client "Active-close path (typically the client) — calls CLOSE first: FIN-WAIT-1 → FIN-WAIT-2 / CLOSING → TIME-WAIT → CLOSED" stroke=#dc2626
|
|
306
306
|
class server "Passive-close path (typically the server) — receives the peer's FIN first: CLOSE-WAIT → LAST-ACK → CLOSED" stroke=#16a34a
|
|
307
307
|
class rare "Rare / simultaneous transition — simultaneous open or close, or a reset/abort (RST, close from a half-open state)" stroke=#9333ea style=dashed
|
|
308
308
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
309
|
+
state closed "CLOSED" shape=rounded class=states
|
|
310
|
+
state listen "LISTEN" shape=rounded class=states
|
|
311
|
+
state synsent "SYN-SENT" shape=rounded class=states
|
|
312
|
+
state synrcvd "SYN-RECEIVED" shape=rounded class=states
|
|
313
|
+
state estab "ESTABLISHED" shape=rounded class=states
|
|
314
|
+
state fw1 "FIN-WAIT-1" shape=rounded class=states
|
|
315
|
+
state fw2 "FIN-WAIT-2" shape=rounded class=states
|
|
316
|
+
state closing "CLOSING" shape=rounded class=states
|
|
317
|
+
state closewait "CLOSE-WAIT" shape=rounded class=states
|
|
318
|
+
state lastack "LAST-ACK" shape=rounded class=states
|
|
319
|
+
state timewait "TIME-WAIT" shape=rounded class=states
|
|
320
|
+
state closed2 "CLOSED" shape=rounded class=states
|
|
321
321
|
|
|
322
322
|
flow down
|
|
323
323
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
324
|
+
transition closed -[passive OPEN / create TCB]-> listen class=setup
|
|
325
|
+
transition closed -[active OPEN / create TCB, snd SYN]-> synsent class=setup
|
|
326
|
+
transition listen -[SEND / snd SYN]-> synsent class=setup
|
|
327
|
+
transition listen -[rcv SYN / snd SYN,ACK]-> synrcvd class=setup
|
|
328
|
+
transition synsent -[rcv SYN / snd SYN,ACK]-> synrcvd class=rare
|
|
329
|
+
transition synsent -[rcv SYN,ACK / snd ACK]-> estab class=setup
|
|
330
|
+
transition synrcvd -[rcv ACK of SYN / x]-> estab class=setup
|
|
331
|
+
|
|
332
|
+
transition listen -[CLOSE / delete TCB]-> closed class=rare
|
|
333
|
+
transition synsent -[CLOSE / delete TCB]-> closed class=rare
|
|
334
|
+
transition synrcvd -[rcv RST (note 1) / x]-> listen class=rare
|
|
335
|
+
|
|
336
|
+
transition synrcvd -[CLOSE / snd FIN]-> fw1 class=client
|
|
337
|
+
transition estab -[CLOSE / snd FIN]-> fw1 class=client
|
|
338
|
+
transition fw1 -[rcv ACK of FIN / x]-> fw2 class=client
|
|
339
|
+
transition fw1 -[rcv FIN / snd ACK]-> closing class=client
|
|
340
|
+
transition fw1 -[rcv FIN,ACK / snd ACK]-> timewait class=rare
|
|
341
|
+
transition fw2 -[rcv FIN / snd ACK]-> timewait class=client
|
|
342
|
+
transition closing -[rcv ACK of FIN / x]-> timewait class=client
|
|
343
|
+
transition timewait -[Timeout=2MSL / delete TCB]-> closed2 class=client
|
|
344
|
+
|
|
345
|
+
transition estab -[rcv FIN / snd ACK]-> closewait class=server
|
|
346
|
+
transition closewait -[CLOSE / snd FIN]-> lastack class=server
|
|
347
|
+
transition lastack -[rcv ACK of FIN / x]-> closed2 class=server
|
|
348
348
|
|
|
349
349
|
layout
|
|
350
350
|
pin closed at=(394,20)
|
|
@@ -365,7 +365,8 @@ The `pin` block reproduces the canonical Figure 5 arrangement so a
|
|
|
365
365
|
reader who knows the RFC diagram recognises it — but it is **presentation
|
|
366
366
|
only** (`strip-check --strict` passes): strip every line after `layout` and all
|
|
367
367
|
11 states, all 21 transitions and their `event / action` labels survive on the
|
|
368
|
-
`
|
|
368
|
+
`state`/`transition`/`class` lines. All meaning is in the transitions; the pins
|
|
369
|
+
are layout.
|
|
369
370
|
|
|
370
371
|
Three `path … points=` lines used to sit under those pins, bowing the active <!-- fence-check: skip -->
|
|
371
372
|
OPEN and the two aborts out to the margins. `EDGE-GEOMETRY-CONSTRUCTS` **withdrew the construct from
|
|
@@ -389,14 +390,14 @@ arrow carrying its `event / action`.
|
|
|
389
390
|
**An agent answers from the text alone:**
|
|
390
391
|
|
|
391
392
|
- *Q: What event takes ESTABLISHED to CLOSE-WAIT, and what does the endpoint
|
|
392
|
-
send?* A: `rcv FIN / snd ACK` — one
|
|
393
|
-
(`
|
|
393
|
+
send?* A: `rcv FIN / snd ACK` — one transition label
|
|
394
|
+
(`transition estab -[rcv FIN / snd ACK]-> closewait`).
|
|
394
395
|
- *Q: From FIN-WAIT-1, how many ways lead to TIME-WAIT and under what
|
|
395
396
|
conditions?* A: three. (1) Directly: `rcv FIN,ACK / snd ACK` (the RFC Note-2
|
|
396
397
|
transition, `fw1 -> timewait`). (2) Via FIN-WAIT-2: `rcv ACK of FIN / x` then
|
|
397
398
|
`rcv FIN / snd ACK` (`fw1 -> fw2 -> timewait`). (3) Via CLOSING:
|
|
398
399
|
`rcv FIN / snd ACK` then `rcv ACK of FIN / x` (`fw1 -> closing -> timewait`).
|
|
399
|
-
All read off the
|
|
400
|
+
All read off the transitions.
|
|
400
401
|
- *Q: How long does TIME-WAIT last and what happens after?* A: `Timeout=2MSL`,
|
|
401
402
|
then `delete TCB` → CLOSED (`timewait -[Timeout=2MSL / delete TCB]-> closed2`).
|
|
402
403
|
- *Q: Which transitions belong to the typical server (passive-close) path?*
|
|
@@ -430,12 +431,17 @@ The Ethernet frame uses the **`BYTE-UNIT-PACKET-BLOCKS`** byte-unit workaround (
|
|
|
430
431
|
not `bitfield`) so byte order rides on cell order, and one of its facts — the
|
|
431
432
|
FCS **coverage span** over a contiguous run of columns (DA through Payload) —
|
|
432
433
|
has no annotation construct yet (**`CONTIGUOUS-RANGE-GROUPING`**), so it rides on a source comment
|
|
433
|
-
and prose. The TCP state machine meets
|
|
434
|
-
|
|
435
|
-
|
|
434
|
+
and prose. The TCP state machine meets one more, and **has just stopped meeting
|
|
435
|
+
the other**: state-ness IS first-class since `STATECHART-GENRE-SCOPE` — line 1 reads
|
|
436
|
+
`figdown 0.2 statechart`, so "this is a state" is now declared by the word
|
|
437
|
+
`state` itself (`GENRE-NODE-SPELLING`) rather than carried by the `states` class
|
|
438
|
+
label, and the label stays only because it says
|
|
439
|
+
something more specific about the two CLOSED nodes. The genre is EXPERIMENTAL
|
|
440
|
+
and may be withdrawn. What remains is that CLOSED is drawn **twice** because
|
|
441
|
+
FigDown has
|
|
436
442
|
no **node-identity/alias** construct (**`IDENTITY-ASSERTION`**) to declare two nodes the same
|
|
437
|
-
entity; the shared class label asserts it instead.
|
|
438
|
-
|
|
443
|
+
entity; the shared class label asserts it instead. So those two are the *only*
|
|
444
|
+
facts the figure
|
|
439
445
|
cannot carry that the canonical drawing implies. All are documented in
|
|
440
446
|
[expressing.md](expressing.md)'s "Known limits".
|
|
441
447
|
That a figure format states its own limits — and that a reading agent recovers
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "figdown",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Figures as text — one source, two readers: a closed, deterministic figure language for Markdown, readable by AI agents and humans alike",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "FigDown <hello@figdown.org>",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"gate:page": "node tools/page-check.js",
|
|
33
33
|
"gate:shape": "node tools/shape-check.js --strict",
|
|
34
34
|
"gate:strip": "node tools/strip-check.js --strict",
|
|
35
|
-
"gate:layout": "node tools/layout-lint.js",
|
|
35
|
+
"gate:layout": "node tools/layout-lint.js --strict",
|
|
36
36
|
"gate:artifact": "node tools/artifact-check.js --strict",
|
|
37
37
|
"gate:dist": "node tools/dist-check.js --strict",
|
|
38
38
|
"gate:isolation": "node tools/isolation-check.js --strict",
|
package/skill/figdown/SKILL.md
CHANGED
|
@@ -106,11 +106,12 @@ so you know which file you need before you need it.
|
|
|
106
106
|
|
|
107
107
|
| Genre on line 1 | Load | Add only for EXPERIMENTAL constructs |
|
|
108
108
|
|---|---|---|
|
|
109
|
-
| `block` — architecture, dataflow, hierarchy | `reference/scene.md`, `reference/layout.md` | `reference/experimental/
|
|
109
|
+
| `block` — architecture, dataflow, hierarchy | `reference/scene.md`, `reference/layout.md` | `reference/experimental/block.md`, `reference/experimental/chart.md` |
|
|
110
110
|
| `bitfield` — packet headers, register layouts | `reference/bitfield.md` | — |
|
|
111
|
-
| `table` — config, state, memory maps | `reference/table.md` | `reference/experimental/
|
|
112
|
-
| `topology` | `reference/
|
|
113
|
-
| `flowchart` | `reference/
|
|
111
|
+
| `table` — config, state, memory maps | `reference/table.md` | `reference/experimental/chart.md` |
|
|
112
|
+
| `topology` | `reference/experimental/topology.md`, `reference/layout.md` | `reference/experimental/chart.md` |
|
|
113
|
+
| `flowchart` | `reference/experimental/flowchart.md`, `reference/layout.md` | `reference/experimental/chart.md` |
|
|
114
|
+
| `statechart` | `reference/experimental/statechart.md`, `reference/layout.md` | `reference/experimental/chart.md` |
|
|
114
115
|
| `timing` | — | `reference/experimental/timing.md` |
|
|
115
116
|
|
|
116
117
|
Two more files answer a **task** rather than a genre:
|
|
@@ -126,6 +127,26 @@ Pick the genre by what the figure IS, not by its subject: the left-hand
|
|
|
126
127
|
column above says what each is for. Prefer the first three — they are the
|
|
127
128
|
portable ones.
|
|
128
129
|
|
|
130
|
+
**Load the genre file BEFORE you write line 2, not only when something
|
|
131
|
+
fails.** A scene genre may spell the thing and the line with **its own
|
|
132
|
+
domain's words**, and it may rank its keywords — preferring a precise one and
|
|
133
|
+
keeping a general one as the honest fallback. Neither is guessable from this
|
|
134
|
+
file, and neither is optional: the wrong spelling is a line error, and the
|
|
135
|
+
lazy spelling is a claim you did not mean to make. The genre file states both
|
|
136
|
+
in its first screen.
|
|
137
|
+
|
|
138
|
+
**Where a genre ranks its keywords, the general one means "the source does not
|
|
139
|
+
state this" — and nothing else.** It is the transcriber's honest line for a
|
|
140
|
+
source that leaves something unsaid, not a shrug and not a shortcut. It is
|
|
141
|
+
**not** the spelling for something FigDown cannot express: that is a **coverage
|
|
142
|
+
gap in the language**, and burying it in the general keyword makes the
|
|
143
|
+
language's hole look like your judgement, in a spelling no reader can tell
|
|
144
|
+
apart from a real decision. When your source states something no keyword
|
|
145
|
+
carries: write the general keyword, **name the missing thing in a `#` comment
|
|
146
|
+
on the same line**, and report the gap. The comment is text a reader can quote
|
|
147
|
+
and it survives every re-render; it is never parsed and never a second
|
|
148
|
+
semantic channel. Each genre file names its own ranking and its own fallback.
|
|
149
|
+
|
|
129
150
|
## The document skeleton
|
|
130
151
|
|
|
131
152
|
The grammar is **CLOSED**: an unknown line is an error, never ignored. Five
|
|
@@ -146,6 +167,11 @@ figdown 0.1 block # REQUIRED first significant line; comments and
|
|
|
146
167
|
# A later `figdown 0.1 <genre>` starts a new
|
|
147
168
|
# section with its own genre; one file still
|
|
148
169
|
# renders to one SVG.
|
|
170
|
+
# The VERSION is `0.1` or `0.2`. Write the LOWEST
|
|
171
|
+
# one that carries what the figure needs — `0.2`
|
|
172
|
+
# only for `statechart`, which does not exist at
|
|
173
|
+
# `0.1`. Sections may differ; each declares its
|
|
174
|
+
# own.
|
|
149
175
|
title "Some Title" # optional; the quotes are REQUIRED
|
|
150
176
|
# comments start with '#'; inside quotes the only escapes are \n \" \\
|
|
151
177
|
class hot "Congested path" stroke=#dc2626 # meaning + style, declared once
|