reladraw 0.21.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/.claude/skills/reladraw/SKILL.md +188 -0
- package/.claude/skills/reladraw/reference/syntax.md +1602 -0
- package/README.md +7 -5
- package/SYNTAX.md +11 -2
- package/dist/cli.js +36 -1
- package/dist/page.js +69 -145
- package/dist/viewer.d.ts +16 -0
- package/dist/viewer.js +185 -0
- package/package.json +2 -1
- package/dist/constrain.d.ts +0 -56
- package/dist/constrain.js +0 -95
package/dist/constrain.d.ts
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import type { Placement } from './ast.js';
|
|
2
|
-
/**
|
|
3
|
-
* The tightest arrangement satisfying a set of relative distances.
|
|
4
|
-
*
|
|
5
|
-
* Every placement in the language turns into the same shape of fact: one thing sits
|
|
6
|
-
* at least so far along an axis from another. Written as `pos[to] >= pos[from]
|
|
7
|
-
* + weight`, a whole diagram is a system of those, and the arrangement the
|
|
8
|
-
* author meant is the one where nothing is further apart than it has to be.
|
|
9
|
-
*
|
|
10
|
-
* That arrangement is unique and is found by longest paths, so no search
|
|
11
|
-
* happens and no alternative is ever weighed. Distances come out of the
|
|
12
|
-
* arithmetic; which side of what a thing sits on came from the author.
|
|
13
|
-
*/
|
|
14
|
-
export interface Constraint {
|
|
15
|
-
from: number;
|
|
16
|
-
to: number;
|
|
17
|
-
weight: number;
|
|
18
|
-
/** The placement this came from, so a failure can be reported in the author's words. */
|
|
19
|
-
placement?: Placement;
|
|
20
|
-
}
|
|
21
|
-
/** An exact distance, which is two inequalities pointing opposite ways. */
|
|
22
|
-
export declare function fix(from: number, to: number, distance: number, placement?: Placement): Constraint[];
|
|
23
|
-
export interface Contradiction {
|
|
24
|
-
/** The placements that cannot all hold. Empty if the loop is entirely implicit. */
|
|
25
|
-
placements: Placement[];
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Solve, or report the placements that fight.
|
|
29
|
-
*
|
|
30
|
-
* Longest path from a virtual source joined to everything at zero, which is
|
|
31
|
-
* Bellman-Ford with the comparison flipped. A distance that keeps growing after
|
|
32
|
-
* one pass per node means the constraints run in a circle that demands ever
|
|
33
|
-
* more room, and that circle is exactly the set of placements to quote back.
|
|
34
|
-
*/
|
|
35
|
-
export declare function tightest(count: number, constraints: Constraint[]): {
|
|
36
|
-
positions: number[];
|
|
37
|
-
} | {
|
|
38
|
-
contradiction: Contradiction;
|
|
39
|
-
};
|
|
40
|
-
/**
|
|
41
|
-
* Which members can be driven apart from which, along one axis.
|
|
42
|
-
*
|
|
43
|
-
* A constraint says `pos[to] >= pos[from] + weight`, so it bounds `to` from
|
|
44
|
-
* below and leaves it free to move further away. Follow those edges and the
|
|
45
|
-
* question "may this one end up beyond that one?" becomes plain reachability:
|
|
46
|
-
* if `j` is reachable from `i` and `i` is not reachable from `j`, then the file
|
|
47
|
-
* lets the distance from `i` to `j` grow without limit and never lets it be
|
|
48
|
-
* closed from the other side. Pushing `j` past `i` is then the one separation
|
|
49
|
-
* the file allows, and no choice was made.
|
|
50
|
-
*
|
|
51
|
-
* Reachable both ways means the two are pinned at a fixed distance, so they
|
|
52
|
-
* cannot be separated along this axis at all. Reachable neither way means the
|
|
53
|
-
* file said nothing that orders them, which is the case the caller must refuse
|
|
54
|
-
* rather than guess at.
|
|
55
|
-
*/
|
|
56
|
-
export declare function reachability(count: number, constraints: Constraint[]): boolean[][];
|
package/dist/constrain.js
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
/** An exact distance, which is two inequalities pointing opposite ways. */
|
|
2
|
-
export function fix(from, to, distance, placement) {
|
|
3
|
-
return [
|
|
4
|
-
{ from, to, weight: distance, ...(placement ? { placement } : {}) },
|
|
5
|
-
{ from: to, to: from, weight: -distance, ...(placement ? { placement } : {}) },
|
|
6
|
-
];
|
|
7
|
-
}
|
|
8
|
-
/**
|
|
9
|
-
* Solve, or report the placements that fight.
|
|
10
|
-
*
|
|
11
|
-
* Longest path from a virtual source joined to everything at zero, which is
|
|
12
|
-
* Bellman-Ford with the comparison flipped. A distance that keeps growing after
|
|
13
|
-
* one pass per node means the constraints run in a circle that demands ever
|
|
14
|
-
* more room, and that circle is exactly the set of placements to quote back.
|
|
15
|
-
*/
|
|
16
|
-
export function tightest(count, constraints) {
|
|
17
|
-
const positions = new Array(count).fill(0);
|
|
18
|
-
const cameFrom = new Array(count).fill(undefined);
|
|
19
|
-
for (let pass = 0; pass < count; pass += 1) {
|
|
20
|
-
let moved = false;
|
|
21
|
-
for (const constraint of constraints) {
|
|
22
|
-
const candidate = positions[constraint.from] + constraint.weight;
|
|
23
|
-
if (candidate > positions[constraint.to] + 1e-9) {
|
|
24
|
-
positions[constraint.to] = candidate;
|
|
25
|
-
cameFrom[constraint.to] = constraint;
|
|
26
|
-
moved = true;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
if (!moved)
|
|
30
|
-
return { positions };
|
|
31
|
-
}
|
|
32
|
-
// Still moving after a full pass per node, so some loop demands more room
|
|
33
|
-
// every time round it. Walk backwards to find it.
|
|
34
|
-
for (const constraint of constraints) {
|
|
35
|
-
if (positions[constraint.from] + constraint.weight > positions[constraint.to] + 1e-9) {
|
|
36
|
-
return { contradiction: { placements: loopFrom(constraint.to, cameFrom, count) } };
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
return { contradiction: { placements: [] } };
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Which members can be driven apart from which, along one axis.
|
|
43
|
-
*
|
|
44
|
-
* A constraint says `pos[to] >= pos[from] + weight`, so it bounds `to` from
|
|
45
|
-
* below and leaves it free to move further away. Follow those edges and the
|
|
46
|
-
* question "may this one end up beyond that one?" becomes plain reachability:
|
|
47
|
-
* if `j` is reachable from `i` and `i` is not reachable from `j`, then the file
|
|
48
|
-
* lets the distance from `i` to `j` grow without limit and never lets it be
|
|
49
|
-
* closed from the other side. Pushing `j` past `i` is then the one separation
|
|
50
|
-
* the file allows, and no choice was made.
|
|
51
|
-
*
|
|
52
|
-
* Reachable both ways means the two are pinned at a fixed distance, so they
|
|
53
|
-
* cannot be separated along this axis at all. Reachable neither way means the
|
|
54
|
-
* file said nothing that orders them, which is the case the caller must refuse
|
|
55
|
-
* rather than guess at.
|
|
56
|
-
*/
|
|
57
|
-
export function reachability(count, constraints) {
|
|
58
|
-
const reach = Array.from({ length: count }, () => new Array(count).fill(false));
|
|
59
|
-
for (const constraint of constraints)
|
|
60
|
-
reach[constraint.from][constraint.to] = true;
|
|
61
|
-
for (let via = 0; via < count; via += 1) {
|
|
62
|
-
for (let from = 0; from < count; from += 1) {
|
|
63
|
-
if (!reach[from][via])
|
|
64
|
-
continue;
|
|
65
|
-
for (let to = 0; to < count; to += 1) {
|
|
66
|
-
if (reach[via][to])
|
|
67
|
-
reach[from][to] = true;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
return reach;
|
|
72
|
-
}
|
|
73
|
-
/** The placements on the loop reached by following each position back to what set it. */
|
|
74
|
-
function loopFrom(start, cameFrom, count) {
|
|
75
|
-
let at = start;
|
|
76
|
-
for (let step = 0; step < count; step += 1) {
|
|
77
|
-
const previous = cameFrom[at];
|
|
78
|
-
if (previous === undefined)
|
|
79
|
-
break;
|
|
80
|
-
at = previous.from;
|
|
81
|
-
}
|
|
82
|
-
const placements = [];
|
|
83
|
-
const seen = new Set();
|
|
84
|
-
let cursor = at;
|
|
85
|
-
while (!seen.has(cursor)) {
|
|
86
|
-
seen.add(cursor);
|
|
87
|
-
const previous = cameFrom[cursor];
|
|
88
|
-
if (previous === undefined)
|
|
89
|
-
break;
|
|
90
|
-
if (previous.placement)
|
|
91
|
-
placements.push(previous.placement);
|
|
92
|
-
cursor = previous.from;
|
|
93
|
-
}
|
|
94
|
-
return placements.reverse();
|
|
95
|
-
}
|