lispgram 0.10.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/LAYOUT_LANGUAGE.md +390 -0
- package/LICENSE +21 -0
- package/LISPGRAM_GRAMMAR.md +568 -0
- package/README.md +326 -0
- package/dist/index.js +5648 -0
- package/dist/interaction.js +9 -0
- package/dist/layout.js +6 -0
- package/dist/surface.js +12 -0
- package/package.json +49 -0
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
# Lispgram layout language
|
|
2
|
+
|
|
3
|
+
This document describes the layout surface that Lispgram accepts today. It is intentionally small. The normal Lispgram graph language remains the primary authoring surface; `$layout` is an optional correction and template layer.
|
|
4
|
+
|
|
5
|
+
The design rule is:
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
write ordinary Lispgram first
|
|
9
|
+
add $layout only when the inferred layout needs a visual nudge
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## 1. Relationship to the Lispgram core
|
|
13
|
+
|
|
14
|
+
The core Lispgram syntax is still enough for many diagrams:
|
|
15
|
+
|
|
16
|
+
```lisp
|
|
17
|
+
(lispgram
|
|
18
|
+
(P{Parent} A B C)
|
|
19
|
+
(-> f A B)
|
|
20
|
+
(-> g B C)
|
|
21
|
+
(-> meta f g))
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
From this small syntax the renderer infers:
|
|
25
|
+
|
|
26
|
+
- visual containment from tree forms such as `(P A B C)`;
|
|
27
|
+
- ordinary routes from arrows such as `(-> f A B)`;
|
|
28
|
+
- self loops from ordinary self-arrows such as `(-> loop A A)`;
|
|
29
|
+
- arrows between arrows from ordinary arrows such as `(-> meta f g)`;
|
|
30
|
+
- curved lanes for repeated or anti-parallel endpoint pairs;
|
|
31
|
+
- containment-scoped fallback rows/ranks;
|
|
32
|
+
- locality for implicit targets that are introduced only by arrow references.
|
|
33
|
+
|
|
34
|
+
`$layout` and legacy `$metalayout` forms are preserved as layout metadata. They do not enter semantic core facts.
|
|
35
|
+
|
|
36
|
+
## 2. Basic shape
|
|
37
|
+
|
|
38
|
+
A layout block is written inside a Lispgram document:
|
|
39
|
+
|
|
40
|
+
```lisp
|
|
41
|
+
(lispgram
|
|
42
|
+
(P A B C)
|
|
43
|
+
(-> f A B)
|
|
44
|
+
|
|
45
|
+
($layout
|
|
46
|
+
(same-row [A B C])
|
|
47
|
+
(left-of A B)))
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Legacy `$metalayout` is still accepted for the older arrow-shaped syntax:
|
|
51
|
+
|
|
52
|
+
```lisp
|
|
53
|
+
($metalayout
|
|
54
|
+
(-> $samerow [A B C])
|
|
55
|
+
(-> $leftof A B))
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
New code should prefer `$layout`.
|
|
59
|
+
|
|
60
|
+
## 3. Strengths
|
|
61
|
+
|
|
62
|
+
Most relative constraints accept an optional strength as their final positional argument:
|
|
63
|
+
|
|
64
|
+
```lisp
|
|
65
|
+
(same-row [A B C] strong)
|
|
66
|
+
(left-of A B required)
|
|
67
|
+
(same-x [X P] medium)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Implemented strength names are:
|
|
71
|
+
|
|
72
|
+
```text
|
|
73
|
+
required > strong > medium > weak
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The solver also has a small numeric epsilon tolerance, so sub-pixel differences do not cause endless projection churn. Required constraints are still the strongest constraints; epsilon only controls when a nearly-satisfied numeric equation stops moving.
|
|
77
|
+
|
|
78
|
+
## 4. Relative positioning forms
|
|
79
|
+
|
|
80
|
+
### `same-row`
|
|
81
|
+
|
|
82
|
+
Aligns the vertical centers of nodes/containers.
|
|
83
|
+
|
|
84
|
+
```lisp
|
|
85
|
+
(same-row [A B C])
|
|
86
|
+
(same-row [A B C] strong)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Equivalent older spelling:
|
|
90
|
+
|
|
91
|
+
```lisp
|
|
92
|
+
(-> $samerow [A B C])
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### `same-column` / `same-col`
|
|
96
|
+
|
|
97
|
+
Aligns the horizontal centers of nodes/containers and performs initial vertical packing so the aligned objects do not collapse on top of each other.
|
|
98
|
+
|
|
99
|
+
```lisp
|
|
100
|
+
(same-column [A B C])
|
|
101
|
+
(same-col [A B C])
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Equivalent older spellings include `$samecol`, `$samecolumn`, `$same-col`, and `$same-column`.
|
|
105
|
+
|
|
106
|
+
### `same-x`
|
|
107
|
+
|
|
108
|
+
A softer x-alignment form. It aligns horizontal centers but defaults to `strong` instead of `required`.
|
|
109
|
+
|
|
110
|
+
```lisp
|
|
111
|
+
(same-x [X P])
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### `left-of`
|
|
115
|
+
|
|
116
|
+
Places the first object left of the second object.
|
|
117
|
+
|
|
118
|
+
```lisp
|
|
119
|
+
(left-of A B)
|
|
120
|
+
(left-of A B required)
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Equivalent older spellings include `leftof` and `$leftof`.
|
|
124
|
+
|
|
125
|
+
### `above`
|
|
126
|
+
|
|
127
|
+
Places one object above another object.
|
|
128
|
+
|
|
129
|
+
```lisp
|
|
130
|
+
(above X P)
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
The first argument may also be a vector in some template-lowered cases, but author-facing uses should usually keep it singular.
|
|
134
|
+
|
|
135
|
+
### `below`
|
|
136
|
+
|
|
137
|
+
Places one or more movers below an anchor.
|
|
138
|
+
|
|
139
|
+
```lisp
|
|
140
|
+
(below [A B C] P)
|
|
141
|
+
(below A P)
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### `center-over` / `center-x-over`
|
|
145
|
+
|
|
146
|
+
Horizontally centers an object over the average center of target objects.
|
|
147
|
+
|
|
148
|
+
```lisp
|
|
149
|
+
(center-over P [A B])
|
|
150
|
+
(center-x-over Product [A B C] strong)
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
This is useful for product/coproduct-like fan diagrams, but most authors should use a template view instead.
|
|
154
|
+
|
|
155
|
+
## 5. Route endpoint references
|
|
156
|
+
|
|
157
|
+
Most route directives accept endpoints. A bare id refers to a node/container by id.
|
|
158
|
+
|
|
159
|
+
```lisp
|
|
160
|
+
(route h :from A :to B)
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
The following endpoint constructors are also available:
|
|
164
|
+
|
|
165
|
+
```lisp
|
|
166
|
+
(node A) ;; force a node endpoint
|
|
167
|
+
(container C) ;; force a container endpoint
|
|
168
|
+
(boundary C left) ;; selected boundary side of a node/container/island
|
|
169
|
+
(boundary C right 0.25) ;; side plus optional normalized side position
|
|
170
|
+
(route f) ;; route midpoint of f
|
|
171
|
+
(arrow f) ;; alias of route endpoint
|
|
172
|
+
(mid f) ;; route midpoint
|
|
173
|
+
(start f) ;; route start anchor
|
|
174
|
+
(end f) ;; route end anchor
|
|
175
|
+
(label f) ;; label anchor
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
`(-> meta f g)` does not need `$layout`: arrow-to-arrow routes are inferred automatically and anchor to the final visible geometry of `f` and `g`.
|
|
179
|
+
|
|
180
|
+
## 6. Route directives
|
|
181
|
+
|
|
182
|
+
### `route`
|
|
183
|
+
|
|
184
|
+
Overrides the visual endpoints or role of an existing arrow.
|
|
185
|
+
|
|
186
|
+
```lisp
|
|
187
|
+
(route h :from A :to B)
|
|
188
|
+
(route h :from (mid f) :to (mid g) :role route-arrow)
|
|
189
|
+
(route h :from A :to B :shape straight :label h)
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
When `route` is used, the automatic rank pressure from the arrow's original semantic endpoints is suppressed for that arrow. This prevents the old semantic direction from fighting the explicit visual route.
|
|
193
|
+
|
|
194
|
+
### `parallel-pair`
|
|
195
|
+
|
|
196
|
+
Draws a set of arrows as global parallel lanes between the same visual endpoints.
|
|
197
|
+
|
|
198
|
+
```lisp
|
|
199
|
+
(parallel-pair [f g h] :from A :to B)
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Despite the historical name, this can handle more than two arrows. The engine also infers parallel and anti-parallel lanes from ordinary Lispgram arrows where possible, so use this only when the automatic lane grouping needs to be overridden.
|
|
203
|
+
|
|
204
|
+
### `attach-at-boundary`
|
|
205
|
+
|
|
206
|
+
Places an external source subtree outside a boundary side, then routes the arrow through that side-port.
|
|
207
|
+
|
|
208
|
+
```lisp
|
|
209
|
+
(attach-at-boundary h
|
|
210
|
+
:from ReviewThread
|
|
211
|
+
:to S
|
|
212
|
+
:boundary CoproductBox
|
|
213
|
+
:side left)
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Supported sides are `left`, `right`, `top`, and `bottom`.
|
|
217
|
+
|
|
218
|
+
This directive is both a placement hint and a route directive. It should be used for hierarchy-route-style diagrams where something external connects into a container/island boundary.
|
|
219
|
+
|
|
220
|
+
### `parallel-to-boundary`
|
|
221
|
+
|
|
222
|
+
Places a route alongside a selected boundary without making its endpoints members of that boundary owner.
|
|
223
|
+
|
|
224
|
+
```lisp
|
|
225
|
+
(parallel-to-boundary q
|
|
226
|
+
:from M
|
|
227
|
+
:to N
|
|
228
|
+
:boundary C
|
|
229
|
+
:side left)
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
## 7. Self loops
|
|
233
|
+
|
|
234
|
+
Self loops are not a `$layout` directive. They are ordinary arrows:
|
|
235
|
+
|
|
236
|
+
```lisp
|
|
237
|
+
(lispgram
|
|
238
|
+
(A)
|
|
239
|
+
(-> loop A A))
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
`$layout (self-loop ...)` and `$layout (loop ...)` intentionally error. This keeps loops in the small core language.
|
|
243
|
+
|
|
244
|
+
## 8. Template / view directives
|
|
245
|
+
|
|
246
|
+
Templates are written as layout views:
|
|
247
|
+
|
|
248
|
+
```lisp
|
|
249
|
+
($layout
|
|
250
|
+
(view product
|
|
251
|
+
:product P
|
|
252
|
+
:factors [A B]
|
|
253
|
+
:test-object X
|
|
254
|
+
:mediator u
|
|
255
|
+
:projections [pi1 pi2]
|
|
256
|
+
:cone-legs [f g]
|
|
257
|
+
:container C))
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
`view` and `template` are aliases. Templates emit ordinary relative constraints, route directives, and an island/layout view. They do not directly assign final coordinates.
|
|
261
|
+
|
|
262
|
+
Common keyword conventions:
|
|
263
|
+
|
|
264
|
+
- `:id` names the layout island. If omitted, the engine generates a template-specific id.
|
|
265
|
+
- `:container` links the view to a visual container shell when safe.
|
|
266
|
+
- `:mode full` asks the template to include optional outer/cone-leg routes where supported.
|
|
267
|
+
- Supplying `:cone-legs` for product/coproduct automatically selects full mode.
|
|
268
|
+
|
|
269
|
+
### Product
|
|
270
|
+
|
|
271
|
+
```lisp
|
|
272
|
+
(view product
|
|
273
|
+
:product P
|
|
274
|
+
:factors [A B]
|
|
275
|
+
:test-object X
|
|
276
|
+
:mediator u
|
|
277
|
+
:projections [pi1 pi2]
|
|
278
|
+
:cone-legs [f g]
|
|
279
|
+
:container C)
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
Visual convention:
|
|
283
|
+
|
|
284
|
+
```text
|
|
285
|
+
X above P
|
|
286
|
+
P centered over factors
|
|
287
|
+
factors in a row below P
|
|
288
|
+
projections fan downward
|
|
289
|
+
mediator is centered
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
Aliases: `product`, `product-cone`.
|
|
293
|
+
|
|
294
|
+
### Coproduct
|
|
295
|
+
|
|
296
|
+
```lisp
|
|
297
|
+
(view coproduct
|
|
298
|
+
:coproduct S
|
|
299
|
+
:summands [A B]
|
|
300
|
+
:test-object X
|
|
301
|
+
:mediator u
|
|
302
|
+
:injections [i1 i2]
|
|
303
|
+
:cone-legs [f g]
|
|
304
|
+
:container CΣ)
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
Aliases: `coproduct`, `sum`, `sum-type`.
|
|
308
|
+
|
|
309
|
+
### Equalizer
|
|
310
|
+
|
|
311
|
+
```lisp
|
|
312
|
+
(view equalizer
|
|
313
|
+
:equalizer E
|
|
314
|
+
:source A
|
|
315
|
+
:target B
|
|
316
|
+
:inclusion e
|
|
317
|
+
:parallel [f g])
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
### Pullback / pushout
|
|
321
|
+
|
|
322
|
+
```lisp
|
|
323
|
+
(view pullback
|
|
324
|
+
:corners [TL TR BL BR]
|
|
325
|
+
:arrows [top left bottom right])
|
|
326
|
+
|
|
327
|
+
(view pushout
|
|
328
|
+
:corners [TL TR BL BR]
|
|
329
|
+
:arrows [top left bottom right])
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
The corner order is top-left, top-right, bottom-left, bottom-right.
|
|
333
|
+
|
|
334
|
+
### Exponential
|
|
335
|
+
|
|
336
|
+
```lisp
|
|
337
|
+
(view exponential
|
|
338
|
+
:exponential BA
|
|
339
|
+
:source A
|
|
340
|
+
:target B
|
|
341
|
+
:product AxBA
|
|
342
|
+
:evaluation eval)
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
### Hasse / ranked rows
|
|
346
|
+
|
|
347
|
+
```lisp
|
|
348
|
+
(view hasse
|
|
349
|
+
:rows [[Bottom] [A B] [Top]])
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
The current surface lowering preserves rows and claims the island. Cover arrows can still be ordinary Lispgram arrows or explicit `route` directives.
|
|
353
|
+
|
|
354
|
+
## 9. NCF round trip
|
|
355
|
+
|
|
356
|
+
`toNCF()` emits layout metadata as a top-level `(layout ...)` block, and public `toNCFDoc()` can read raw NCF back into `doc.layoutForms`. Layout metadata remains outside semantic core. The lower-level `parseNCF()` helper exists inside the implementation but is not part of the minimal public npm export surface.
|
|
357
|
+
|
|
358
|
+
A simplified NCF shape looks like:
|
|
359
|
+
|
|
360
|
+
```lisp
|
|
361
|
+
(cy
|
|
362
|
+
(nodes ...)
|
|
363
|
+
(edges ...)
|
|
364
|
+
(layout
|
|
365
|
+
(same-row [A B C])
|
|
366
|
+
(view product :product P :factors [A B])))
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
## 10. Recommended authoring style
|
|
370
|
+
|
|
371
|
+
Prefer this:
|
|
372
|
+
|
|
373
|
+
```lisp
|
|
374
|
+
(lispgram
|
|
375
|
+
(P{Parent} A B C)
|
|
376
|
+
(-> f A B)
|
|
377
|
+
(-> g B C)
|
|
378
|
+
(-> meta f g))
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
Add this only when needed:
|
|
382
|
+
|
|
383
|
+
```lisp
|
|
384
|
+
($layout
|
|
385
|
+
(same-row [A B C])
|
|
386
|
+
(attach-at-boundary h :from External :to P :boundary C :side left)
|
|
387
|
+
(view product :product P :factors [A B]))
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
Avoid using `$layout` to restate obvious graph facts. The engine should infer containers, self-loops, arrow-to-arrow routes, parallel lanes, and many ordinary ranks from the small core syntax.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|